Skip to content

Commit 0d98c7e

Browse files
authored
fix(ci): namespace rollup checks by API (#3824)
1 parent 606b85e commit 0d98c7e

2 files changed

Lines changed: 19 additions & 4 deletions

File tree

scripts/lib/check-rollup.mjs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
* newest run for a context; counting every historical row instead makes a
1010
* green replacement look failed (#3792).
1111
*
12-
* Deduplication requires both a stable context name and parseable timestamps.
12+
* Deduplication requires a reporting API type, a stable context name, and
13+
* parseable timestamps. A Checks API run and a legacy Status API context with
14+
* the same label are independent signals and must never supersede each other
15+
* (#3817).
1316
* Unknown rows stay visible and ties stay together, preserving the sweep's
1417
* fail-closed direction instead of guessing which ambiguous row superseded
1518
* which.
@@ -18,14 +21,16 @@ export function currentRollupChecks(rollup) {
1821
const unnamed = [];
1922
const groups = new Map();
2023
for (const check of rollup ?? []) {
21-
const name = check?.__typename === 'StatusContext' ? check?.context : check?.name;
24+
const type = check?.__typename === 'StatusContext' ? 'StatusContext' : 'CheckRun';
25+
const name = type === 'StatusContext' ? check?.context : check?.name;
2226
if (typeof name !== 'string' || name === '') {
2327
unnamed.push(check);
2428
continue;
2529
}
26-
const group = groups.get(name) ?? [];
30+
const key = `${type}\x00${name}`;
31+
const group = groups.get(key) ?? [];
2732
group.push(check);
28-
groups.set(name, group);
33+
groups.set(key, group);
2934
}
3035

3136
const current = [...unnamed];

scripts/lib/pr-green-sweep.test.mjs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,16 @@ test('#3792: status contexts dedupe by context while distinct lane names remain
214214
assert.deepEqual(countRollup(rows), { fail: 0, pending: 0, pass: 2 });
215215
});
216216

217+
test('#3817: a same-labelled CheckRun and StatusContext never supersede each other', () => {
218+
const rows = [
219+
{ __typename: 'CheckRun', name: 'Deploy', status: 'COMPLETED', conclusion: 'FAILURE', startedAt: '2026-09-03T09:00:00Z' },
220+
{ __typename: 'StatusContext', context: 'Deploy', state: 'SUCCESS', startedAt: '2026-09-03T10:00:00Z' },
221+
];
222+
assert.equal(currentRollupChecks(rows).length, 2);
223+
assert.deepEqual(countRollup(rows), { fail: 1, pending: 0, pass: 1 });
224+
assert.deepEqual(countRollup([...rows].reverse()), { fail: 1, pending: 0, pass: 1 });
225+
});
226+
217227
// --- the three refuse-to-pass-vacuously paths --------------------------------
218228

219229
/** A `gh` stub that answers each call from a table keyed by a substring. */

0 commit comments

Comments
 (0)