diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 2a4065bff47..795beca131e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -667,6 +667,14 @@ jobs: runner: ubuntu-24.04-arm shards: ${{ needs.unit_plan.outputs.shards }} + # Why a sibling and not part of the test workflow: it is advisory, so it must not delay the + # gate. Inside unit-tests.yml a caller's `needs: test` waited for it, holding verify ~36s + # after the last shard. Deliberately absent from verify's needs for the same reason. + unit_selection_evidence: + needs: [test] + if: ${{ !cancelled() && needs.test.result == 'success' }} + uses: ./.github/workflows/unit-selection-evidence.yml + # Why a separate job: the test needs a real Chrome, and the sharded `test` matrix # would pay for it on every shard to run one file in whichever shard it landed in. orcad_browser: diff --git a/.github/workflows/unit-selection-evidence.yml b/.github/workflows/unit-selection-evidence.yml new file mode 100644 index 00000000000..4ff46be84d0 --- /dev/null +++ b/.github/workflows/unit-selection-evidence.yml @@ -0,0 +1,41 @@ +name: Unit selection evidence + +# Why its own workflow: this job is advisory -- `continue-on-error` on both the job and its +# comparison step, so it can never fail a PR. But a caller's `needs: test` waits for every job in +# the called workflow, so while it lived in unit-tests.yml it held `verify` for ~36s after the +# last shard finished. Called as a sibling instead, it still runs on every PR and still uploads +# its review artifact; it just no longer sits on the critical path. +on: + workflow_call: + +permissions: + contents: read + +jobs: + selection_evidence: + if: ${{ !cancelled() }} + continue-on-error: true + runs-on: ubuntu-slim + steps: + - uses: actions/checkout@v6 + with: + sparse-checkout: config/scripts/ci-unit-selection-review.mjs + sparse-checkout-cone-mode: false + persist-credentials: false + - uses: actions/setup-node@v6 + with: + node-version: '24' + - uses: actions/download-artifact@v8 + with: + pattern: unit-shard-node-*-attempt-${{ github.run_attempt }} + path: unit-evidence/ + - name: Compare selection with full results + continue-on-error: true + run: node config/scripts/ci-unit-selection-review.mjs unit-evidence + - uses: actions/upload-artifact@v7 + if: always() + continue-on-error: true + with: + name: unit-selection-review-attempt-${{ github.run_attempt }} + path: unit-evidence/selection-review.json + retention-days: 30 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 0090387b75c..abe9cf28a41 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -75,35 +75,6 @@ jobs: retention-days: 14 if-no-files-found: warn - selection_evidence: - needs: test - if: ${{ !cancelled() }} - continue-on-error: true - runs-on: ubuntu-slim - steps: - - uses: actions/checkout@v6 - with: - sparse-checkout: config/scripts/ci-unit-selection-review.mjs - sparse-checkout-cone-mode: false - persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version: '24' - - uses: actions/download-artifact@v8 - with: - pattern: unit-shard-node-*-attempt-${{ github.run_attempt }} - path: unit-evidence/ - - name: Compare selection with full results - continue-on-error: true - run: node config/scripts/ci-unit-selection-review.mjs unit-evidence - - uses: actions/upload-artifact@v7 - if: always() - continue-on-error: true - with: - name: unit-selection-review-attempt-${{ github.run_attempt }} - path: unit-evidence/selection-review.json - retention-days: 30 - relay_integration: name: relay integration node ${{ matrix.node }} strategy: diff --git a/config/scripts/pr-workflow-parallelism.test.mjs b/config/scripts/pr-workflow-parallelism.test.mjs index 6054f026144..ffd3e1c9fc9 100644 --- a/config/scripts/pr-workflow-parallelism.test.mjs +++ b/config/scripts/pr-workflow-parallelism.test.mjs @@ -501,6 +501,22 @@ describe('PR workflow parallelism', () => { } }) + it('keeps advisory unit-selection evidence off the gate', () => { + // It is continue-on-error, so it can never fail a PR. Living inside unit-tests.yml made a + // caller's `needs: test` wait for it anyway, holding verify ~36s past the last shard. Pinned + // here so it cannot drift back onto the critical path. + const evidence = workflow.jobs.unit_selection_evidence + expect(evidence.uses).toBe('./.github/workflows/unit-selection-evidence.yml') + expect(evidence.needs).toEqual(['test']) + expect(workflow.jobs.verify.needs).not.toContain('unit_selection_evidence') + expect(unitTestWorkflow.jobs.selection_evidence).toBeUndefined() + const evidenceWorkflow = parse( + readFileSync('.github/workflows/unit-selection-evidence.yml', 'utf8') + ) + const job = evidenceWorkflow.jobs.selection_evidence + expect(job['continue-on-error']).toBe(true) + }) + it('keeps verify as the aggregate required check', () => { expect(workflow.jobs.verify.needs).toEqual([ 'code_paths',