diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index e5165f9c7..ac552d8ac 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -201,6 +201,7 @@ jobs: ]; let details = ''; + let detailsNoTrends = ''; for (const suite of suites) { const suiteDir = path.join(root, suite.dir); let readme = '', trends = ''; @@ -208,23 +209,43 @@ jobs: try { trends = fs.readFileSync(path.join(suiteDir, 'trends.md'), 'utf8'); } catch {} if (!readme && !trends) continue; - details += `
\n${suite.label}\n\n`; + const open = `
\n${suite.label}\n\n`; + details += open; if (readme) details += readme + '\n\n'; if (trends) { details += `**Trends:**\n\n${trends}\n\n`; } details += `
\n\n`; + + if (readme) detailsNoTrends += open + readme + `\n\n
\n\n`; } const marker = ''; - const body = `${marker} + const header = `${marker} ## CI Test Results [${commitSha}](${server}/${repo}/commit/${commitSha}) (${date}) - ${summaryContent} - - ${details}`; + `; + + const runUrl = `${server}/${repo}/actions/runs/${context.payload.workflow_run.id}`; + const note = (what) => `\n_${what} omitted, the comment hit GitHub's size limit. Full report in the [workflow run](${runUrl})._\n`; + + // Bodies to try, largest first. GitHub decides which one fits: it + // rejects an oversized body with 422, but the 65536 characters its + // message names is not the enforced ceiling (140k bodies post), so + // there is no constant here worth comparing against. Trend tables + // are the bulk of an oversized body, so they are shed first. + function* candidates() { + yield header + summaryContent + '\n\n' + details; + yield header + summaryContent + '\n\n' + detailsNoTrends + note('Trend tables'); + let summary = summaryContent; + yield header + summary + note('Per-suite details'); + while (summary) { + summary = summary.slice(0, Math.floor(summary.length / 2)); + yield header + summary + note('Per-suite details and most of the summary'); + } + } // Update existing comment if present, otherwise create new one const comments = await github.rest.issues.listComments({ @@ -235,20 +256,37 @@ jobs: }); const existing = comments.data.find(c => c.body.includes(marker)); - if (existing) { - await github.rest.issues.updateComment({ - comment_id: existing.id, - owner: context.repo.owner, - repo: context.repo.repo, - body: body, - }); - core.info(`Updated comment ${existing.id}`); - } else { - await github.rest.issues.createComment({ - issue_number: prNumber, - owner: context.repo.owner, - repo: context.repo.repo, - body: body, - }); - core.info('Created new comment'); + const post = (body) => existing + ? github.rest.issues.updateComment({ + comment_id: existing.id, + owner: context.repo.owner, + repo: context.repo.repo, + body: body, + }) + : github.rest.issues.createComment({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body: body, + }); + + let shed = 0; + let posted = false; + for (const body of candidates()) { + try { + await post(body); + posted = true; + } catch (error) { + if (!(error.status === 422 && /too long/i.test(error.message))) throw error; + shed++; + continue; + } + if (shed) { + core.warning(`Comment shortened ${shed} time(s) to fit GitHub's size limit.`); + } + core.info(existing ? `Updated comment ${existing.id}` : 'Created new comment'); + break; + } + if (!posted) { + throw new Error('Comment rejected as too long at every size.'); }