diff --git a/apps/code-infra-dashboard/app/api/ci-reports/sync-pr-comment/route.ts b/apps/code-infra-dashboard/app/api/ci-reports/sync-pr-comment/route.ts index 94b68069a..70d1a9ed3 100644 --- a/apps/code-infra-dashboard/app/api/ci-reports/sync-pr-comment/route.ts +++ b/apps/code-infra-dashboard/app/api/ci-reports/sync-pr-comment/route.ts @@ -144,23 +144,15 @@ export async function POST(request: NextRequest) { : null, ]); - const commentSections: Record = {}; + const trailer = `
\n\nCheck out the [code infra dashboard](${DASHBOARD_ORIGIN}/repository/${prRepo}/prs/${pr.number}) for more information about this PR.`; - if (bundleSizeReport) { - commentSections.bundleSize = bundleSizeReport.content; - } - - if (benchmarkReportResult) { - commentSections.benchmark = benchmarkReportResult.content; - } - - if (deployPreviewReport) { - commentSections.deployPreview = deployPreviewReport.content; - } + const commentBody = [deployPreviewReport, bundleSizeReport, benchmarkReportResult] + .filter((report): report is ReportResult => report !== null) + .map((report) => report.content) + .concat(trailer) + .join('\n\n'); - await upsertPrComment(prRepo, pr.number, commentSections, { - footer: `
\n\nCheck out the [code infra dashboard](${DASHBOARD_ORIGIN}/repository/${prRepo}/prs/${pr.number}) for more information about this PR.`, - }); + await upsertPrComment(prRepo, pr.number, commentBody); return NextResponse.json({ success: true }); } diff --git a/apps/code-infra-dashboard/src/lib/benchmark/buildMarkdownReport.ts b/apps/code-infra-dashboard/src/lib/benchmark/buildMarkdownReport.ts index 90aba5a62..b4840c677 100644 --- a/apps/code-infra-dashboard/src/lib/benchmark/buildMarkdownReport.ts +++ b/apps/code-infra-dashboard/src/lib/benchmark/buildMarkdownReport.ts @@ -72,15 +72,12 @@ export function buildBenchmarkMarkdownReport( lines.push(`| ${entry.name} | ${duration} | ${renders} |`); } + const detailsLink = reportUrl ? `[details](${reportUrl})` : ''; + lines.push(''); if (remaining > 0) { - const moreText = `...and ${remaining} more`; - if (reportUrl) { - lines.push(''); - lines.push(`*${moreText}. [View full report](${reportUrl})*`); - } else { - lines.push(''); - lines.push(`*${moreText}.*`); - } + lines.push(`*…and ${remaining} more${detailsLink ? ` — ${detailsLink}` : ''}*`); + } else if (detailsLink) { + lines.push(detailsLink); } return lines.join('\n'); diff --git a/apps/code-infra-dashboard/src/lib/ciReports/benchmarkReport.ts b/apps/code-infra-dashboard/src/lib/ciReports/benchmarkReport.ts index 6b1a9b866..80d3fefb0 100644 --- a/apps/code-infra-dashboard/src/lib/ciReports/benchmarkReport.ts +++ b/apps/code-infra-dashboard/src/lib/ciReports/benchmarkReport.ts @@ -49,7 +49,5 @@ export async function generateBenchmarkReport( reportUrl: detailsUrl.toString(), }); - markdownContent += `\n\n[Details of benchmark changes](${detailsUrl})`; - return { content: `## ${BENCHMARK_SECTION_TITLE}\n\n${markdownContent}` }; } diff --git a/apps/code-infra-dashboard/src/lib/ciReports/prComment.test.ts b/apps/code-infra-dashboard/src/lib/ciReports/prComment.test.ts index 7f24bb56f..1eb93b7cb 100644 --- a/apps/code-infra-dashboard/src/lib/ciReports/prComment.test.ts +++ b/apps/code-infra-dashboard/src/lib/ciReports/prComment.test.ts @@ -45,8 +45,8 @@ describe('upsertPrComment', () => { return {}; }); - const first = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 1' }); - const second = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 2' }); + const first = upsertPrComment('mui/material-ui', 42, 'report 1'); + const second = upsertPrComment('mui/material-ui', 42, 'report 2'); resolveFirst(); await first; @@ -73,8 +73,8 @@ describe('upsertPrComment', () => { return {}; }); - const first = upsertPrComment('mui/material-ui', 1, { bundleSize: 'report 1' }); - const second = upsertPrComment('mui/material-ui', 2, { bundleSize: 'report 2' }); + const first = upsertPrComment('mui/material-ui', 1, 'report 1'); + const second = upsertPrComment('mui/material-ui', 2, 'report 2'); resolveFirst(); await first; @@ -88,8 +88,8 @@ describe('upsertPrComment', () => { .mockRejectedValueOnce(new Error('GitHub API error')) .mockResolvedValueOnce({}); - const first = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 1' }); - const second = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 2' }); + const first = upsertPrComment('mui/material-ui', 42, 'report 1'); + const second = upsertPrComment('mui/material-ui', 42, 'report 2'); await expect(first).rejects.toThrow('GitHub API error'); await expect(second).resolves.toBeUndefined(); diff --git a/apps/code-infra-dashboard/src/lib/ciReports/prComment.ts b/apps/code-infra-dashboard/src/lib/ciReports/prComment.ts index c84abb8a4..cdd1b2d81 100644 --- a/apps/code-infra-dashboard/src/lib/ciReports/prComment.ts +++ b/apps/code-infra-dashboard/src/lib/ciReports/prComment.ts @@ -1,54 +1,6 @@ import { getOctokit } from '@/lib/github'; const COMMENT_MARKER = ''; -const SECTION_REGEX = /\n([\s\S]*?)/g; -const HEADER_REGEX = /\n([\s\S]*?)/; -const FOOTER_REGEX = /\n([\s\S]*?)/; - -function parseSections(body: string): Record { - const sections: Record = {}; - for (const match of body.matchAll(SECTION_REGEX)) { - sections[match[1]] = match[2].trim(); - } - return sections; -} - -function parseHeader(body: string): string | null { - const match = HEADER_REGEX.exec(body); - return match ? match[1].trim() : null; -} - -function parseFooter(body: string): string | null { - const match = FOOTER_REGEX.exec(body); - return match ? match[1].trim() : null; -} - -function renderComment( - header: string | null, - sections: Record, - footer: string | null, -): string { - const parts: string[] = [COMMENT_MARKER]; - - if (header) { - parts.push(`\n${header}\n`); - } - - const sectionEntries = Object.entries(sections); - if (sectionEntries.length > 0) { - parts.push( - sectionEntries - .map(([id, content]) => `\n${content}\n`) - .join('\n\n'), - ); - } - - if (footer) { - parts.push(`\n${footer}\n`); - } - - return parts.join('\n\n'); -} /** * Recursively searches for a comment containing the comment marker. @@ -76,32 +28,19 @@ async function findComment(owner: string, repoName: string, prNumber: number, pa return findComment(owner, repoName, prNumber, page + 1); } -export interface UpsertPrCommentOptions { - header?: string; - footer?: string; - defaultSections?: Record; -} - const pendingUpdates = new Map>(); /** - * Creates or updates a comment on a pull request with section-based content. - * Each section is independently updatable — only the provided sections are - * modified, others are preserved. + * Creates or updates the CI report comment on a pull request. * * Concurrent calls for the same PR are serialized to prevent race conditions. */ -export function upsertPrComment( - repo: string, - prNumber: number, - sections: Record, - options?: UpsertPrCommentOptions, -): Promise { +export function upsertPrComment(repo: string, prNumber: number, body: string): Promise { const key = `${repo}/${prNumber}`; const prev = pendingUpdates.get(key) ?? Promise.resolve(); const next = prev .catch(() => {}) - .then(() => doUpsert(repo, prNumber, sections, options)) + .then(() => doUpsert(repo, prNumber, body)) .finally(() => { if (pendingUpdates.get(key) === next) { pendingUpdates.delete(key); @@ -111,12 +50,7 @@ export function upsertPrComment( return next; } -async function doUpsert( - repo: string, - prNumber: number, - sections: Record, - options?: UpsertPrCommentOptions, -): Promise { +async function doUpsert(repo: string, prNumber: number, body: string): Promise { const [owner, repoName] = repo.split('/'); if (!owner || !repoName) { @@ -125,32 +59,21 @@ async function doUpsert( const octokit = getOctokit(); const existingComment = await findComment(owner, repoName, prNumber); + const commentBody = `${COMMENT_MARKER}\n\n${body}`; if (existingComment) { - const existingBody = existingComment.body ?? ''; - const existingSections = parseSections(existingBody); - const mergedSections = { - ...options?.defaultSections, - ...existingSections, - ...sections, - }; - const mergedHeader = options?.header ?? parseHeader(existingBody); - const mergedFooter = options?.footer ?? parseFooter(existingBody); - await octokit.issues.updateComment({ owner, repo: repoName, comment_id: existingComment.id, - body: renderComment(mergedHeader, mergedSections, mergedFooter), + body: commentBody, }); } else { - const mergedSections = { ...options?.defaultSections, ...sections }; - await octokit.issues.createComment({ owner, repo: repoName, issue_number: prNumber, - body: renderComment(options?.header ?? null, mergedSections, options?.footer ?? null), + body: commentBody, }); } }