From 0156604e966ae8cea6ec658ede750000a6886903 Mon Sep 17 00:00:00 2001 From: sotashimozono Date: Fri, 4 Sep 2026 11:46:11 +0000 Subject: [PATCH] ci: gate on one aggregate context instead of four matrix legs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Branch protection named `julia 1.11 — ubuntu-latest` and three siblings. Adding a Julia version to the matrix left the new leg ungated; renaming one would have made `main` permanently unmergeable, because the required context would never report again. `All tests passed` is now the single context, and `if: always()` on it is load-bearing in a way that is invisible from reading the file. Measured on a scratch branch by failing a leg on purpose: needs: alone, required leg fails -> All tests passed = SKIPPED if: always(), required leg fails -> All tests passed = failure if: always(), nightly fails -> All tests passed = success GitHub counts a skipped required check as passing, so the first row is not a smaller version of the second — it is a gate that lets a red pull request through, which is worse than what it replaces. The third row is the property that matters for `continue-on-error`: a failing nightly stays out of `needs.test.result`. Branch protection is not changed here. The context has to report at least once before it can be required, or requiring it deadlocks `main`. Refs #6. Co-Authored-By: Claude Opus 5 --- .github/workflows/CI.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7043575..12cfd89 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -79,3 +79,23 @@ jobs: - run: julia --project=docs -e 'using Pkg; Pkg.instantiate(); include("docs/make.jl")' env: GKSwstype: nul + + # The one context branch protection requires. Without it, protection has to name each matrix + # leg, and adding a Julia version leaves the new leg ungated while renaming one makes `main` + # permanently unmergeable. + # + # `if: always()` is load-bearing, and its absence is silent. Measured 2026-09-03 by failing a + # leg on purpose: with `needs:` alone this job is SKIPPED when a required leg fails, and GitHub + # counts a skipped required check as passing — so the gate would let a red pull request + # through, which is worse than the per-leg contexts it replaces. Measured with `always()`: + # a required leg failing gives `failure`, and a failing `nightly` still gives `success`, + # because `continue-on-error` keeps it out of `needs.test.result`. + all-tests: + name: All tests passed + needs: test + if: always() + runs-on: ubuntu-latest + steps: + - run: | + echo "needs.test.result = ${{ needs.test.result }}" + test "${{ needs.test.result }}" = "success"