ci(web): skip bundle comments for minor size changes (#42856)

This commit is contained in:
Stephen Zhou authored and GitHub committed 2026-09-24 01:28:45 +00:00
1 parent 70e973b9ab
commit 2f9fa672d0
4 files changed
+94 -14

No files matched your search

+10
View File
@@ -112,6 +112,7 @@ jobs:
path: bundle-results
- name: Compare and summarize
id: compare
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
@@ -127,6 +128,8 @@ jobs:
- name: Update PR report
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
SHOULD_COMMENT: ${{ steps.compare.outputs.should-comment }}
with:
script: |
const fs = require('node:fs');
@@ -145,6 +148,13 @@ jobs:
const existing = comments.find(comment =>
comment.user?.login === 'github-actions[bot]' &&
comment.body?.startsWith('<!-- dify-vinext-bundle-size -->'));
if (process.env.SHOULD_COMMENT !== 'true') {
if (existing) {
await github.rest.issues.deleteComment({ owner, repo, comment_id: existing.id });
}
core.info('Bundle changes are below the PR comment thresholds. See the job summary.');
return;
}
if (existing) {
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
} else {
+9 -2
View File
@@ -20,8 +20,15 @@ job instead of appearing as savings.
## Reading the report
The comparison appears directly in the Actions summary and in an updated comment
for same-repository PRs. Merge queue runs receive the summary and artifacts without
The full comparison always appears in the Actions summary. Same-repository PRs
receive an updated comment only when the absolute gzip change reaches at least
5 KiB for all client JS, 1 KiB for client CSS, or 2 KiB for any entry present in
both revisions. Increases and decreases both qualify. Raw sizes, package
attribution, and added/removed entry boundaries do not independently trigger a
comment. If a later run falls below every threshold, the existing report comment
is removed to avoid leaving stale results.
Merge queue runs receive the summary and artifacts without
a PR comment. Fork PRs receive the summary and artifacts without a
privileged build or comment token. Reports are informational: growth does not fail
the check; build, analysis, and reporting errors do.
+53 -1
View File
@@ -2,7 +2,14 @@ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { gzipSync } from 'node:zlib'
import { collect, compare, parseAnalysis, parseSnapshot, staticClosure } from '../bundle-analysis'
import {
collect,
compare,
parseAnalysis,
parseSnapshot,
shouldComment,
staticClosure,
} from '../bundle-analysis'
const dirs: string[] = []
const sha = 'a'.repeat(40)
@@ -112,3 +119,48 @@ it('reports additions, removals, gzip differences and package attribution withou
expect(report).toContain('not page first-load metrics')
expect(() => parseSnapshot(JSON.stringify({ ...base, totals: {} }))).toThrow('Invalid')
})
const snapshot = () => ({
version: 1 as const,
commit: sha,
vinext: '1.0.0',
rolldown: '1.2.9',
totals: { js: { raw: 100000, gzip: 20000 }, css: { raw: 50000, gzip: 10000 } },
entries: { shared: { raw: 50000, gzip: 10000 } },
packages: { example: 10000 },
})
it.each([
['js', 5 * 1024],
['css', 1024],
['entry', 2 * 1024],
] as const)('comments at the %s gzip threshold in either direction', (metric, threshold) => {
for (const direction of [-1, 1]) {
const base = snapshot()
const merged = snapshot()
const target = metric === 'entry' ? merged.entries.shared : merged.totals[metric]
target.gzip += direction * (threshold - 1)
expect(shouldComment(base, merged)).toBe(false)
target.gzip += direction
expect(shouldComment(base, merged)).toBe(true)
target.gzip += direction
expect(shouldComment(base, merged)).toBe(true)
}
})
it('keeps tiny gzip changes and attribution-only or entry-boundary changes in the full report', () => {
const base = snapshot()
expect(shouldComment(base, base)).toBe(false)
const merged = {
...snapshot(),
totals: { js: { raw: 200000, gzip: 20500 }, css: { raw: 100000, gzip: 10000 } },
entries: { added: { raw: 100000, gzip: 20000 } },
packages: { example: 100000 },
}
expect(shouldComment(base, merged)).toBe(false)
const report = compare(base, merged)
expect(report).toContain('+0.49 KiB')
expect(report).toContain('New entry')
expect(report).toContain('Removed entry')
expect(report).toContain('example')
})
+22 -11
View File
@@ -1,4 +1,4 @@
import { mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises'
import { appendFile, mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises'
import { dirname, isAbsolute, join, relative, resolve } from 'node:path'
import { gzipSync } from 'node:zlib'
@@ -169,6 +169,15 @@ export function parseSnapshot(text: string): Snapshot {
return v as Snapshot
}
const kib = (n: number) => `${(n / 1024).toFixed(2)} KiB`
export function shouldComment(a: Snapshot, b: Snapshot): boolean {
return (
Math.abs(b.totals.js.gzip - a.totals.js.gzip) >= 5 * 1024 ||
Math.abs(b.totals.css.gzip - a.totals.css.gzip) >= 1024 ||
Object.keys(a.entries).some(
(key) => b.entries[key] && Math.abs(b.entries[key].gzip - a.entries[key]!.gzip) >= 2 * 1024,
)
)
}
const delta = (a: number, b: number) => `${b > a ? '+' : b < a ? '−' : ''}${kib(Math.abs(b - a))}`
const label = (s: string) =>
`<code>${s.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('|', '&#124;').replaceAll('\n', ' ')}</code>`
@@ -286,16 +295,18 @@ async function main() {
throw new Error(
'Usage: instrument <web> | collect <web> <sha> <json> | compare <base.json> <merge.json> <report.md>',
)
const result =
command === 'collect'
? `${JSON.stringify(await collect(first, second), null, 2)}\n`
: command === 'compare'
? compare(
parseSnapshot(await readFile(first, 'utf8')),
parseSnapshot(await readFile(second, 'utf8')),
)
: null
if (result === null) throw new Error('Unknown command.')
let result: string
if (command === 'collect') {
result = `${JSON.stringify(await collect(first, second), null, 2)}\n`
} else if (command === 'compare') {
const base = parseSnapshot(await readFile(first, 'utf8'))
const merged = parseSnapshot(await readFile(second, 'utf8'))
result = compare(base, merged)
if (process.env.GITHUB_OUTPUT)
await appendFile(process.env.GITHUB_OUTPUT, `should-comment=${shouldComment(base, merged)}\n`)
} else {
throw new Error('Unknown command.')
}
await mkdir(dirname(resolve(output)), { recursive: true })
await writeFile(output, result)
}