ci: add a branch-protection fan-in gate per workflow - #1173
Merged
Conversation
GitHub evaluates a job's `if:` before expanding its matrix, so a matrix job
skipped at job level reports one check run under the unexpanded name --
`Build CLI for ${{ matrix.platform.target }}` rather than one context per
platform. Any per-leg context required by branch protection then never
reports and the PR hangs on "Expected -- Waiting for status to be reported".
Each PR workflow now ends in a `gate` job that always runs and passes when
every job it needs finished success-or-skipped. That gives branch protection
one stable context per workflow instead of 12 hand-typed matrix-leg names
that also break on any matrix edit (runner labels and Xcode versions are
currently baked into them).
Each gate's `needs` lists the jobs that are required checks today, so the
required set is preserved rather than widened. It also removes a latent
ambiguity: the required context `build` currently matches the `build` job in
both ruby.yml and wasm.yml.
No behavior change on its own -- the gate only aggregates results.
|
😎 This pull request was merged. |
The gate only reads `needs.*.result`, so anything beyond a few seconds means it is wedged rather than working -- and a wedged required check blocks merges until the default 6h job timeout expires.
|
acatxnamedvirtue
approved these changes
Aug 27, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1173 +/- ##
==========================================
+ Coverage 83.07% 83.31% +0.23%
==========================================
Files 72 72
Lines 16313 16313
==========================================
+ Hits 13552 13591 +39
+ Misses 2761 2722 -39 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Stacked PR 1170 failed testing in the merge queue. Please investigate the failure and re-submit the stack. |
|
This pull request was merged into |
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.
Prep for Dynamic CI (#1170 stacks on this), but a standalone fix for a problem the repo already has.
The problem
GitHub evaluates a job's
if:before expanding its matrix. So a matrix job skipped at job level reports one check run under the unexpanded name:Branch protection on
mainrequires 12 expanded per-leg contexts (Build CLI for x86_64-apple-darwin,macos (macos-14, aarch64, 16), …). Those never report, and the PR hangs on "Expected — Waiting for status to be reported" forever.Non-matrix jobs are unaffected: they report
skipped, which satisfies a required check.There's a second, pre-existing problem with the current context list: it hard-codes runner labels and Xcode versions, so any matrix edit silently breaks branch protection. And the required context
buildis ambiguous — it matches thebuildjob in bothruby.ymlandwasm.yml.The fix
Each PR workflow now ends in a
gatejob that always runs and passes when every job it needs finished success-or-skipped:PR Gatebuild_release,test,trunk_check_runner,build_pyo3,build_wasmcontext-py Gatelinux,macos,sdistrspec Gatebuildcontext-js GatebuildEach gate's
needslists the jobs that are required checks today, so the required set is preserved rather than widened.linux-pytest,build-ruby-gemandtest-ruby-gem-uploadsare deliberately omitted for that reason — one-line additions if they should start blocking merge.No behavior change on its own. The gate only aggregates results; nothing is skipped by this PR.
Ruleset edit (after this merges, before #1170)
Ruleset
main(id14925321): replace all 17 contexts with the 4 gate names.strict_required_status_checks_policystaysfalse;bypass_actors(2 exempt Integrations) and thedeletion/non_fast_forward/pull_requestrules are untouched.Two notes on that edit:
PUT /rulesets/{id}replaces the entire ruleset, so omittingbypass_actorswould silently strip the two exempt Integrations. A UI edit avoids the hazard.main, so they'll show the 4 new contexts as "Expected" until they do.One deliberate tightening
Branch protection currently requires only 4 of 5 matrix legs for
build_releaseandtest— the Windows legs are excluded. A fan-in can only aggregate at job granularity, soBuild CLI for x86_64-pc-windows-gnuandTest for x86_64-pc-windows-gnuwill start blocking merge. Accepted deliberately.Rejected alternatives
workflowsruleset rule ("Require workflows to pass before merging") would need no YAML at all and is immune to renames — but it is GitHub Enterprise Cloud only andtrunk-iois on Team. Attempting it returns422 Invalid rule 'workflows'with an empty per-entry error.Test plan
trunk checkclean (actionlint, prettier, yamllint, checkov, shellcheck, shfmt).