From bc586362dc4dd1dd1234caa2466904e1ee40f710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E8=89=AF?= <1204183885@qq.com> Date: Wed, 24 Jun 2026 23:58:15 +0800 Subject: [PATCH] ci: split platform test matrix into named jobs so PRs can enter the merge queue (#5833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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. --- .github/workflows/ci.yml | 81 ++++++++++++++++------ scripts/tests/no-ak-integration-ci.test.js | 13 ++-- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8dbfc0920..4b00297cf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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/' diff --git a/scripts/tests/no-ak-integration-ci.test.js b/scripts/tests/no-ak-integration-ci.test.js index 0f0957cab9..71f3190854 100644 --- a/scripts/tests/no-ak-integration-ci.test.js +++ b/scripts/tests/no-ak-integration-ci.test.js @@ -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)", );