From fd31b7c2a58bf914be009d58e12c0616b1511b6e Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Fri, 11 Sep 2026 23:00:43 -0400 Subject: [PATCH] fix: drop a run whose timings cannot be aggregated instead of failing the branch The try/catch around a sampled run only covered fetching its artifacts; aggregating them ran outside it, so a spec-timings.json that parsed as JSON but carried no per-file data would still fail the whole branch's refresh. Aggregate inside the same block, and reject such a file where it is read so the message names the artifact. --- src/utils/roll-spec-weights.ts | 15 ++++++++------- src/utils/spec-weights.ts | 6 +++++- .../spec-weights/test_artifacts_truncated_1.zip | Bin 0 -> 179 bytes tests/utils/spec-weights.spec.ts | 5 +++++ 4 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 tests/fixtures/spec-weights/test_artifacts_truncated_1.zip diff --git a/src/utils/roll-spec-weights.ts b/src/utils/roll-spec-weights.ts index a679d11..05bd205 100644 --- a/src/utils/roll-spec-weights.ts +++ b/src/utils/roll-spec-weights.ts @@ -109,18 +109,19 @@ export async function computeRefresh( const runs: Weights[] = []; const usedRunIds: number[] = []; for (const runId of runIds) { - let jobs: JobTimings[]; + let run: Weights; try { - jobs = await fetchRunTimings(octokit, runId); + const jobs = await fetchRunTimings(octokit, runId); + if (!jobs.length) { + d(`run ${runId} has no timing artifacts (expired?) - ignoring`); + continue; + } + run = aggregateRun(jobs); } catch (e) { d(`run ${runId}: could not read its timing artifacts (${e.message}) - ignoring`); continue; } - if (!jobs.length) { - d(`run ${runId} has no timing artifacts (expired?) - ignoring`); - continue; - } - runs.push(aggregateRun(jobs)); + runs.push(run); usedRunIds.push(runId); } if (!runs.length) { diff --git a/src/utils/spec-weights.ts b/src/utils/spec-weights.ts index f4758a9..ee0528f 100644 --- a/src/utils/spec-weights.ts +++ b/src/utils/spec-weights.ts @@ -258,7 +258,11 @@ export function timingsFromArtifactZip(zip: Buffer): SpecTimings[] { const data = zip.subarray(dataStart, dataStart + compressedSize); const raw = method === 0 ? data : method === 8 ? inflateRawSync(data) : null; if (!raw) throw new Error(`unsupported zip compression method ${method} for ${name}`); - found.push(JSON.parse(raw.toString('utf8'))); + const timings = JSON.parse(raw.toString('utf8')); + if (!timings || typeof timings.files !== 'object' || timings.files === null) { + throw new Error(`${name} carries no per-file timings`); + } + found.push(timings); } return found; } diff --git a/tests/fixtures/spec-weights/test_artifacts_truncated_1.zip b/tests/fixtures/spec-weights/test_artifacts_truncated_1.zip new file mode 100644 index 0000000000000000000000000000000000000000..e1b1051fbaa955a515957e329e0c2f96222dc037 GIT binary patch literal 179 zcmWIWW@Zs#U|`^2;NGDf`_S*(YJDKj7>EUdxVRuSS+^uJH#0B2STCzMKW}xI)(KA? z&(r#+LN^5kczNn*oj((NDKNlG$LkzJXUL414Lf#r9(9O|O7bhr(q#znW@Hj!#%(^( b3NUD31W_2a1$eWvfg~7#&>l#~fjA5RAbBm@ literal 0 HcmV?d00001 diff --git a/tests/utils/spec-weights.spec.ts b/tests/utils/spec-weights.spec.ts index 06d3026..e9586db 100644 --- a/tests/utils/spec-weights.spec.ts +++ b/tests/utils/spec-weights.spec.ts @@ -28,6 +28,11 @@ describe('spec-weights', () => { expect(timings[0].files['spec/api-browser-window-spec.ts']).toBeCloseTo(364.971, 3); }); + it('rejects a timings file with no per-file data', () => { + const zip = readFileSync(join(fixtures, 'test_artifacts_truncated_1.zip')); + expect(() => timingsFromArtifactZip(zip)).toThrow(/no per-file timings/); + }); + it('rejects something that is not a zip', () => { expect(() => timingsFromArtifactZip(Buffer.from('nope'))).toThrow(/not a zip/); });