mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
feat(ci): surface merge-queue needs-validation ejection as a PR comment (#5519)
A PR ejected from the merge queue by the needs-validation gate leaves no trace on the PR itself: the gate fails on the queue's transient ref, the PR's own checks stay green, and mergeQueueEntry silently goes null. The only way to learn why the PR fell out of the queue is to dig through merge_group workflow runs, which nobody watches (observed on #5329). Producer: the merge_group gate in ci.yml now emits a handoff/comment artifact targeting the labeled PR right before it blocks, and uploads it on the failure path. Consumer: comment.atom.yml accepts merge_group workflow_run events; since a merge_group run's head_sha is the queue's synthetic merge commit, artifacts from those runs are bound to their producing run by run_id, and the base-freshness skip is waived (PRs ahead in the queue move the base while the run completes). The live-PR head check still guards staleness. Topology coverage pins the new boundary: comment.atom consumes pull_request + merge_group; autofix/report stay pull_request-only.
This commit is contained in:
@@ -343,12 +343,40 @@ describe("packaged smoke workflow", () => {
|
||||
expect(dockerTrigger).not.toContain("branches: [main]");
|
||||
expect(dockerTrigger).not.toContain("- main");
|
||||
expect(commentWorkflow).toContain("workflows: [ci]");
|
||||
expect(commentWorkflow).toContain("github.event.workflow_run.event == 'pull_request'");
|
||||
// comment.atom consumes merge_group runs too, so the needs-validation gate can surface a
|
||||
// queue-ejection notice on the PR; autofix/report stay pull_request-only trusted consumers.
|
||||
expect(commentWorkflow).toContain(
|
||||
"(github.event.workflow_run.event == 'pull_request' || github.event.workflow_run.event == 'merge_group')",
|
||||
);
|
||||
expect(autofixWorkflow).toContain("workflows: [ci]");
|
||||
expect(autofixWorkflow).toContain("github.event.workflow_run.event == 'pull_request'");
|
||||
expect(autofixWorkflow).not.toContain("merge_group");
|
||||
expect(autofixWorkflow).not.toContain("ci-nix");
|
||||
expect(reportWorkflow).toContain("workflows: [ci]");
|
||||
expect(reportWorkflow).toContain("github.event.workflow_run.event == 'pull_request'");
|
||||
expect(reportWorkflow).not.toContain("merge_group");
|
||||
});
|
||||
|
||||
it("[P2] surfaces a merge-queue needs-validation ejection as a PR comment handoff", async () => {
|
||||
const [ciWorkflow, commentWorkflow] = await Promise.all([
|
||||
readFile(ciWorkflowPath, "utf8"),
|
||||
readFile(commentWorkflowPath, "utf8"),
|
||||
]);
|
||||
|
||||
// Producer: the merge_group gate emits a handoff/comment artifact for the labeled PR when
|
||||
// it blocks, and uploads it on the failure path (the gate exits 1 exactly when it produces).
|
||||
expect(ciWorkflow).toContain("<!-- merge-queue-needs-validation -->");
|
||||
expect(ciWorkflow).toContain("emit_ejection_notice");
|
||||
expect(ciWorkflow).toContain(
|
||||
"if: ${{ failure() && steps.needs_validation_gate.outputs.comment_created == 'true' }}",
|
||||
);
|
||||
|
||||
// Consumer: a merge_group run's head_sha is the queue's synthetic merge commit, so the atom
|
||||
// binds merge_group artifacts to their producing run by run_id and skips the base-freshness
|
||||
// check (PRs ahead in the queue move the base while the run completes).
|
||||
expect(commentWorkflow).toContain('"$RUN_EVENT" = "merge_group"');
|
||||
expect(commentWorkflow).toContain('"$artifact_run_id" != "$RUN_ID"');
|
||||
expect(commentWorkflow).toContain('[ "$RUN_EVENT" != "merge_group" ] && [ "$current_base" != "$base_sha" ]');
|
||||
});
|
||||
|
||||
it("[P2] gates the backport auto-merge follow-up as a trusted workflow_run consumer", async () => {
|
||||
|
||||
Reference in New Issue
Block a user