Skip to content

Commit 10d3b3a

Browse files
authored
[dashboard] Simplify PR comment rendering (#1310)
1 parent 9280e91 commit 10d3b3a

5 files changed

Lines changed: 25 additions & 115 deletions

File tree

apps/code-infra-dashboard/app/api/ci-reports/sync-pr-comment/route.ts

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,23 +144,15 @@ export async function POST(request: NextRequest) {
144144
: null,
145145
]);
146146

147-
const commentSections: Record<string, string> = {};
147+
const trailer = `<hr>\n\nCheck out the [code infra dashboard](${DASHBOARD_ORIGIN}/repository/${prRepo}/prs/${pr.number}) for more information about this PR.`;
148148

149-
if (bundleSizeReport) {
150-
commentSections.bundleSize = bundleSizeReport.content;
151-
}
152-
153-
if (benchmarkReportResult) {
154-
commentSections.benchmark = benchmarkReportResult.content;
155-
}
156-
157-
if (deployPreviewReport) {
158-
commentSections.deployPreview = deployPreviewReport.content;
159-
}
149+
const commentBody = [deployPreviewReport, bundleSizeReport, benchmarkReportResult]
150+
.filter((report): report is ReportResult => report !== null)
151+
.map((report) => report.content)
152+
.concat(trailer)
153+
.join('\n\n');
160154

161-
await upsertPrComment(prRepo, pr.number, commentSections, {
162-
footer: `<hr>\n\nCheck out the [code infra dashboard](${DASHBOARD_ORIGIN}/repository/${prRepo}/prs/${pr.number}) for more information about this PR.`,
163-
});
155+
await upsertPrComment(prRepo, pr.number, commentBody);
164156

165157
return NextResponse.json({ success: true });
166158
}

apps/code-infra-dashboard/src/lib/benchmark/buildMarkdownReport.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,12 @@ export function buildBenchmarkMarkdownReport(
7272
lines.push(`| ${entry.name} | ${duration} | ${renders} |`);
7373
}
7474

75+
const detailsLink = reportUrl ? `[details](${reportUrl})` : '';
76+
lines.push('');
7577
if (remaining > 0) {
76-
const moreText = `...and ${remaining} more`;
77-
if (reportUrl) {
78-
lines.push('');
79-
lines.push(`*${moreText}. [View full report](${reportUrl})*`);
80-
} else {
81-
lines.push('');
82-
lines.push(`*${moreText}.*`);
83-
}
78+
lines.push(`*…and ${remaining} more${detailsLink ? ` — ${detailsLink}` : ''}*`);
79+
} else if (detailsLink) {
80+
lines.push(detailsLink);
8481
}
8582

8683
return lines.join('\n');

apps/code-infra-dashboard/src/lib/ciReports/benchmarkReport.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,5 @@ export async function generateBenchmarkReport(
6161
reportUrl: detailsUrl.toString(),
6262
});
6363

64-
markdownContent += `\n\n[Details of benchmark changes](${detailsUrl})`;
65-
6664
return { content: `## ${BENCHMARK_SECTION_TITLE}\n\n${markdownContent}` };
6765
}

apps/code-infra-dashboard/src/lib/ciReports/prComment.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ describe('upsertPrComment', () => {
4545
return {};
4646
});
4747

48-
const first = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 1' });
49-
const second = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 2' });
48+
const first = upsertPrComment('mui/material-ui', 42, 'report 1');
49+
const second = upsertPrComment('mui/material-ui', 42, 'report 2');
5050

5151
resolveFirst();
5252
await first;
@@ -73,8 +73,8 @@ describe('upsertPrComment', () => {
7373
return {};
7474
});
7575

76-
const first = upsertPrComment('mui/material-ui', 1, { bundleSize: 'report 1' });
77-
const second = upsertPrComment('mui/material-ui', 2, { bundleSize: 'report 2' });
76+
const first = upsertPrComment('mui/material-ui', 1, 'report 1');
77+
const second = upsertPrComment('mui/material-ui', 2, 'report 2');
7878

