From b1dee22acc13fd35549c5a05b646b58ac3681391 Mon Sep 17 00:00:00 2001 From: "Matthew T. Hunter" Date: Thu, 30 Jul 2026 20:09:44 -0400 Subject: [PATCH] ci: run on pull_request and add the "CI passed" aggregator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `main` ruleset (created 2026-07-29) requires a status check named "CI passed". No workflow in this repo produced it, and the only workflow here had no `pull_request` trigger at all — so nothing ran on a PR and the required check could never arrive. Every pull request was permanently unmergeable. It went unnoticed because both merged PRs (#1, #2) landed on 2026-06-29, a month before the ruleset existed; #3 is the first PR to meet the rule. "CI passed" is doppler's aggregator job name, so the ruleset appears to have been copied from doppler's without the workflow that makes the name true. Two changes: - `pull_request` trigger, with NO path filter. The required check must report on every PR, so the job has to run on every PR — a path filter would skip it on an unrelated change and reproduce the same deadlock. - a `ci-passed` job named "CI passed", gating on every other job, mirroring doppler's ci.yml aggregator so the org has one shape. `if: always()` so it still reports when a dependency fails, rather than being skipped and leaving a red PR indistinguishable from an unmergeable one. This workflow runs on its own PR (pull_request events use the merge ref), so the fix is self-bootstrapping: the PR that adds the check is the first to be gated by it. --- .github/workflows/check-readme.yml | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/.github/workflows/check-readme.yml b/.github/workflows/check-readme.yml index fd70709..058b4a5 100644 --- a/.github/workflows/check-readme.yml +++ b/.github/workflows/check-readme.yml @@ -8,6 +8,13 @@ on: - README.md - .github/workflows/check-readme.yml - .github/scripts/check-readme-content.sh + # No path filter on pull_request, deliberately. The `main` ruleset requires + # the "CI passed" check below on every PR, so it has to run on every PR — + # a path filter would skip the job on an unrelated change and the required + # check would never arrive, leaving the PR unmergeable forever. (That is + # exactly what happened before this trigger existed: the ruleset required a + # check that no workflow here could ever report.) + pull_request: schedule: # Weekly — catches drift from the *other* side: an alias removed from # aliases.toml, a repo renamed, a PyPI package yanked. Nothing here @@ -22,3 +29,30 @@ jobs: - uses: actions/checkout@v4 - name: Check profile/README.md run: .github/scripts/check-readme-content.sh profile/README.md + + # ------------------------------------------------------------------ + # Aggregator: the single "CI passed" check the `main` ruleset requires. + # Green only when every job above succeeded. Adding a job to this workflow + # means adding it to `needs:` here — otherwise the aggregator goes green + # while the new job is red, and the required check stops meaning anything. + # Mirrors doppler's ci.yml aggregator so the org has one shape. + # ------------------------------------------------------------------ + ci-passed: + name: CI passed + needs: + - check + runs-on: ubuntu-latest + # `always()` so this job still runs when a dependency failed — otherwise it + # would be skipped, the required check would never report, and a red PR + # would look identical to an unmergeable one. + if: always() + steps: + - name: Require all jobs to have succeeded + run: | + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" || \ + "${{ contains(needs.*.result, 'cancelled') }}" == "true" || \ + "${{ contains(needs.*.result, 'skipped') }}" == "true" ]]; then + echo "::error::a required CI job did not succeed — CI not green" + exit 1 + fi + echo "All required CI jobs succeeded."