ci: give each CI job one home in the merge-queue flow (#5842)

Now that the merge queue is live, each job should run in exactly one place instead of doubling up.

- CodeQL and E2E leave the merge queue (CodeQL gains a merge_group guard, E2E loses its merge_group trigger). Neither is a required check, so neither gated a merge — CodeQL just ran ~30min and got cancelled at merge every time, and the three E2E jobs burned ~25/36/36min of hosted time, for nothing. They keep running post-merge on push to main.
- macOS/Windows move to merge_group only (they were also running on push to main), and the ubuntu Test job stops running on push too. The queue already tests the merged tree, so re-running these gate jobs on the post-merge push is redundant.

Net: PR runs ubuntu; the merge queue runs ubuntu + integration + mac + win (the gate); push to main runs CodeQL + E2E (the backstop). No job runs in two of those.
This commit is contained in:
易良 2026-06-25 14:09:08 +08:00 committed by GitHub
parent 9faa23db4d
commit 4bd113518f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 18 deletions

View file

@ -111,7 +111,9 @@ jobs:
needs: 'classify_pr'
# Stay running on release-sync PRs so the required Test contexts still
# report; the per-step skip_ci guards below make them no-op (pass) there.
if: '${{ !cancelled() }}'
# Not on push: the merge queue already tested the merged tree, so a
# post-merge re-run on `main` would be redundant.
if: "${{ !cancelled() && github.event_name != 'push' }}"
runs-on: '${{ fromJSON(needs.classify_pr.outputs.ubuntu_runner || ''["ubuntu-latest"]'') }}'
permissions:
contents: 'read'
@ -272,16 +274,18 @@ jobs:
name: 'coverage-reports-22.x-ubuntu-latest'
path: 'packages/*/coverage'
# macOS/Windows: slowest/costliest runners, rare platform regressions — skip
# on PR, run on push to `main` and in the merge queue. Two named jobs, not a
# matrix: a skipped matrix job reports one collapsed check name, never the
# per-OS required contexts, so PRs would sit "Expected" forever and never
# enter the queue. A skipped named job reports under its exact name and
# satisfies the required check (same as the Integration Tests job).
# macOS/Windows: slowest/costliest runners, rare platform regressions — run
# only in the merge queue. Skipped on PR (ubuntu is the fast PR signal) and on
# push (the queue already tested the merged tree, so a post-merge re-run is
# redundant). Two named jobs, not a matrix: a skipped matrix job reports one
# collapsed check name, never the per-OS required contexts, so PRs would sit
# "Expected" forever and never enter the queue. A skipped named job reports
# under its exact name and satisfies the required check (same as the
# Integration Tests job).
test_macos:
name: 'Test (macos-latest, Node 22.x)'
needs: 'classify_pr'
if: "${{ !cancelled() && github.event_name != 'pull_request' }}"
if: "${{ !cancelled() && github.event_name == 'merge_group' }}"
runs-on: 'macos-latest'
permissions:
contents: 'read'
@ -329,7 +333,7 @@ jobs:
test_windows:
name: 'Test (windows-latest, Node 22.x)'
needs: 'classify_pr'
if: "${{ !cancelled() && github.event_name != 'pull_request' }}"
if: "${{ !cancelled() && github.event_name == 'merge_group' }}"
runs-on: 'windows-2022'
permissions:
contents: 'read'
@ -418,10 +422,12 @@ jobs:
codeql:
name: 'CodeQL'
needs: 'classify_pr'
# Security findings rarely change push-to-push, so a slow scan on every PR
# push is poor value. Skip on PR pushes; CodeQL still runs on push to `main`
# (and in the merge queue, once enabled) as the pre-/post-merge backstop.
if: "${{ !cancelled() && needs.classify_pr.outputs.skip_ci != 'true' && github.event_name != 'pull_request' }}"
# Security findings rarely change push-to-push, and a slow scan is poor value
# as a hard merge gate. Run CodeQL only on push to `main` (post-merge
# backstop) — not on PR pushes, and not in the merge queue where, being
# non-required, it would just burn a runner and lengthen the serial queue
# without blocking anything.
if: "${{ !cancelled() && needs.classify_pr.outputs.skip_ci != 'true' && github.event_name != 'pull_request' && github.event_name != 'merge_group' }}"
runs-on: 'ubuntu-latest'
# Analysis normally finishes in ~7-9 min (22 min worst case observed). Without
# an explicit cap, a hosted runner that drops its heartbeat mid-analysis leaves

View file

@ -1,11 +1,14 @@
name: 'E2E Tests'
on:
# E2E runs post-merge on `main` (per-commit signal) only. It is intentionally
# NOT in the merge queue yet: it is slow and currently flaky, so gating the
# serial queue on it would stall every merge. Promote it to `merge_group` +
# required once it is reliable.
push:
branches:
- 'main'
- 'feat/e2e/**'
merge_group:
concurrency:
# Key on the head ref so a `push` to a `feat/e2e/**` branch and a
@ -13,11 +16,10 @@ concurrency:
# other instead of running the matrix twice for the same change.
group: |-
${{ github.workflow }}-${{ github.head_ref || github.ref_name }}
# Cancel superseded PR / feature-branch runs, but let every `main`
# commit finish (complete per-commit e2e signal, matching ci.yml) and
# never cancel merge-queue runs.
# Cancel superseded feature-branch runs, but let every `main` commit finish
# (complete per-commit e2e signal, matching ci.yml).
cancel-in-progress: |-
${{ github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref != 'refs/heads/main') }}
${{ github.event_name == 'push' && github.ref != 'refs/heads/main' }}
jobs:
e2e-test-linux: