diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1221f8802..2da6f7d310 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1012,11 +1012,17 @@ jobs: # Same stale-checkout guard as the Ubuntu gate: this job now runs on ECS, # so fail loud if the checkout lacks the merge-queue head rather than # silently testing the wrong tree into a merge. + # Written when this lane ran in the merge queue alone, so its expected + # SHA named only the queue's event: on any other trigger the input is + # empty and the step fails the whole lane before a single test runs. + # That is what the revived triggers hit first. Same event-aware shape as + # the Ubuntu gate now, and skipped where there is no head to verify — + # the scheduled and dispatch runs check out a branch by name. - name: 'Verify checkout includes expected head commit' - if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}" + if: "${{ needs.classify_pr.outputs.skip_ci != 'true' && (github.event_name == 'pull_request' || github.event_name == 'merge_group') }}" uses: './.github/actions/verify-checkout-head' with: - expected_sha: '${{ github.event.merge_group.head_sha }}' + expected_sha: "${{ github.event_name == 'merge_group' && github.event.merge_group.head_sha || github.event.pull_request.head.sha }}" # Avoid setup-node downloads on ECS, where nodejs.org may be unreachable # through the egress proxy; reuse the machine's Node instead. diff --git a/scripts/tests/ci-platform-lanes.test.js b/scripts/tests/ci-platform-lanes.test.js index 0d2af40c56..4ebe415d12 100644 --- a/scripts/tests/ci-platform-lanes.test.js +++ b/scripts/tests/ci-platform-lanes.test.js @@ -64,6 +64,35 @@ describe('platform lanes — triggers', () => { }); } + for (const lane of LANES) { + it(`${lane}'s steps are gated for every trigger it now has`, () => { + // The first thing the revived triggers hit was not a test failure but + // the lane's own plumbing: a `verify-checkout-head` step written when + // this lane ran in the merge queue alone, with `expected_sha` naming + // only `github.event.merge_group.head_sha`. On a pull request that + // input is empty and the step fails the lane before a single test + // runs. A step whose inputs name one event must be gated to that + // event — for every step in a job that now runs on four. + for (const step of ci.jobs[lane].steps ?? []) { + const inputs = JSON.stringify(step.with ?? {}); + const gate = String(step.if ?? ''); + for (const [context, event] of [ + ['github.event.merge_group', "'merge_group'"], + ['github.event.pull_request', "'pull_request'"], + ]) { + if (!inputs.includes(context)) continue; + const guarded = + inputs.includes(`github.event_name == ${event}`) || + gate.includes(`github.event_name == ${event}`); + expect( + guarded, + `${lane} step "${step.name}" reads ${context} on every trigger`, + ).toBe(true); + } + } + }); + } + it('keeps a nightly run to exactly the two lanes', () => { // A `schedule:` trigger fires the whole workflow. Every other job must // therefore either exclude `schedule` outright or gate on an event