mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
ci(web): skip bundle comments for minor size changes (#42856)
This commit is contained in:
1 parent
70e973b9ab
commit
2f9fa672d0
4 files changed
+94
-14
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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')
|
||||
})
|
||||
@@ -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('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('|', '|').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)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user