diff --git a/.github/workflows/size-compare.yml b/.github/workflows/size-compare.yml index 59ebf66608..b0b6a7881c 100644 --- a/.github/workflows/size-compare.yml +++ b/.github/workflows/size-compare.yml @@ -139,7 +139,8 @@ jobs: --head desktop-client=./head/web-stats.json \ --head loot-core=./head/loot-core-stats.json \ --head api=./head/api-stats.json \ - --identifier combined > bundle-stats-comment.md + --identifier combined \ + --format pr-body > bundle-stats-comment.md - name: Post combined bundle stats comment env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -148,4 +149,5 @@ jobs: run: | node packages/ci-actions/bin/update-bundle-stats-comment.mjs \ --comment-file bundle-stats-comment.md \ - --identifier '' + --identifier combined \ + --target pr-body diff --git a/packages/ci-actions/bin/bundle-stats-comment.mjs b/packages/ci-actions/bin/bundle-stats-comment.mjs index 391ea33ed7..124ed3a812 100644 --- a/packages/ci-actions/bin/bundle-stats-comment.mjs +++ b/packages/ci-actions/bin/bundle-stats-comment.mjs @@ -174,6 +174,7 @@ function parseArgs(argv) { return { sections, identifier: getSingleValue(args, 'identifier') ?? 'bundle-stats', + format: getSingleValue(args, 'format') ?? 'pr-body', }; } @@ -463,6 +464,12 @@ const TOTAL_HEADERS = makeHeader([ 'Total bundle size', '% Changed', ]); +const SUMMARY_HEADERS = makeHeader([ + 'Bundle', + 'Files count', + 'Total bundle size', + '% Changed', +]); const TABLE_HEADERS = makeHeader(['Asset', 'File Size', '% Changed']); const CHUNK_TABLE_HEADERS = makeHeader(['File', 'Δ', 'Size']); @@ -596,6 +603,24 @@ function printTotalAssetTable(statsDiff) { return `**Total**\n${TOTAL_HEADERS}\n${printAssetTableRow(statsDiff.total)}`; } +function printSummaryTable(sections) { + if (sections.length === 0) { + return `${SUMMARY_HEADERS}\nNo bundle stats were generated.`; + } + + const rows = sections.map(section => { + const total = section.statsDiff.total; + return [ + section.name, + total.name, + toFileSizeDiffCell(total), + conditionalPercentage(total.diffPercentage), + ].join(' | '); + }); + + return `${SUMMARY_HEADERS}\n${rows.join('\n')}`; +} + function renderSection(title, statsDiff, chunkModuleDiff) { const { total, ...groups } = statsDiff; const parts = [`#### ${title}`, '', printTotalAssetTable({ total })]; @@ -615,8 +640,30 @@ function renderSection(title, statsDiff, chunkModuleDiff) { return parts.join('\n'); } +function renderSections(sections) { + return sections + .map(section => + renderSection(section.name, section.statsDiff, section.chunkDiff), + ) + .join('\n\n---\n\n'); +} + +function getIdentifierMarkers(key) { + const label = 'bundlestats-action-comment'; + return { + start: ``, + end: ``, + }; +} + async function main() { const args = parseArgs(process.argv); + const allowedFormats = new Set(['comment', 'pr-body']); + if (!allowedFormats.has(args.format)) { + throw new Error( + `Invalid format "${args.format}". Use "comment" or "pr-body".`, + ); + } console.error( `[bundle-stats] Found ${args.sections.length} sections to process`, @@ -654,22 +701,29 @@ async function main() { }); } - const identifier = ``; + const markers = getIdentifierMarkers(args.identifier); + const sectionsContent = renderSections(sections); + const summaryTable = printSummaryTable(sections); - const comment = [ + const detailedBody = ['### Bundle Stats', '', sectionsContent].join('\n'); + + const commentBody = [markers.start, detailedBody, '', markers.end, ''].join( + '\n', + ); + + const prBody = [ + markers.start, '### Bundle Stats', '', - sections - .map(section => - renderSection(section.name, section.statsDiff, section.chunkDiff), - ) - .join('\n\n---\n\n'), + summaryTable, '', - identifier, + `
\nView detailed bundle stats\n\n${sectionsContent}\n
`, + '', + markers.end, '', ].join('\n'); - process.stdout.write(comment); + process.stdout.write(args.format === 'comment' ? commentBody : prBody); } main().catch(error => { diff --git a/packages/ci-actions/bin/update-bundle-stats-comment.mjs b/packages/ci-actions/bin/update-bundle-stats-comment.mjs index c835be6251..ea69903b33 100644 --- a/packages/ci-actions/bin/update-bundle-stats-comment.mjs +++ b/packages/ci-actions/bin/update-bundle-stats-comment.mjs @@ -18,6 +18,7 @@ function parseArgs(argv) { const args = { commentFile: null, identifier: null, + target: 'comment', }; for (let i = 2; i < argv.length; i += 2) { @@ -41,6 +42,9 @@ function parseArgs(argv) { case '--identifier': args.identifier = value; break; + case '--target': + args.target = value; + break; default: throw new Error(`Unknown argument "${key}".`); } @@ -54,6 +58,12 @@ function parseArgs(argv) { throw new Error('Missing required argument "--identifier".'); } + if (!['comment', 'pr-body'].includes(args.target)) { + throw new Error( + `Invalid value "${args.target}" for "--target". Use "comment" or "pr-body".`, + ); + } + return args; } @@ -110,20 +120,120 @@ function isGitHubActionsBot(comment) { return comment.user?.login === 'github-actions[bot]'; } +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +function getIdentifierMarkers(identifier) { + if (identifier.includes('`, + end: ``, + }; +} + +function upsertBlock(existingBody, block, markers) { + const body = existingBody ?? ''; + + if (markers.end) { + const pattern = new RegExp( + `${escapeRegExp(markers.start)}[\\s\\S]*?${escapeRegExp(markers.end)}`, + 'm', + ); + + if (pattern.test(body)) { + return body.replace(pattern, block.trim()); + } + } + + if (body.trim().length === 0) { + return block.trim(); + } + + const separator = body.endsWith('\n') ? '\n' : '\n\n'; + return `${body}${separator}${block.trim()}`; +} + +async function updatePullRequestBody( + octokit, + owner, + repo, + pullNumber, + block, + markers, +) { + const { data } = await octokit.rest.pulls.get({ + owner, + repo, + pull_number: pullNumber, + }); + const nextBody = upsertBlock(data.body ?? '', block, markers); + + await octokit.rest.pulls.update({ + owner, + repo, + pull_number: pullNumber, + body: nextBody, + }); +} + +async function deleteExistingComment( + octokit, + owner, + repo, + issueNumber, + markers, +) { + const comments = await listComments(octokit, owner, repo, issueNumber); + const existingComment = comments.find( + comment => + isGitHubActionsBot(comment) && comment.body?.includes(markers.start), + ); + + if (existingComment) { + await octokit.rest.issues.deleteComment({ + owner, + repo, + comment_id: existingComment.id, + }); + } +} + async function main() { - const { commentFile, identifier } = parseArgs(process.argv); + const { commentFile, identifier, target } = parseArgs(process.argv); const commentBody = await loadCommentBody(commentFile); const token = assertGitHubToken(); const { owner, repo } = getRepoInfo(); const issueNumber = getPullRequestNumber(); + const markers = getIdentifierMarkers(identifier); const octokit = new Octokit({ auth: token }); - const comments = await listComments(octokit, owner, repo, issueNumber); + if (target === 'pr-body') { + await updatePullRequestBody( + octokit, + owner, + repo, + issueNumber, + commentBody, + markers, + ); + await deleteExistingComment(octokit, owner, repo, issueNumber, markers); + console.log('Updated pull request body with bundle stats.'); + return; + } + const comments = await listComments(octokit, owner, repo, issueNumber); const existingComment = comments.find( comment => - isGitHubActionsBot(comment) && comment.body?.includes(identifier), + isGitHubActionsBot(comment) && comment.body?.includes(markers.start), ); if (existingComment) { @@ -134,15 +244,16 @@ async function main() { body: commentBody, }); console.log('Updated existing bundle stats comment.'); - } else { - await octokit.rest.issues.createComment({ - owner, - repo, - issue_number: issueNumber, - body: commentBody, - }); - console.log('Created new bundle stats comment.'); + return; } + + await octokit.rest.issues.createComment({ + owner, + repo, + issue_number: issueNumber, + body: commentBody, + }); + console.log('Created new bundle stats comment.'); } main().catch(error => { diff --git a/upcoming-release-notes/6677.md b/upcoming-release-notes/6677.md new file mode 100644 index 0000000000..e6a2df6e58 --- /dev/null +++ b/upcoming-release-notes/6677.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [matt-fidd] +--- + +Post bundle size comparison comment in the PR body instead