ci: make required checks always report on path-scoped workflows - #404
Merged
Conversation
Every cloud-only PR was permanently unmergeable. Branch protection requires fourteen Rust CI contexts; rust.yml carried `paths-ignore: cloud/**`, so on a cloud-only change the workflow never started, never created those check runs, and the PR sat at "Expected — Waiting for status" with nothing to click. mergeStateStatus BLOCKED, every check that did run green, no way forward except an admin override. PR #403 is the current example. A workflow skipped by a path filter creates no check runs. A *job* skipped by an `if:` condition does create one, concludes "skipped", and branch protection counts that as satisfied. So both workflows now always start, decide once in a `changes` job whether their tree was touched, and let every other job skip itself when it wasn't. `changes` reads the PR's file list from the API rather than cloning full history to diff it — this repo is large enough that fetch-depth: 0 on every job is a real cost. Push events skip the detection entirely and run everything, since only pull requests are gated by branch protection. An empty or unreadable file list falls through to running CI, so the failure mode is wasted minutes rather than an ungated merge. This also lets cloud's `build` become a required context for the first time: it now reports on Rust-only PRs (as skipped) instead of never appearing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Two defects in the previous commit, both caught by its own PR run. The cloud detection job inherited the workflow-level `working-directory: cloud` but never checks out, so bash could not start: "No such file or directory". rust.yml has no such default, which is why only one of the two failed. The worse one: `build` still reported "skipped" after that failure, and branch protection accepts skipped. A broken detection step would therefore have merged cloud changes with no CI at all — fail-open, the exact hazard this whole change exists to remove. Both workflows now run the gated jobs when detection itself fails. `!cancelled()` is required for a job to be considered at all once a dependency has failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mohabbis
added a commit
that referenced
this pull request
Aug 4, 2026
#405) * ci: require one aggregate Rust context instead of fourteen matrix ones PR #404 moved path scoping into an `if:` so required checks would always report. That works for non-matrix jobs — Rustfmt, Version consistency and Frontend contract tests all reported "skipped" on #403 as intended — and does not work for the matrix ones. A matrix job skipped by an `if:` condition never expands its matrix, so its check run is created under the literal name "Check (${{ matrix.os }})" rather than "Check (ubuntu-latest)". Requiring the expanded names therefore leaves them waiting forever on a cloud-only PR: the same deadlock #404 set out to fix, one level down, which is why #403 was still BLOCKED afterwards. A non-matrix aggregator has a static name in every case. `rust-ci` needs the seven previously-required jobs, runs with `always()` so it still reports when they skipped, and fails if any of them failed or was cancelled. Required contexts become "Rust CI" and "build" — two instead of fifteen, and adding an OS to the matrix no longer means editing branch protection. `experimental` is deliberately not among the dependencies: it was not a required context before this change and this is not the commit that makes it one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ci: fix invalid expression in the Rust CI aggregator GitHub expressions accept single-quoted string literals only. The aggregator used join(needs.*.result, ",") with double quotes, which is a workflow-file syntax error rather than a runtime one: the run fails to start, no jobs are created, and the PR shows no Rust checks at all — not a failure that points at the offending line. Replaced with the contains(needs.*.result, 'failure') pattern, which needs no string literal argument and is the more conventional spelling anyway. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every cloud-only PR is currently unmergeable.
masterrequires fourteen Rust CI contexts;rust.ymlcarriedpaths-ignore: cloud/**, so on a cloud-only change the workflow never started, never created those check runs, and the PR sits at "Expected — Waiting for status" forever —mergeStateStatus: BLOCKED, every check that actually ran green, no way forward except an admin override. PR #403 is the live example.What changed
A workflow skipped by a path filter creates no check runs. A job skipped by an
if:condition does create one, concludesskipped, and branch protection counts that as satisfied.So both workflows now always start, decide once in a
changesjob whether their tree was touched, and let every other job skip itself when it wasn't.rust.yml—paths-ignoreremoved fromon:; all 8 jobs gainedneeds: changes+if: needs.changes.outputs.rust == 'true'. The ignore list moved verbatim into the detection step.cloud.yml— same shape, mirrored.changesreads the PR file list viagh api .../pulls/N/filesrather thanfetch-depth: 0on every job.Follow-up (after this merges)
build(cloud) can become a required context for the first time — it now reports on Rust-only PRs asskippedinstead of never appearing. Required-check list to be updated once this is onmaster.Validation
Both files parse; all 9 + 2 jobs confirmed gated. Because this PR touches
.github/workflows/rust.yml,changesresolvesrust=trueand the full Rust matrix runs for real here — this PR validates itself.🤖 Generated with Claude Code