ci: split platform test matrix into named jobs so PRs can enter the merge queue (#5833)
Some checks are pending
Qwen Code CI / Classify PR (push) Waiting to run
Qwen Code CI / Test (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (macos-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (windows-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Blocked by required conditions
Qwen Code CI / Integration Tests (CLI, No Sandbox) (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run

* ci: stop running push CI on release/** branches

release.yml pushes version + changelog commits to the release branch.
With 'release/**' under the push trigger, that fired a full push-event CI
run (mac/win/CodeQL all run since event != pull_request) on the release
PR's head, blocking it from main's merge queue and double-running the
matrix. Nothing gates on it: release branches have no protection and
publish happens inside release.yml. Keep 'release/**' under pull_request
for backport PRs.

* ci: split platform test matrix into named jobs to unblock merge queue

The macOS/Windows tests are required status checks that only run in the
merge queue (if: event_name != 'pull_request'). As a single matrix job, a
skipped run collapses to one check named 'Test (${{ matrix.os }}, Node
${{ matrix.node-version }})' — so the required contexts 'Test
(macos-latest, Node 22.x)' and 'Test (windows-latest, Node 22.x)' are never
reported on the PR head and sit 'Expected' forever, leaving every PR BLOCKED
and unable to enter the queue (observed on #5830/#5832).

Split into two named jobs. A skipped named job reports under its exact name
(conclusion: skipped), which satisfies the required check on the PR head —
exactly how the merge-queue-only Integration Tests job already behaves — so
PRs can enter the queue, where these jobs run for real and gate the merge.
No PR-stage runner cost (skipped jobs spin no runner); no ruleset change.

* test(ci): update no-AK wiring test for split platform jobs

The test looked up the 'test_platforms' matrix job, which this branch
split into named 'test_macos' / 'test_windows' jobs. Assert the same
properties (no no-AK script, immutable PR-head checkout) on both new jobs.
This commit is contained in:
易良 2026-06-24 23:58:15 +08:00 committed by GitHub
parent 5bb79bc67c
commit bc586362dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 26 deletions

View file

@ -6,7 +6,9 @@ on:
push:
branches:
- 'main'
- 'release/**'
# No 'release/**' here: release.yml's commits to the release branch would
# fire a redundant full CI run that blocks the release PR's merge queue.
# Kept under pull_request below for backport PRs.
pull_request:
branches:
- 'main'
@ -270,28 +272,19 @@ jobs:
name: 'coverage-reports-22.x-ubuntu-latest'
path: 'packages/*/coverage'
test_platforms:
name: 'Test (${{ matrix.os }}, Node ${{ matrix.node-version }})'
# 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).
test_macos:
name: 'Test (macos-latest, Node 22.x)'
needs: 'classify_pr'
# macOS/Windows are the slowest, costliest runners and platform-specific
# regressions are rare per push, so rerunning them on every review iteration
# is mostly wasted. Skip on PR pushes; they still run on push to `main` (and
# in the merge queue, once enabled), catching platform breakage before it
# ships without sitting on every PR's critical path.
if: "${{ !cancelled() && github.event_name != 'pull_request' }}"
runs-on: '${{ fromJSON(matrix.runner) }}'
runs-on: 'macos-latest'
permissions:
contents: 'read'
strategy:
fail-fast: false
matrix:
include:
- os: 'macos-latest'
runner: '["macos-latest"]'
node-version: '22.x'
- os: 'windows-latest'
runner: '["windows-2022"]'
node-version: '22.x'
steps:
# See the Ubuntu gate's checkout: on PRs use the immutable refs/pull/N/head
# to avoid merge-ref rebuild lag; other events keep github.ref.
@ -302,11 +295,57 @@ jobs:
with:
ref: "${{ github.event.inputs.branch_ref || (github.event_name == 'pull_request' && format('refs/pull/{0}/head', github.event.pull_request.number)) || github.ref }}"
- name: 'Set up Node.js ${{ matrix.node-version }}'
- name: 'Set up Node.js 22.x'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version: '${{ matrix.node-version }}'
node-version: '22.x'
cache: 'npm'
cache-dependency-path: 'package-lock.json'
registry-url: 'https://registry.npmjs.org/'
- name: 'Configure npm for rate limiting'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
run: |-
npm config set fetch-retry-mintimeout 20000
npm config set fetch-retry-maxtimeout 120000
npm config set fetch-retries 5
npm config set fetch-timeout 300000
- name: 'Install dependencies'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
run: |-
npm ci --prefer-offline --no-audit --progress=false
- name: 'Run tests and generate reports'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
env:
NO_COLOR: true
run: 'npm run test:ci'
# Windows counterpart of test_macos (see that job's note). Runner is
# windows-2022; the check name keeps the windows-latest label so it matches
# the required-status-check context.
test_windows:
name: 'Test (windows-latest, Node 22.x)'
needs: 'classify_pr'
if: "${{ !cancelled() && github.event_name != 'pull_request' }}"
runs-on: 'windows-2022'
permissions:
contents: 'read'
steps:
- name: 'Checkout'
id: 'checkout'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: "${{ github.event.inputs.branch_ref || (github.event_name == 'pull_request' && format('refs/pull/{0}/head', github.event.pull_request.number)) || github.ref }}"
- name: 'Set up Node.js 22.x'
if: "${{ needs.classify_pr.outputs.skip_ci != 'true' }}"
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version: '22.x'
cache: 'npm'
cache-dependency-path: 'package-lock.json'
registry-url: 'https://registry.npmjs.org/'

View file

@ -47,7 +47,8 @@ describe('no-AK integration CI wiring', () => {
'utf8',
);
const ubuntuJob = getWorkflowJob(workflow, 'test');
const platformJob = getWorkflowJob(workflow, 'test_platforms');
const macosJob = getWorkflowJob(workflow, 'test_macos');
const windowsJob = getWorkflowJob(workflow, 'test_windows');
expect(workflow).not.toContain(' integration_no_ak:');
expect(workflow.split(`npm run ${NO_AK_SCRIPT}`).length - 1).toBe(1);
@ -59,7 +60,8 @@ describe('no-AK integration CI wiring', () => {
expect(ubuntuJob).not.toContain('secrets.OPENAI_BASE_URL');
expect(ubuntuJob).not.toContain('secrets.OPENAI_MODEL');
expect(platformJob).not.toContain(NO_AK_SCRIPT);
expect(macosJob).not.toContain(NO_AK_SCRIPT);
expect(windowsJob).not.toContain(NO_AK_SCRIPT);
});
it('checks out the immutable PR head ref instead of the lagging merge ref', () => {
@ -68,12 +70,13 @@ describe('no-AK integration CI wiring', () => {
'utf8',
);
const ubuntuJob = getWorkflowJob(workflow, 'test');
const platformJob = getWorkflowJob(workflow, 'test_platforms');
const macosJob = getWorkflowJob(workflow, 'test_macos');
const windowsJob = getWorkflowJob(workflow, 'test_windows');
// On PRs both gates check out refs/pull/N/head, which is published the
// On PRs every gate checks out refs/pull/N/head, which is published the
// instant the branch is pushed, instead of the merge ref that GitHub
// rebuilds asynchronously and can serve stale for minutes.
for (const job of [ubuntuJob, platformJob]) {
for (const job of [ubuntuJob, macosJob, windowsJob]) {
expect(job).toContain(
"format('refs/pull/{0}/head', github.event.pull_request.number)",
);