diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34a4f0cc..52ed16cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,3 +151,27 @@ jobs: $listeners | Format-Table -AutoSize LocalAddress, LocalPort, OwningProcess throw "Desktop E2E left an orphaned process or a listener on port 4445." } + + ci-gate: + name: CI Gate + if: ${{ always() }} + needs: [check-frontend, check-backend, test-e2e-desktop] + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Verify required check results + env: + NEEDS_RESULTS: ${{ toJSON(needs) }} + run: | + node --input-type=module <<'NODE' + const jobs = JSON.parse(process.env.NEEDS_RESULTS); + if (Object.keys(jobs).length === 0) throw new Error("No prerequisite results were provided."); + + let failed = false; + for (const [name, { result }] of Object.entries(jobs)) { + console.log(`${name}: ${result} (expected success)`); + if (result !== "success") failed = true; + } + process.exit(failed ? 1 : 0); + NODE diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8c1ef02..932f9058 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -185,6 +185,12 @@ Verify changes locally before merging. Use `pnpm check:frontend` for frontend-on Frontend checks enforce a coverage floor. It is a ratchet set just below the measured numbers rather than a target: a change that falls below it needs tests, not a lower floor, and the floor is raised when the measured numbers move up. +### CI Enforcement + +The `CI Gate` job in [the CI workflow](./.github/workflows/ci.yml) waits for `Frontend Checks`, `Backend Checks`, and `Desktop E2E`. It runs even when a prerequisite fails or is skipped, and passes only when every prerequisite succeeds. + +To change the required validation, update `ci-gate.needs` with the relevant job IDs. If a job becomes conditional, update the gate's result policy in the same pull request so intentional skips are explicit and unexpected skips still fail. Keep the `CI Gate` display name stable because GitHub branch protection uses it. When migrating branch protection, retain the existing required checks until the gate passes on a pull request and is merged, then require `CI Gate` from GitHub Actions. + ## Maintainer Project Management Maintainers own issue classification, scheduling, and project state. Contributors only need to provide the information requested by the relevant issue template; maintainers triage contributor-reported issues after they are opened.