7979
resolveFirst();
8080
await first;
@@ -88,8 +88,8 @@ describe('upsertPrComment', () => {
8888
.mockRejectedValueOnce(new Error('GitHub API error'))
8989
.mockResolvedValueOnce({});
9090

91-
const first = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 1' });
92-
const second = upsertPrComment('mui/material-ui', 42, { bundleSize: 'report 2' });
91+
const first = upsertPrComment('mui/material-ui', 42, 'report 1');
92+
const second = upsertPrComment('mui/material-ui', 42, 'report 2');
9393

9494
await expect(first).rejects.toThrow('GitHub API error');
9595
await expect(second).resolves.toBeUndefined();
Lines changed: 7 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,6 @@
11
import { getOctokit } from '@/lib/github';
22

33
const COMMENT_MARKER = '<!-- ci-report-comment -->';
4-
const SECTION_REGEX = /<!-- section:(\w+) -->\n([\s\S]*?)<!-- \/section:\1 -->/g;
5-
const HEADER_REGEX = /<!-- header -->\n([\s\S]*?)<!-- \/header -->/;
6-
const FOOTER_REGEX = /<!-- footer -->\n([\s\S]*?)<!-- \/footer -->/;
7-
8-
function parseSections(body: string): Record<string, string> {
9-
const sections: Record<string, string> = {};
10-
for (const match of body.matchAll(SECTION_REGEX)) {
11-
sections[match[1]] = match[2].trim();
12-
}
13-
return sections;
14-
}
15-
16-
function parseHeader(body: string): string | null {
17-
const match = HEADER_REGEX.exec(body);
18-
return match ? match[1].trim() : null;
19-
}
20-
21-
function parseFooter(body: string): string | null {
22-
const match = FOOTER_REGEX.exec(body);
23-
return match ? match[1].trim() : null;
24-
}
25-
26-
function renderComment(
27-
header: string | null,
28-
sections: Record<string, string>,
29-
footer: string | null,
30-
): string {
31-
const parts: string[] = [COMMENT_MARKER];
32-
33-
if (header) {
34-
parts.push(`<!-- header -->\n${header}\n<!-- /header -->`);
35-
}
36-
37-
const sectionEntries = Object.entries(sections);
38-
if (sectionEntries.length > 0) {
39-
parts.push(
40-
sectionEntries
41-
.map(([id, content]) => `<!-- section:${id} -->\n${content}\n<!-- /section:${id} -->`)
42-
.join('\n\n'),
43-
);
44-
}
45-
46-
if (footer) {
47-
parts.push(`<!-- footer -->\n${footer}\n<!-- /footer -->`);
48-
}
49-
50-
return parts.join('\n\n');
51-
}
524

535
/**
546
* Recursively searches for a comment containing the comment marker.
@@ -76,32 +28,19 @@ async function findComment(owner: string, repoName: string, prNumber: number, pa
7628
return findComment(owner, repoName, prNumber, page + 1);
7729
}
7830

79-
export interface UpsertPrCommentOptions {
80-
header?: string;
81-
footer?: string;
82-
defaultSections?: Record<string, string>;
83-
}
84-
8531
const pendingUpdates = new Map<string, Promise<void>>();
8632

8733
/**
88-
* Creates or updates a comment on a pull request with section-based content.
89-
* Each section is independently updatable — only the provided sections are
90-
* modified, others are preserved.
34+
* Creates or updates the CI report comment on a pull request.
9135
*
9236
* Concurrent calls for the same PR are serialized to prevent race conditions.
9337
*/
94-
export function upsertPrComment(
95-
repo: string,
96-
prNumber: number,
97-
sections: Record<string, string>,
98-
options?: UpsertPrCommentOptions,
99-
): Promise<void> {
38+
export function upsertPrComment(repo: string, prNumber: number, body: string): Promise<void> {
10039
const key = `${repo}/${prNumber}`;
10140
const prev = pendingUpdates.get(key) ?? Promise.resolve();
10241
const next = prev
10342
.catch(() => {})
104-
.then(() => doUpsert(repo, prNumber, sections, options))
43+
.then(() => doUpsert(repo, prNumber, body))
10544
.finally(() => {
10645
if (pendingUpdates.get(key) === next) {
10746
pendingUpdates.delete(key);
@@ -111,12 +50,7 @@ export function upsertPrComment(
11150
return next;
11251
}
11352

114-
async function doUpsert(
115-
repo: string,
116-
prNumber: number,
117-
sections: Record<string, string>,
118-
options?: UpsertPrCommentOptions,
119-
): Promise<void> {
53+
async function doUpsert(repo: string, prNumber: number, body: string): Promise<void> {
12054
const [owner, repoName] = repo.split('/');
12155

12256
if (!owner || !repoName) {
@@ -125,32 +59,21 @@ async function doUpsert(
12559

12660
const octokit = getOctokit();
12761
const existingComment = await findComment(owner, repoName, prNumber);
62+
const commentBody = `${COMMENT_MARKER}\n\n${body}`;
12863

12964
if (existingComment) {
130-
const existingBody = existingComment.body ?? '';
131-
const existingSections = parseSections(existingBody);
132-
const mergedSections = {
133-
...options?.defaultSections,
134-
...existingSections,
135-
...sections,
136-
};
137-
const mergedHeader = options?.header ?? parseHeader(existingBody);
138-
const mergedFooter = options?.footer ?? parseFooter(existingBody);
139-
14065
await octokit.issues.updateComment({
14166
owner,
14267
repo: repoName,
14368
comment_id: existingComment.id,
144-
body: renderComment(mergedHeader, mergedSections, mergedFooter),
69+
body: commentBody,
14570
});
14671
} else {
147-
const mergedSections = { ...options?.defaultSections, ...sections };
148-
14972
await octokit.issues.createComment({
15073
owner,
15174
repo: repoName,
15275
issue_number: prNumber,
153-
body: renderComment(options?.header ?? null, mergedSections, options?.footer ?? null),
76+
body: commentBody,
15477
});
15578
}
15679
}

0 commit comments

Comments
 (0)