From 66a126926e7c9d489537b4f1871dd2d07059d6d2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 12:39:15 +0000 Subject: [PATCH] CI: install coverage in the background in all-green The coverage install sits on the critical path ahead of the artifact download, which it has nothing to do with, and steps otherwise execute in sequence. Mark it `background: true` and `wait:` for it once the download is done. Measured, the install and the download now occupy the same two second window and the wait costs nothing, taking the job from 20s to 17s. A background step that fails is reported at the wait, so a broken install still fails the job. The alls-green check moves to the end of the job because of an awkward interaction: a `wait:` step does not accept an `if:` (the workflow fails to parse with "Unexpected value 'if'"), so the wait cannot carry `always()` and has to sit in a prefix of steps that nothing failing can skip. Every step in this job already ran under `always()`, so the check's position was not gating anything - it only sets the job's conclusion. It keeps `always()` in its new position so a coverage failure doesn't skip it and lose the report of which needed job failed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GFG654D9KD6rxzQ6R453qm --- .github/workflows/ci.yml | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b229c98ce41a..453d12c342e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -484,19 +484,23 @@ jobs: timeout-minutes: 3 with: persist-credentials: false - - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 - with: - jobs: ${{ toJSON(needs) }} - - run: pip install -c ci-constraints-requirements.txt coverage[toml] - if: ${{ always() }} + # Runs in the background so it overlaps the artifact download + # below; the wait step is where a failure here surfaces. A `wait:` + # step cannot carry a condition, so it has to sit in a prefix of + # steps that nothing failing can skip - which is why the alls-green + # check moved to the end of the job. + - name: Install coverage + id: coverage + run: pip install -c ci-constraints-requirements.txt coverage[toml] + background: true - name: Download coverage data - if: ${{ always() }} uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: coverage-data-* merge-multiple: true path: coverage-data/ + - name: Wait for coverage + wait: [coverage] - name: Combine coverage and fail if it's <100%. if: ${{ always() }} id: combinecoverage @@ -519,3 +523,10 @@ jobs: path: htmlcov if-no-files-found: ignore if: ${{ failure() && steps.combinecoverage.outcome == 'failure' }} + # always(), so that a failure in the coverage steps above doesn't + # skip this and lose the report of which needed job failed. + - name: Decide whether the needed jobs succeeded or failed + if: ${{ always() }} + uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 + with: + jobs: ${{ toJSON(needs) }}