Skip to content

Commit

Permalink
[Release] Stage to Main (#2479)
Browse files Browse the repository at this point in the history
  • Loading branch information
milo-pr-merge[bot] authored Jun 18, 2024
2 parents ead382f + 16c64e4 commit ddbdf7a
Show file tree
Hide file tree
Showing 66 changed files with 7,637 additions and 11,593 deletions.
1 change: 1 addition & 0 deletions .github/workflows/label-zero-impact.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const zeroImpactDirs = [
'LICENSE',
'codecov.yaml',
'.gitignore',
'package-lock.json',
];
const zeroImpactLabel = 'zero-impact';

Expand Down
43 changes: 39 additions & 4 deletions .github/workflows/merge-to-stage.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,28 @@ const hasFailingChecks = (checks) =>
name !== 'merge-to-stage' && conclusion === 'failure'
);

const commentOnPR = async (comment, prNumber) => {
console.log(comment); // Logs for debugging the action.
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber,
});

const dayAgo = new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
const hasRecentComment = comments
.filter(({ created_at }) => new Date(created_at) > dayAgo)
.some(({ body }) => body === comment);
if (hasRecentComment) return console.log('Comment exists for', prNumber);

await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: comment,
});
};

const getPRs = async () => {
let prs = await github.rest.pulls
.list({ owner, repo, state: 'open', per_page: 100, base: STAGE })
Expand All @@ -69,13 +91,19 @@ const getPRs = async () => {

prs = prs.filter(({ checks, reviews, number, title }) => {
if (hasFailingChecks(checks)) {
console.log(`Skipping ${number}: ${title} due to failing checks`);
commentOnPR(
`Skipped merging ${number}: ${title} due to failing checks`,
number
);
return false;
}

const approvals = reviews.filter(({ state }) => state === 'APPROVED');
if (approvals.length < REQUIRED_APPROVALS) {
console.log(`Skipping ${number}: ${title} due to insufficient approvals`);
commentOnPR(
`Skipped merging ${number}: ${title} due to insufficient approvals. Required: ${REQUIRED_APPROVALS} approvals`,
number
);
return false;
}

Expand Down Expand Up @@ -103,7 +131,10 @@ const merge = async ({ prs, type }) => {
for await (const { number, files, html_url, title } of prs) {
try {
if (files.some((file) => SEEN[file])) {
console.log(`Skipping ${number}: ${title} due to overlap in files.`);
commentOnPR(
`Skipped ${number}: ${title} due to file overlap. Merging will be attempted in the next batch`,
number
);
continue;
}
if (type !== LABELS.zeroImpact) {
Expand All @@ -130,7 +161,7 @@ const merge = async ({ prs, type }) => {
);
await new Promise((resolve) => setTimeout(resolve, 5000));
} catch (error) {
console.log(`Error merging ${number}: ${title}`, error.message);
commentOnPR(`Error merging ${number}: ${title} ` + error.message, number);
}
}
};
Expand Down Expand Up @@ -187,6 +218,10 @@ const openStageToMainPR = async () => {
});

await slackNotification(SLACK.openedSyncPr({ html_url, number }));
await slackNotification(
SLACK.openedSyncPr({ html_url, number }),
process.env.MILO_STAGE_SLACK_WH
);
} catch (error) {
if (error.message.includes('No commits between main and stage'))
return console.log('No new commits, no stage->main PR opened');
Expand Down
2 changes: 1 addition & 1 deletion libs/blocks/marketo-config/marketo-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const Fields = ({ fieldsData }) => {
} catch {
const keyValuePairs = field.options.split(',').map((item) => {
const [key, val] = item.trim().split(':');
return key.trim() ? [key.trim(), `${(val || key).trim()} (${key.trim()})`] : ['', 'Choose an option...'];
return key.trim() ? [key.trim(), `${(val || key).trim()}`] : ['', 'Choose an option...'];
});
options = Object.fromEntries(keyValuePairs);
}
Expand Down
5 changes: 5 additions & 0 deletions libs/blocks/merch-card/merch-card.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ div[class*="-merch-card"] > div,
color: var(--text-color);
}

.twp.merch-card .merch-card-price {
font-weight: 700;
margin: 0;
}

merch-card.special-offers del span[is="inline-price"] {
text-decoration: line-through;
}
Expand Down
187 changes: 119 additions & 68 deletions libs/blocks/merch-card/merch-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,24 @@ import '../../deps/merch-card.js';

const TAG_PATTERN = /^[a-zA-Z0-9_-]+:[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-].*$/;

const CARD_TYPES = ['segment', 'special-offers', 'plans', 'catalog', 'product', 'inline-heading', 'image', 'mini-compare-chart'];
const SEGMENT = 'segment';
const SPECIAL_OFFERS = 'special-offers';
const PLANS = 'plans';
const CATALOG = 'catalog';
const PRODUCT = 'product';
const MINI_COMPARE_CHART = 'mini-compare-chart';
const TWP = 'twp';
const CARD_TYPES = [
SEGMENT,
SPECIAL_OFFERS,
PLANS,
CATALOG,
PRODUCT,
'inline-heading',
'image',
MINI_COMPARE_CHART,
TWP,
];

const CARD_SIZES = ['wide', 'super-wide'];

Expand All @@ -25,13 +42,9 @@ const HEADING_MAP = {
},
};

const MINI_COMPARE_CHART = 'mini-compare-chart';
const PLANS = 'plans';
const SEGMENT = 'segment';

const INNER_ELEMENTS_SELECTOR = 'h2, h3, h4, h5, p, ul, em';

const MULTI_OFFER_CARDS = ['plans', 'product', MINI_COMPARE_CHART];
const MULTI_OFFER_CARDS = [PLANS, PRODUCT, MINI_COMPARE_CHART, TWP];
// Force cards to refresh once they become visible so that the footer rows are properly aligned.
const intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
Expand All @@ -46,10 +59,10 @@ const getPodType = (styles) => styles?.find((style) => CARD_TYPES.includes(style
const isHeadingTag = (tagName) => /^H[2-5]$/.test(tagName);
const isParagraphTag = (tagName) => tagName === 'P';

const appendSlot = (slotEls, slotName, merchCard) => {
const appendSlot = (slotEls, slotName, merchCard, nodeName = 'p') => {
if (slotEls.length === 0 || merchCard.variant !== MINI_COMPARE_CHART) return;
const newEl = createTag(
'p',
nodeName,
{ slot: slotName, class: slotName },
);
slotEls.forEach((e) => {
Expand All @@ -72,6 +85,68 @@ export async function loadMnemonicList(foreground) {
}
}

function extractQuantitySelect(el) {
const quantitySelectConfig = [...el.querySelectorAll('ul')]
.find((ul) => ul.querySelector('li')?.innerText?.includes('Quantity'));
const configMarkup = quantitySelectConfig?.querySelector('ul');
if (!configMarkup) return null;
const config = configMarkup.children;
if (config.length !== 2) return null;
const attributes = {};
attributes.title = config[0].textContent.trim();
const values = config[1].textContent.split(',')
.map((value) => value.trim())
.filter((value) => /^\d*$/.test(value))
.map((value) => (value === '' ? undefined : Number(value)));
quantitySelectConfig.remove();
if (![3, 4, 5].includes(values.length)) return null;
import('../../deps/merch-quantity-select.js');
[attributes.min, attributes.max, attributes.step, attributes['default-value'], attributes['max-input']] = values;
const quantitySelect = createTag('merch-quantity-select', attributes);
return quantitySelect;
}

const parseTwpContent = async (el, merchCard) => {
const quantitySelect = extractQuantitySelect(el);
if (quantitySelect) {
merchCard.append(quantitySelect);
}
let allElements = el?.children[0]?.children[0]?.children;
if (!allElements?.length) return;
allElements = [...allElements];
const contentGroups = allElements.reduce((acc, curr) => {
if (curr.tagName.toLowerCase() === 'p' && curr.textContent.trim() === '--') {
acc.push([]);
} else {
acc[acc.length - 1].push(curr);
}
return acc;
}, [[]]);

contentGroups.forEach((group, index) => {
if (index === 0) { // Top section
const headings = group.filter((e) => e.tagName.toLowerCase() === 'h3');
const topBody = group.filter((e) => e.tagName.toLowerCase() === 'p');
appendSlot(headings, 'heading-xs', merchCard);
appendSlot(topBody, 'body-xs-top', merchCard);
} else if (index === 1) { // Body section
const content = group.filter((e) => e.tagName.toLowerCase() === 'p' || e.tagName.toLowerCase() === 'ul');
const bodySlot = createTag('div', { slot: 'body-xs' }, content);
merchCard.append(bodySlot);
} else if (index === 2) { // Footer section
const footerContent = group.filter((e) => ['h5', 'p'].includes(e.tagName.toLowerCase()));
const footer = createTag('div', { slot: 'footer' }, footerContent);
merchCard.append(footer);
}
});

const offerSelection = el.querySelector('ul');
if (offerSelection) {
const { initOfferSelection } = await import('./merch-offer-select.js');
await initOfferSelection(merchCard, offerSelection);
}
};

const parseContent = async (el, merchCard) => {
let bodySlotName = `body-${merchCard.variant !== MINI_COMPARE_CHART ? 'xs' : 'm'}`;
let headingMCount = 0;
Expand Down Expand Up @@ -201,7 +276,7 @@ const decorateMerchCardLinkAnalytics = (el) => {
};

const addStock = (merchCard, styles) => {
if (styles.includes('add-stock')) {
if (styles.includes('add-stock') && merchCard.variant !== TWP) {
let stock;
const selector = styles.includes('edu') ? '.merch-offers.stock.edu > *' : '.merch-offers.stock > *';
const [label, ...rest] = [...document.querySelectorAll(selector)];
Expand All @@ -225,27 +300,6 @@ const simplifyHrs = (el) => {
});
};

async function extractQuantitySelect(el) {
const quantitySelectConfig = el.querySelector('ul');
if (!quantitySelectConfig) return null;
const configMarkup = quantitySelectConfig.querySelector('li');
if (!configMarkup || !configMarkup.textContent.includes('Quantity')) return null;
const config = configMarkup.querySelector('ul').querySelectorAll('li');
if (config.length !== 2) return null;
const attributes = {};
attributes.title = config[0].textContent.trim();
const values = config[1].textContent.split(',')
.map((value) => value.trim())
.filter((value) => /^\d*$/.test(value))
.map((value) => (value === '' ? undefined : Number(value)));
if (![3, 4, 5].includes(values.length)) return null;
await import('../../deps/merch-quantity-select.js');
[attributes.min, attributes.max, attributes.step, attributes['default-value'], attributes['max-input']] = values;
const quantitySelect = createTag('merch-quantity-select', attributes);
quantitySelectConfig.remove();
return quantitySelect;
}

const getMiniCompareChartFooterRows = (el) => {
let footerRows = Array.from(el.children).slice(1);
footerRows = footerRows.filter((row) => !row.querySelector('.footer-row-cell'));
Expand Down Expand Up @@ -289,7 +343,7 @@ const setMiniCompareOfferSlot = (merchCard, offers) => {
export default async function init(el) {
if (!el.querySelector(INNER_ELEMENTS_SELECTOR)) return el;
const styles = [...el.classList];
const cardType = getPodType(styles) || 'product';
const cardType = getPodType(styles) || PRODUCT;
if (!styles.includes(cardType)) {
styles.push(cardType);
}
Expand Down Expand Up @@ -344,7 +398,6 @@ export default async function init(el) {
);
merchCard.setAttribute('badge-color', badge.badgeColor);
merchCard.setAttribute('badge-text', badge.badgeText);
if (document.querySelector('html').dir === 'rtl') merchCard.setAttribute('is-rtl', 'true');
merchCard.classList.add('badge-card');
}
}
Expand Down Expand Up @@ -372,7 +425,7 @@ export default async function init(el) {
}
}
});
const actionMenuContent = cardType === 'catalog'
const actionMenuContent = cardType === CATALOG
? getActionMenuContent(el)
: null;
if (actionMenuContent) {
Expand All @@ -397,7 +450,6 @@ export default async function init(el) {
imageSlot.appendChild(image);
merchCard.appendChild(imageSlot);
}
parseContent(el, merchCard);
if (!icons || icons.length > 0) {
const iconImgs = Array.from(icons).map((icon) => {
const img = {
Expand All @@ -421,46 +473,45 @@ export default async function init(el) {
merchCard.setAttribute('filters', categories.join(','));
merchCard.setAttribute('types', types.join(','));

const footer = createTag('div', { slot: 'footer' });
if (ctas) {
if (merchCard.variant === 'mini-compare-chart') {
decorateButtons(ctas, 'button-l');
} else {
decorateButtons(ctas);
}
const links = ctas.querySelectorAll('a');
ctas.remove();
footer.append(...links);
}
merchCard.appendChild(footer);
if (merchCard.variant !== TWP) {
parseContent(el, merchCard);

if (MULTI_OFFER_CARDS.includes(cardType)) {
if (merchCard.variant === MINI_COMPARE_CHART) {
const miniCompareOffers = createTag('div', { slot: 'offers' });
merchCard.append(miniCompareOffers);
}
const quantitySelect = await extractQuantitySelect(el, cardType);
const offerSelection = el.querySelector('ul');
if (offerSelection) {
const { initOfferSelection } = await import('./merch-offer-select.js');
setMiniCompareOfferSlot(merchCard, undefined);
initOfferSelection(merchCard, offerSelection, quantitySelect);
const footer = createTag('div', { slot: 'footer' });
if (ctas) {
decorateButtons(ctas, (merchCard.variant === MINI_COMPARE_CHART) ? 'button-l' : undefined);
footer.append(ctas);
}
if (quantitySelect) {
merchCard.appendChild(footer);

if (MULTI_OFFER_CARDS.includes(cardType)) {
const quantitySelect = extractQuantitySelect(el);
const offerSelection = el.querySelector('ul');
if (merchCard.variant === MINI_COMPARE_CHART) {
setMiniCompareOfferSlot(merchCard, quantitySelect);
} else {
const bodySlot = merchCard.querySelector('div[slot="body-xs"]');
bodySlot.append(quantitySelect);
const miniCompareOffers = createTag('div', { slot: 'offers' });
merchCard.append(miniCompareOffers);
}
if (offerSelection) {
const { initOfferSelection } = await import('./merch-offer-select.js');
setMiniCompareOfferSlot(merchCard, undefined);
initOfferSelection(merchCard, offerSelection, quantitySelect);
}
if (quantitySelect) {
if (merchCard.variant === MINI_COMPARE_CHART) {
setMiniCompareOfferSlot(merchCard, quantitySelect);
} else {
const bodySlot = merchCard.querySelector('div[slot="body-xs"]');
bodySlot.append(quantitySelect);
}
}
}

decorateBlockHrs(merchCard);
simplifyHrs(merchCard);
if (merchCard.classList.contains('has-divider')) merchCard.setAttribute('custom-hr', true);
decorateFooterRows(merchCard, footerRows);
} else {
parseTwpContent(el, merchCard);
}
decorateBlockHrs(merchCard);
simplifyHrs(merchCard);
if (merchCard.classList.contains('has-divider')) {
merchCard.setAttribute('custom-hr', true);
}
decorateFooterRows(merchCard, footerRows);
el.replaceWith(merchCard);
decorateMerchCardLinkAnalytics(merchCard);
return merchCard;
Expand Down
Loading

0 comments on commit ddbdf7a

Please sign in to comment.