The failover runbook landed as .agents/notes/implemented/process/ci-failover-runbook.md, which fails three doc-sync gates: the classification/format gates require a yyyy-mm-dd-topic.md filename and the implemented Agent Note skeleton (Problem/Decision/Alternatives/Consequences), and the bilingual pairing gate requires cross-note link targets to match between the two language sides. Rename to 2026-07-26-ci-failover-runbook.md/.zh.md, reshape both sides into the implemented skeleton (the runbook steps live in bespoke sections under Decision), point the sibling topology note and the ci.yml comment at the dated filename, and make both sides link the canonical .md per the bilingual convention. Re-recorded the i18n pairing records.
769 lines
28 KiB
YAML
769 lines
28 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [master]
|
|
pull_request:
|
|
workflow_dispatch:
|
|
inputs:
|
|
suite:
|
|
description: Manual CI suite to run
|
|
required: true
|
|
default: larger-runner-benchmark
|
|
type: choice
|
|
options:
|
|
- larger-runner-benchmark
|
|
- consolidated-runner-benchmark
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
PRIMARY_NODE_VERSION: '24'
|
|
|
|
jobs:
|
|
|
|
# Three enterprise jobs isolate coverage, static analysis, and the
|
|
# build-backed consumer tail. The static job publishes its exact build so
|
|
# consumers do not repeat the longest part of their critical path.
|
|
#
|
|
# FAILOVER: each Linux enterprise job resolves its pool through the
|
|
# DSH_CI_FAILOVER repository variable. Unset (normal), the expressions
|
|
# pick the hosted enterprise pools below. Setting the variable to
|
|
# 'selfhosted' (repo Settings → Actions → Variables; admin-only, not
|
|
# PR-editable, no merge required) retargets all three onto the in-house
|
|
# vm-backup pool and re-running the failed jobs is the entire switch —
|
|
# see .agents/notes/implemented/process/2026-07-26-ci-failover-runbook.md. The
|
|
# in-house pool's readiness is re-proven on every master push by the
|
|
# serial-linux-selfhosted standby lane below.
|
|
node-24:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER == 'selfhosted'
|
|
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|
|
|| 'dsh-enterprise-ubuntu-latest-32core-test' }}
|
|
name: node 24 / static
|
|
env:
|
|
DSH_GATE_CONCURRENCY: '8'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# Pull requests consume the default-branch cache but do not put cache
|
|
# compression and upload on the paid latency-critical path.
|
|
- uses: actions/cache/restore@v4
|
|
with:
|
|
path: /home/runner/.local/share/pnpm/store/v11
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Enable corepack and install dependencies
|
|
run: |
|
|
corepack enable
|
|
pnpm install --frozen-lockfile
|
|
|
|
- name: Run static gates
|
|
run: pnpm run check:ci:static
|
|
|
|
- name: Pack built tree
|
|
run: >-
|
|
tar -czf "$RUNNER_TEMP/node-24-built-tree.tar.gz"
|
|
apps/*/lib packages/*/*/lib vendor/*/lib
|
|
|
|
- uses: actions/upload-artifact@v6
|
|
with:
|
|
name: node-24-built-tree
|
|
path: ${{ runner.temp }}/node-24-built-tree.tar.gz
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
compression-level: 0
|
|
|
|
node-24-coverage:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER == 'selfhosted'
|
|
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|
|
|| 'dsh-enterprise-ubuntu-24-04-32core-test' }}
|
|
name: node 24 / coverage
|
|
env:
|
|
# Failover halves the worker bound: the hosted 32-core runner is
|
|
# exclusive to one job, but the failover pool shares one 64-core VM
|
|
# across four runner instances, and the timing-sensitive process
|
|
# suites have documented aggregate-contention failures.
|
|
DSH_COVERAGE_MAX_WORKERS: ${{ vars.DSH_CI_FAILOVER == 'selfhosted' && '12' || '24' }}
|
|
DSH_GATE_CONCURRENCY: '8'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# Skipped under failover: the self-hosted VM's persistent pnpm store
|
|
# serves warm installs directly, and this hosted-path restore would
|
|
# spend ~52 s pulling ~180 MB into a path pnpm never reads there.
|
|
- uses: actions/cache/restore@v4
|
|
if: vars.DSH_CI_FAILOVER != 'selfhosted'
|
|
with:
|
|
path: /home/runner/.local/share/pnpm/store/v11
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Enable corepack, install dependencies, and prepare bubblewrap
|
|
run: |
|
|
corepack enable
|
|
pnpm install --frozen-lockfile &
|
|
install_pid=$!
|
|
bash scripts/prepare-ci-bubblewrap.sh &
|
|
sandbox_pid=$!
|
|
install_status=0
|
|
wait "$install_pid" || install_status=$?
|
|
sandbox_status=0
|
|
wait "$sandbox_pid" || sandbox_status=$?
|
|
if (( install_status != 0 )); then exit "$install_status"; fi
|
|
exit "$sandbox_status"
|
|
|
|
- name: Run exhaustive coverage
|
|
run: pnpm run check:ci:coverage
|
|
|
|
node-24-consumers:
|
|
needs: node-24
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER == 'selfhosted'
|
|
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|
|
|| 'dsh-enterprise-ubuntu-latest-32core-test' }}
|
|
name: node 24 / snapshots and artifacts
|
|
env:
|
|
DSH_ESLINT_CACHE: '1'
|
|
DSH_ESLINT_CONCURRENCY: '8'
|
|
DSH_GATE_CONCURRENCY: '8'
|
|
DSH_NODE_COMPAT_SKIP_TYPECHECK: '1'
|
|
DSH_PUBLINT_CONCURRENCY: '8'
|
|
# Failover halves snapshot concurrency for the shared 64-core VM.
|
|
DSH_SNAPSHOT_MAX_CONCURRENCY: ${{ vars.DSH_CI_FAILOVER == 'selfhosted' && '16' || '32' }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: node-24-built-tree
|
|
path: ${{ runner.temp }}
|
|
|
|
- name: Restore built tree
|
|
run: tar -xzf "$RUNNER_TEMP/node-24-built-tree.tar.gz"
|
|
|
|
# Skipped under failover — see the coverage lane's identical rationale.
|
|
- uses: actions/cache/restore@v4
|
|
if: vars.DSH_CI_FAILOVER != 'selfhosted'
|
|
with:
|
|
path: /home/runner/.local/share/pnpm/store/v11
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
|
|
|
|
- uses: actions/cache/restore@v4
|
|
with:
|
|
path: .cache/eslint
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Enable corepack, install dependencies, and prepare bubblewrap
|
|
run: |
|
|
corepack enable
|
|
pnpm install --frozen-lockfile &
|
|
install_pid=$!
|
|
bash scripts/prepare-ci-bubblewrap.sh &
|
|
sandbox_pid=$!
|
|
install_status=0
|
|
wait "$install_pid" || install_status=$?
|
|
sandbox_status=0
|
|
wait "$sandbox_pid" || sandbox_status=$?
|
|
if (( install_status != 0 )); then exit "$install_status"; fi
|
|
exit "$sandbox_status"
|
|
|
|
- name: Run compatibility, snapshot, and artifact gates
|
|
run: |
|
|
pnpm run check:ci:lint &
|
|
lint_pid=$!
|
|
pnpm run check:node-compat &
|
|
compat_pid=$!
|
|
DSH_EXAMPLE_MODE=lib pnpm run test:snapshot &
|
|
snapshot_pid=$!
|
|
pnpm run publint &
|
|
publint_pid=$!
|
|
pnpm run verify-node-next-types &
|
|
node_next_pid=$!
|
|
pnpm run verify-built-package-invariants &
|
|
built_invariants_pid=$!
|
|
DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts \
|
|
examples/headless-agent/tests/keyless-smoke.e2e.ts \
|
|
examples/tui-agent/tests/tui-keyless-smoke.e2e.ts \
|
|
packages/examples/cli-demo/tests/built-bin.e2e.ts \
|
|
packages/examples/acp-demo/tests/built-bin.e2e.ts \
|
|
packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts \
|
|
packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts \
|
|
packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts &
|
|
built_bin_pid=$!
|
|
|
|
final_status=0
|
|
capture_status() {
|
|
local child_status=0
|
|
wait "$1" || child_status=$?
|
|
if (( final_status == 0 && child_status != 0 )); then
|
|
final_status=$child_status
|
|
fi
|
|
}
|
|
for child_pid in \
|
|
"$lint_pid" "$compat_pid" "$snapshot_pid" \
|
|
"$publint_pid" "$node_next_pid" "$built_invariants_pid" "$built_bin_pid"
|
|
do
|
|
capture_status "$child_pid"
|
|
done
|
|
exit "$final_status"
|
|
|
|
|
|
node-compat:
|
|
if: github.event_name == 'pull_request'
|
|
# Each compatibility contract receives an independent standard hosted job.
|
|
runs-on: ${{ matrix.runner }}
|
|
name: ${{ matrix.name }}
|
|
env:
|
|
DSH_GATE_CONCURRENCY: ${{ matrix.gate_concurrency }}
|
|
DSH_NODE_COMPAT_SKIP_TYPECHECK: '1'
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- node: '22.19'
|
|
name: node 22.19
|
|
runner: ubuntu-latest
|
|
gate_concurrency: '1'
|
|
- node: 26
|
|
name: node 26
|
|
runner: ubuntu-latest
|
|
gate_concurrency: '1'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ matrix.node }}
|
|
|
|
- name: Enable corepack and resolve pnpm store path
|
|
id: pnpm-store
|
|
run: |
|
|
corepack enable
|
|
echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
|
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: ${{ steps.pnpm-store.outputs.path }}
|
|
key: ${{ runner.os }}-node-${{ matrix.node }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ matrix.node }}-pnpm-
|
|
|
|
- name: Install (immutable)
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run compatibility smokes
|
|
run: pnpm run check:node-compat
|
|
|
|
python-sdk:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
name: python 3.10 / keyless SDK
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-python@v6
|
|
with:
|
|
python-version: '3.10'
|
|
cache: pip
|
|
|
|
- name: Install uv
|
|
run: python -m pip install uv==0.11.23
|
|
|
|
- name: Run complete keyless Python suite
|
|
run: uv run --python 3.10 --group test --project python/sdk pytest
|
|
|
|
# One Windows box shares setup across the required build/site checks and the
|
|
# observational portability inventory. Linux owns duplicate lint, coverage,
|
|
# and snapshots so they do not dominate the paid Windows critical path.
|
|
windows:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: dsh-enterprise-windows-2025-32core-test
|
|
name: windows node 24 / complete
|
|
env:
|
|
DSH_COVERAGE_MAX_WORKERS: '12'
|
|
DSH_GATE_CONCURRENCY: '16'
|
|
DSH_PUBLINT_CONCURRENCY: '16'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Enable Developer Mode (symlink support)
|
|
shell: pwsh
|
|
run: >-
|
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
|
|
/t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
# Extracting the many-file pnpm store cache is slower than a clean install,
|
|
# and saving it adds more latency after gates.
|
|
- name: Enable corepack and install (immutable)
|
|
shell: pwsh
|
|
run: |
|
|
corepack enable
|
|
pnpm install --frozen-lockfile
|
|
|
|
- name: Run blocking and observational Windows gates concurrently
|
|
shell: pwsh
|
|
run: pnpm run check:ci:windows-complete
|
|
|
|
# Master pushes run only the serial reference jobs below.
|
|
# Each host executes the complete, unsharded primary Node aggregate with one
|
|
# gate worker, giving reviewers a simple cross-platform oracle for completeness
|
|
# and timing.
|
|
serial-linux:
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
|
name: serial / linux
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Enable corepack and resolve pnpm store path
|
|
id: pnpm-store
|
|
run: |
|
|
corepack enable
|
|
echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
|
|
|
# Master refreshes the caches that pull requests restore without saving.
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: ${{ steps.pnpm-store.outputs.path }}
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
|
|
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: .cache/eslint
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
|
|
|
- name: Install (immutable)
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Prepare bubblewrap (unrestrict userns)
|
|
run: bash scripts/prepare-ci-bubblewrap.sh
|
|
|
|
- name: Run complete unsharded primary Node CI serially
|
|
env:
|
|
DSH_COVERAGE_MAX_WORKERS: '1'
|
|
DSH_E2E_MAX_WORKERS: '1'
|
|
DSH_ESLINT_CACHE: '1'
|
|
DSH_GATE_CONCURRENCY: '1'
|
|
DSH_PUBLINT_CONCURRENCY: '1'
|
|
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
|
|
run: pnpm run check:ci
|
|
|
|
# Hot-standby drill for the in-house self-hosted pool: every master move
|
|
# re-runs the complete unsharded aggregate on the persistent 64-core VM,
|
|
# continuously proving that environment can take over a required lane if
|
|
# the hosted pools degrade (the switch is then a one-line runs-on change).
|
|
# Push-triggered, so it always executes the base branch's own workflow
|
|
# definition — no PR-editable path selects these runners. Non-blocking for
|
|
# pull requests; no cache steps because the VM's persistent pnpm store and
|
|
# tool caches make them redundant (and saving here would poison the hosted
|
|
# cache namespace with self-hosted paths).
|
|
serial-linux-selfhosted:
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
|
name: serial / linux (self-hosted standby)
|
|
runs-on: [self-hosted, linux, x64, vm-backup]
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Enable corepack (pnpm)
|
|
run: corepack enable
|
|
|
|
- name: Install (immutable)
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Prepare bubblewrap (unrestrict userns)
|
|
run: bash scripts/prepare-ci-bubblewrap.sh
|
|
|
|
- name: Run complete unsharded primary Node CI serially
|
|
env:
|
|
DSH_COVERAGE_MAX_WORKERS: '1'
|
|
DSH_E2E_MAX_WORKERS: '1'
|
|
DSH_ESLINT_CACHE: '1'
|
|
DSH_GATE_CONCURRENCY: '1'
|
|
DSH_PUBLINT_CONCURRENCY: '1'
|
|
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
|
|
run: pnpm run check:ci
|
|
|
|
serial-macos:
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
|
name: serial / macos
|
|
runs-on: macos-latest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Enable corepack (pnpm)
|
|
run: corepack enable
|
|
|
|
- name: Install (immutable)
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run complete unsharded primary Node CI serially
|
|
env:
|
|
DSH_COVERAGE_MAX_WORKERS: '1'
|
|
DSH_E2E_MAX_WORKERS: '1'
|
|
DSH_GATE_CONCURRENCY: '1'
|
|
DSH_PUBLINT_CONCURRENCY: '1'
|
|
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
|
|
run: pnpm run check:ci
|
|
|
|
serial-windows:
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
|
name: serial / windows
|
|
runs-on: windows-2025
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Enable Developer Mode (symlink support)
|
|
shell: pwsh
|
|
run: >-
|
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
|
|
/t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Enable corepack (pnpm)
|
|
shell: pwsh
|
|
run: corepack enable
|
|
|
|
# Master refreshes the small cache that pull requests restore without
|
|
# putting package-store extraction back on the Windows critical path.
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: .cache/eslint
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
|
|
|
- name: Install (immutable)
|
|
shell: pwsh
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run complete unsharded primary Node CI serially
|
|
shell: pwsh
|
|
env:
|
|
DSH_COVERAGE_MAX_WORKERS: '1'
|
|
DSH_E2E_MAX_WORKERS: '1'
|
|
DSH_ESLINT_CACHE: '1'
|
|
DSH_GATE_CONCURRENCY: '1'
|
|
DSH_PUBLINT_CONCURRENCY: '1'
|
|
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
|
|
run: pnpm run check:ci
|
|
|
|
# Manual, bounded comparison of the actual critical Linux and Windows lanes.
|
|
# The named pools are restricted at the organization level to this repository.
|
|
larger-runner-benchmark:
|
|
if: github.event_name == 'workflow_dispatch' && inputs.suite == 'larger-runner-benchmark'
|
|
runs-on: ${{ matrix.runner }}
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
max-parallel: 12
|
|
matrix:
|
|
include:
|
|
- platform: linux
|
|
cores: '4'
|
|
runner: dsh-ubuntu-24-04-4core
|
|
workload: typecheck
|
|
- platform: linux
|
|
cores: '8'
|
|
runner: dsh-ubuntu-24-04-8core
|
|
workload: typecheck
|
|
- platform: linux
|
|
cores: '16'
|
|
runner: dsh-ubuntu-24-04-16core
|
|
workload: typecheck
|
|
- platform: linux
|
|
cores: '32'
|
|
runner: dsh-ubuntu-24-04-32core
|
|
workload: typecheck
|
|
- platform: linux
|
|
cores: '64'
|
|
runner: dsh-ubuntu-24-04-64core
|
|
workload: typecheck
|
|
- platform: linux
|
|
cores: '96'
|
|
runner: dsh-ubuntu-24-04-96core
|
|
workload: typecheck
|
|
- platform: windows
|
|
cores: '4'
|
|
runner: dsh-windows-2025-4core
|
|
workload: production-site
|
|
- platform: windows
|
|
cores: '8'
|
|
runner: dsh-windows-2025-8core
|
|
workload: production-site
|
|
- platform: windows
|
|
cores: '16'
|
|
runner: dsh-windows-2025-16core
|
|
workload: production-site
|
|
- platform: windows
|
|
cores: '32'
|
|
runner: dsh-windows-2025-32core
|
|
workload: production-site
|
|
- platform: windows
|
|
cores: '64'
|
|
runner: dsh-windows-2025-64core
|
|
workload: production-site
|
|
- platform: windows
|
|
cores: '96'
|
|
runner: dsh-windows-2025-96core
|
|
workload: production-site
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Report runner capacity
|
|
run: >-
|
|
node -e "const os = require('node:os');
|
|
console.log(JSON.stringify({ arch: process.arch, cpus: os.cpus().length,
|
|
memoryGiB: Math.round(os.totalmem() / 2 ** 30) }))"
|
|
|
|
- name: Enable corepack (pnpm)
|
|
run: corepack enable
|
|
|
|
- name: Resolve pnpm store path
|
|
if: matrix.platform == 'linux'
|
|
id: pnpm-store
|
|
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
|
|
|
- uses: actions/cache@v4
|
|
if: matrix.platform == 'linux'
|
|
with:
|
|
path: ${{ steps.pnpm-store.outputs.path }}
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
|
|
|
|
- name: Install (immutable)
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run critical Linux typecheck lane
|
|
if: matrix.platform == 'linux'
|
|
run: pnpm run typecheck
|
|
|
|
- name: Run critical Windows production-site lane
|
|
if: matrix.platform == 'windows'
|
|
run: pnpm run docs:build
|
|
|
|
# Manual comparison of the intended low-fanout topology. Linux runs the
|
|
# complete unsharded primary aggregate with bounded in-runner parallelism;
|
|
# Windows runs both blocking build surfaces concurrently through run-gates.
|
|
consolidated-runner-benchmark:
|
|
if: github.event_name == 'workflow_dispatch' && inputs.suite == 'consolidated-runner-benchmark'
|
|
runs-on: ${{ matrix.runner }}
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
max-parallel: 12
|
|
matrix:
|
|
include:
|
|
- platform: linux
|
|
cores: '4'
|
|
runner: dsh-ubuntu-24-04-4core
|
|
workers: '4'
|
|
- platform: linux
|
|
cores: '8'
|
|
runner: dsh-ubuntu-24-04-8core
|
|
workers: '8'
|
|
- platform: linux
|
|
cores: '16'
|
|
runner: dsh-ubuntu-24-04-16core
|
|
workers: '16'
|
|
- platform: linux
|
|
cores: '32'
|
|
runner: dsh-ubuntu-24-04-32core
|
|
workers: '32'
|
|
- platform: linux
|
|
cores: '64'
|
|
runner: dsh-ubuntu-24-04-64core
|
|
workers: '32'
|
|
- platform: linux
|
|
cores: '96'
|
|
runner: dsh-ubuntu-24-04-96core
|
|
workers: '32'
|
|
- platform: windows
|
|
cores: '4'
|
|
runner: dsh-windows-2025-4core
|
|
workers: '2'
|
|
- platform: windows
|
|
cores: '8'
|
|
runner: dsh-windows-2025-8core
|
|
workers: '2'
|
|
- platform: windows
|
|
cores: '16'
|
|
runner: dsh-windows-2025-16core
|
|
workers: '2'
|
|
- platform: windows
|
|
cores: '32'
|
|
runner: dsh-windows-2025-32core
|
|
workers: '2'
|
|
- platform: windows
|
|
cores: '64'
|
|
runner: dsh-windows-2025-64core
|
|
workers: '2'
|
|
- platform: windows
|
|
cores: '96'
|
|
runner: dsh-windows-2025-96core
|
|
workers: '2'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Report runner capacity
|
|
run: >-
|
|
node -e "const os = require('node:os');
|
|
console.log(JSON.stringify({ arch: process.arch, cpus: os.cpus().length,
|
|
memoryGiB: Math.round(os.totalmem() / 2 ** 30) }))"
|
|
|
|
- name: Enable corepack (pnpm)
|
|
run: corepack enable
|
|
|
|
- name: Resolve pnpm store path (Linux)
|
|
if: matrix.platform == 'linux'
|
|
id: pnpm-store-linux
|
|
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Resolve pnpm store path (Windows)
|
|
if: matrix.platform == 'windows'
|
|
id: pnpm-store-windows
|
|
shell: pwsh
|
|
run: '"path=$(pnpm store path --silent)" >> $env:GITHUB_OUTPUT'
|
|
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: ${{ steps.pnpm-store-linux.outputs.path || steps.pnpm-store-windows.outputs.path }}
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
|
|
|
|
- uses: actions/cache@v4
|
|
if: matrix.platform == 'linux'
|
|
with:
|
|
path: .cache/eslint
|
|
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
|
|
|
- name: Install and prepare Linux
|
|
if: matrix.platform == 'linux'
|
|
run: |
|
|
pnpm install --frozen-lockfile &
|
|
install_pid=$!
|
|
bash scripts/prepare-ci-bubblewrap.sh &
|
|
sandbox_pid=$!
|
|
install_status=0
|
|
wait "$install_pid" || install_status=$?
|
|
sandbox_status=0
|
|
wait "$sandbox_pid" || sandbox_status=$?
|
|
if (( install_status != 0 )); then exit "$install_status"; fi
|
|
exit "$sandbox_status"
|
|
|
|
- name: Install (immutable)
|
|
if: matrix.platform == 'windows'
|
|
shell: pwsh
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run complete unsharded primary Node CI concurrently
|
|
if: matrix.platform == 'linux'
|
|
env:
|
|
DSH_COVERAGE_MAX_WORKERS: ${{ matrix.workers }}
|
|
DSH_ESLINT_CACHE: '1'
|
|
DSH_ESLINT_CONCURRENCY: ${{ matrix.workers }}
|
|
DSH_GATE_CONCURRENCY: ${{ matrix.workers }}
|
|
DSH_PUBLINT_CONCURRENCY: ${{ matrix.workers }}
|
|
DSH_SNAPSHOT_MAX_CONCURRENCY: ${{ matrix.workers }}
|
|
run: pnpm run check:ci
|
|
|
|
- name: Run blocking Windows builds concurrently
|
|
if: matrix.platform == 'windows'
|
|
shell: pwsh
|
|
env:
|
|
DSH_GATE_CONCURRENCY: ${{ matrix.workers }}
|
|
run: pnpm run check:ci:windows-blocking
|
|
|
|
# Single stable required check for branch protection: require "all checks
|
|
# passed" instead of enumerating matrix legs whose names change as lanes and
|
|
# node versions evolve. Every blocking job in THIS workflow must be listed in
|
|
# `needs`; observational Windows gates share the required Windows job but are
|
|
# marked non-blocking inside run-gates. (`needs` cannot reach across workflow
|
|
# files; e2e.yml stays its own check.)
|
|
# `if: always()` is load-bearing: without it a failed dependency
|
|
# would SKIP this job, and GitHub counts a skipped required check as passing
|
|
# — so this job always runs and fails on any non-success result, including
|
|
# 'cancelled' and 'skipped'.
|
|
all-checks-passed:
|
|
name: all checks passed
|
|
runs-on: ubuntu-latest
|
|
needs: [node-24, node-24-coverage, node-24-consumers, node-compat, python-sdk, windows]
|
|
if: always() && github.event_name == 'pull_request'
|
|
steps:
|
|
- name: Fail if any needed job did not succeed
|
|
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')
|
|
run: |
|
|
echo "::error::Needed job results: ${{ join(needs.*.result, ', ') }}"
|
|
exit 1
|
|
- name: All checks passed
|
|
run: echo "All needed jobs succeeded (${{ join(needs.*.result, ', ') }})"
|