Skip to content

Commit e5c9cdf

Browse files
committed
fix(ci): sweep PRs with unknown mergeability — stuck merge-ref is the target pathology
Live verification showed dropped-CI PRs report mergeable=null and mergeable_state=unknown indefinitely: the stuck merge-ref computation is the same failure that dropped their CI, and close/reopen is what un-sticks it. The pending-mergeability skip therefore made the primary repair population permanently unsweepable (three real dropped PRs skipped across three consecutive sweeps). Keep skipping computed conflicts; a not-yet-computed conflict costs at most one budgeted re-fire.
1 parent a7e4765 commit e5c9cdf

2 files changed

Lines changed: 8 additions & 9 deletions

File tree

scripts/github/pr-ci-sweeper.mjs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,14 @@ export function classifyPrForSweep({ pr, ciRuns, botCloseCount, now }) {
3737
return { action: "skip", reason: "recently-updated" };
3838
}
3939
// A conflicted PR legitimately has no merge ref; CI cannot attach until the
40-
// author resolves, so re-firing would loop forever.
40+
// author resolves, so re-firing would loop forever. Null/unknown mergeability
41+
// is NOT skipped: live testing showed dropped-CI PRs stay mergeable=null
42+
// indefinitely (the stuck merge-ref computation IS the pathology), and
43+
// close/reopen is what un-sticks it. A not-yet-computed conflict costs at
44+
// most one budgeted re-fire before the recomputed false skips it.
4145
if (pr.mergeable === false) {
4246
return { action: "skip", reason: "merge-conflict" };
4347
}
44-
// Pending computation resolves by the next hourly sweep; do not close/reopen
45-
// on an unknown merge state.
46-
if (pr.mergeable === null || pr.mergeable === undefined) {
47-
return { action: "skip", reason: "mergeability-pending" };
48-
}
4948
// Closing a PR silently cancels enabled auto-merge and reopening does not
5049
// restore it; leave those PRs (e.g. generated locale refreshes) to a human.
5150
if (pr.auto_merge) {
@@ -203,7 +202,7 @@ export async function runPrCiSweeper({ github, context, core, dryRun = false, ap
203202
fresh.state !== "open" ||
204203
fresh.head.sha !== pr.head.sha ||
205204
fresh.auto_merge ||
206-
fresh.mergeable !== true
205+
fresh.mergeable === false
207206
) {
208207
core.info(`pr-ci-sweeper: #${pr.number} changed during sweep; leaving it alone`);
209208
continue;

test/scripts/pr-ci-sweeper.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ describe("classifyPrForSweep", () => {
113113
expected: { action: "skip", reason: "refire-budget-exhausted" },
114114
},
115115
{
116-
name: "skips while mergeability is still computing",
116+
name: "re-fires on unknown mergeability (stuck merge-ref IS the pathology)",
117117
input: { pr: pr({ mergeable: null }), ciRuns: [], botCloseCount: 0, now: NOW },
118-
expected: { action: "skip", reason: "mergeability-pending" },
118+
expected: { action: "refire", reason: "ci-run-missing" },
119119
},
120120
];
121121

0 commit comments

Comments
 (0)