ci.yml 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. name: CI
  2. on:
  3. push:
  4. branches: [master]
  5. pull_request:
  6. workflow_dispatch:
  7. inputs:
  8. suite:
  9. description: Manual CI suite to run
  10. required: true
  11. default: larger-runner-benchmark
  12. type: choice
  13. options:
  14. - larger-runner-benchmark
  15. - consolidated-runner-benchmark
  16. concurrency:
  17. group: ${{ github.workflow }}-${{ github.ref }}
  18. cancel-in-progress: true
  19. permissions:
  20. contents: read
  21. env:
  22. PRIMARY_NODE_VERSION: '24'
  23. jobs:
  24. # One large runner pays hosted setup once, then the repository scheduler
  25. # overlaps the complete unsharded primary Node inventory. Build starts eagerly;
  26. # only consumers of emitted output wait for it.
  27. node-24:
  28. if: github.event_name == 'pull_request'
  29. runs-on: dsh-ubuntu-24-04-96core
  30. name: node 24 / complete
  31. env:
  32. DSH_COVERAGE_MAX_WORKERS: '16'
  33. DSH_ESLINT_CACHE: '1'
  34. DSH_ESLINT_CONCURRENCY: '16'
  35. DSH_GATE_CONCURRENCY: '10'
  36. DSH_PUBLINT_CONCURRENCY: '16'
  37. DSH_SNAPSHOT_MAX_CONCURRENCY: '8'
  38. steps:
  39. - uses: actions/checkout@v6
  40. with:
  41. persist-credentials: false
  42. # Pull requests consume the default-branch cache but do not put cache
  43. # compression and upload on the paid latency-critical path.
  44. - uses: actions/cache/restore@v4
  45. with:
  46. path: /home/runner/.local/share/pnpm/store/v11
  47. key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
  48. restore-keys: |
  49. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
  50. - uses: actions/cache/restore@v4
  51. with:
  52. path: .cache/eslint
  53. 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') }}
  54. restore-keys: |
  55. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
  56. - name: Select preinstalled Node, install dependencies, and prepare bubblewrap
  57. run: |
  58. node_root="$(printf '%s\n' "$RUNNER_TOOL_CACHE"/node/"${PRIMARY_NODE_VERSION}".*/x64 | sort -V | tail -n 1)"
  59. if [[ ! -d "$node_root" ]]; then
  60. echo "preinstalled Node ${PRIMARY_NODE_VERSION}.x not found in $RUNNER_TOOL_CACHE" >&2
  61. exit 1
  62. fi
  63. echo "$node_root/bin" >> "$GITHUB_PATH"
  64. export PATH="$node_root/bin:$PATH"
  65. [[ "$(node --version)" == "v${PRIMARY_NODE_VERSION}."* ]]
  66. corepack enable
  67. pnpm install --frozen-lockfile &
  68. install_pid=$!
  69. bash scripts/prepare-ci-bubblewrap.sh &
  70. sandbox_pid=$!
  71. install_status=0
  72. wait "$install_pid" || install_status=$?
  73. sandbox_status=0
  74. wait "$sandbox_pid" || sandbox_status=$?
  75. if (( install_status != 0 )); then exit "$install_status"; fi
  76. exit "$sandbox_status"
  77. - name: Run complete unsharded primary Node CI concurrently
  78. run: pnpm run check:ci
  79. node-compat:
  80. if: github.event_name == 'pull_request'
  81. # Distinct larger-runner pools avoid both standard-runner setup outliers and
  82. # delayed allocation when independent environment contracts share one pool.
  83. runs-on: ${{ matrix.runner }}
  84. name: ${{ matrix.name }}
  85. env:
  86. DSH_GATE_CONCURRENCY: ${{ matrix.gate_concurrency }}
  87. DSH_NODE_COMPAT_SKIP_TYPECHECK: '1'
  88. strategy:
  89. fail-fast: false
  90. matrix:
  91. include:
  92. - node: '22.19'
  93. name: node 22.19
  94. runner: dsh-ubuntu-24-04-4core
  95. gate_concurrency: '2'
  96. - node: 26
  97. name: node 26
  98. runner: dsh-ubuntu-24-04-32core
  99. gate_concurrency: '2'
  100. steps:
  101. - uses: actions/checkout@v6
  102. - uses: actions/setup-node@v6
  103. with:
  104. node-version: ${{ matrix.node }}
  105. - name: Enable corepack and resolve pnpm store path
  106. id: pnpm-store
  107. run: |
  108. corepack enable
  109. echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
  110. - uses: actions/cache@v4
  111. with:
  112. path: ${{ steps.pnpm-store.outputs.path }}
  113. key: ${{ runner.os }}-node-${{ matrix.node }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
  114. restore-keys: |
  115. ${{ runner.os }}-node-${{ matrix.node }}-pnpm-
  116. - name: Install (immutable)
  117. run: pnpm install --frozen-lockfile
  118. - name: Run compatibility smokes
  119. run: pnpm run check:node-compat
  120. python-sdk:
  121. if: github.event_name == 'pull_request'
  122. runs-on: dsh-ubuntu-24-04-8core
  123. name: python 3.10 / keyless SDK
  124. steps:
  125. - uses: actions/checkout@v6
  126. - uses: actions/setup-python@v6
  127. with:
  128. python-version: '3.10'
  129. cache: pip
  130. - name: Install uv
  131. run: python -m pip install uv==0.11.23
  132. - name: Run complete keyless Python suite
  133. run: uv run --python 3.10 --group test --project python/sdk pytest
  134. # One Windows box shares setup across the required build/site checks and the
  135. # complete observational portability inventory. run-gates reports failures
  136. # from observational gates without allowing them to fail the required job.
  137. windows:
  138. if: github.event_name == 'pull_request'
  139. runs-on: dsh-windows-2025-32core
  140. name: windows node 24 / complete
  141. env:
  142. # Keep ESLint itself single-threaded: 16 ESLint workers took 174 seconds on
  143. # this image. The outer scheduler still overlaps lint with the other gates.
  144. DSH_COVERAGE_MAX_WORKERS: '12'
  145. DSH_ESLINT_CACHE: '1'
  146. DSH_GATE_CONCURRENCY: '16'
  147. DSH_PUBLINT_CONCURRENCY: '16'
  148. steps:
  149. - uses: actions/checkout@v6
  150. - uses: actions/cache/restore@v4
  151. with:
  152. path: .cache/eslint
  153. 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') }}
  154. restore-keys: |
  155. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
  156. # Extracting the many-file pnpm store cache is slower on this image than
  157. # a clean parallel install, and saving it adds more latency after gates.
  158. - name: Select preinstalled Node and install (immutable)
  159. shell: pwsh
  160. run: |
  161. $nodeRoot = Get-ChildItem -Path "$env:RUNNER_TOOL_CACHE\node" -Directory |
  162. Where-Object { $_.Name -like "$env:PRIMARY_NODE_VERSION.*" } |
  163. Sort-Object { [version]$_.Name } |
  164. Select-Object -Last 1
  165. if ($null -eq $nodeRoot) {
  166. throw "preinstalled Node $env:PRIMARY_NODE_VERSION.x not found in $env:RUNNER_TOOL_CACHE"
  167. }
  168. $nodeBin = Join-Path $nodeRoot.FullName 'x64'
  169. if (-not (Test-Path $nodeBin -PathType Container)) {
  170. throw "preinstalled Node x64 directory not found at $nodeBin"
  171. }
  172. Add-Content -Path $env:GITHUB_PATH -Value $nodeBin
  173. $env:PATH = "$nodeBin;$env:PATH"
  174. if ((node --version) -notlike "v$env:PRIMARY_NODE_VERSION.*") {
  175. throw "selected unexpected Node version $(node --version)"
  176. }
  177. corepack enable
  178. pnpm install --frozen-lockfile
  179. - name: Run blocking and observational Windows gates concurrently
  180. shell: pwsh
  181. run: pnpm run check:ci:windows-complete
  182. # Master pushes run only the serial reference jobs below.
  183. # Each host executes the complete, unsharded primary Node aggregate with one
  184. # gate worker, giving reviewers a simple cross-platform oracle for completeness
  185. # and timing.
  186. serial-linux:
  187. if: github.event_name == 'push' && github.ref == 'refs/heads/master'
  188. name: serial / linux
  189. runs-on: ubuntu-latest
  190. steps:
  191. - uses: actions/checkout@v6
  192. - uses: actions/setup-node@v6
  193. with:
  194. node-version: ${{ env.PRIMARY_NODE_VERSION }}
  195. - name: Enable corepack and resolve pnpm store path
  196. id: pnpm-store
  197. run: |
  198. corepack enable
  199. echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
  200. # Master refreshes the caches that pull requests restore without saving.
  201. - uses: actions/cache@v4
  202. with:
  203. path: ${{ steps.pnpm-store.outputs.path }}
  204. key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
  205. restore-keys: |
  206. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
  207. - uses: actions/cache@v4
  208. with:
  209. path: .cache/eslint
  210. 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') }}
  211. restore-keys: |
  212. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
  213. - name: Install (immutable)
  214. run: pnpm install --frozen-lockfile
  215. - name: Prepare bubblewrap (unrestrict userns)
  216. run: bash scripts/prepare-ci-bubblewrap.sh
  217. - name: Run complete unsharded primary Node CI serially
  218. env:
  219. DSH_COVERAGE_MAX_WORKERS: '1'
  220. DSH_E2E_MAX_WORKERS: '1'
  221. DSH_ESLINT_CACHE: '1'
  222. DSH_GATE_CONCURRENCY: '1'
  223. DSH_PUBLINT_CONCURRENCY: '1'
  224. DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
  225. run: pnpm run check:ci
  226. serial-macos:
  227. if: github.event_name == 'push' && github.ref == 'refs/heads/master'
  228. name: serial / macos
  229. runs-on: macos-latest
  230. steps:
  231. - uses: actions/checkout@v6
  232. - uses: actions/setup-node@v6
  233. with:
  234. node-version: ${{ env.PRIMARY_NODE_VERSION }}
  235. - name: Enable corepack (pnpm)
  236. run: corepack enable
  237. - name: Install (immutable)
  238. run: pnpm install --frozen-lockfile
  239. - name: Run complete unsharded primary Node CI serially
  240. env:
  241. DSH_COVERAGE_MAX_WORKERS: '1'
  242. DSH_E2E_MAX_WORKERS: '1'
  243. DSH_GATE_CONCURRENCY: '1'
  244. DSH_PUBLINT_CONCURRENCY: '1'
  245. DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
  246. run: pnpm run check:ci
  247. serial-windows:
  248. if: github.event_name == 'push' && github.ref == 'refs/heads/master'
  249. name: serial / windows
  250. runs-on: windows-2025
  251. steps:
  252. - uses: actions/checkout@v6
  253. - name: Enable Developer Mode (symlink support)
  254. shell: pwsh
  255. run: >-
  256. reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
  257. /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
  258. - uses: actions/setup-node@v6
  259. with:
  260. node-version: ${{ env.PRIMARY_NODE_VERSION }}
  261. - name: Enable corepack (pnpm)
  262. shell: pwsh
  263. run: corepack enable
  264. # Master refreshes the small cache that pull requests restore without
  265. # putting package-store extraction back on the Windows critical path.
  266. - uses: actions/cache@v4
  267. with:
  268. path: .cache/eslint
  269. 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') }}
  270. restore-keys: |
  271. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
  272. - name: Install (immutable)
  273. shell: pwsh
  274. run: pnpm install --frozen-lockfile
  275. - name: Run complete unsharded primary Node CI serially
  276. shell: pwsh
  277. env:
  278. DSH_COVERAGE_MAX_WORKERS: '1'
  279. DSH_E2E_MAX_WORKERS: '1'
  280. DSH_ESLINT_CACHE: '1'
  281. DSH_GATE_CONCURRENCY: '1'
  282. DSH_PUBLINT_CONCURRENCY: '1'
  283. DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
  284. run: pnpm run check:ci
  285. # Manual, bounded comparison of the actual critical Linux and Windows lanes.
  286. # The named pools are restricted at the organization level to this repository.
  287. larger-runner-benchmark:
  288. if: github.event_name == 'workflow_dispatch' && inputs.suite == 'larger-runner-benchmark'
  289. runs-on: ${{ matrix.runner }}
  290. timeout-minutes: 15
  291. strategy:
  292. fail-fast: false
  293. max-parallel: 12
  294. matrix:
  295. include:
  296. - platform: linux
  297. cores: '4'
  298. runner: dsh-ubuntu-24-04-4core
  299. workload: typecheck
  300. - platform: linux
  301. cores: '8'
  302. runner: dsh-ubuntu-24-04-8core
  303. workload: typecheck
  304. - platform: linux
  305. cores: '16'
  306. runner: dsh-ubuntu-24-04-16core
  307. workload: typecheck
  308. - platform: linux
  309. cores: '32'
  310. runner: dsh-ubuntu-24-04-32core
  311. workload: typecheck
  312. - platform: linux
  313. cores: '64'
  314. runner: dsh-ubuntu-24-04-64core
  315. workload: typecheck
  316. - platform: linux
  317. cores: '96'
  318. runner: dsh-ubuntu-24-04-96core
  319. workload: typecheck
  320. - platform: windows
  321. cores: '4'
  322. runner: dsh-windows-2025-4core
  323. workload: production-site
  324. - platform: windows
  325. cores: '8'
  326. runner: dsh-windows-2025-8core
  327. workload: production-site
  328. - platform: windows
  329. cores: '16'
  330. runner: dsh-windows-2025-16core
  331. workload: production-site
  332. - platform: windows
  333. cores: '32'
  334. runner: dsh-windows-2025-32core
  335. workload: production-site
  336. - platform: windows
  337. cores: '64'
  338. runner: dsh-windows-2025-64core
  339. workload: production-site
  340. - platform: windows
  341. cores: '96'
  342. runner: dsh-windows-2025-96core
  343. workload: production-site
  344. steps:
  345. - uses: actions/checkout@v6
  346. - uses: actions/setup-node@v6
  347. with:
  348. node-version: ${{ env.PRIMARY_NODE_VERSION }}
  349. - name: Report runner capacity
  350. run: >-
  351. node -e "const os = require('node:os');
  352. console.log(JSON.stringify({ arch: process.arch, cpus: os.cpus().length,
  353. memoryGiB: Math.round(os.totalmem() / 2 ** 30) }))"
  354. - name: Enable corepack (pnpm)
  355. run: corepack enable
  356. - name: Resolve pnpm store path
  357. if: matrix.platform == 'linux'
  358. id: pnpm-store
  359. run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
  360. - uses: actions/cache@v4
  361. if: matrix.platform == 'linux'
  362. with:
  363. path: ${{ steps.pnpm-store.outputs.path }}
  364. key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
  365. restore-keys: |
  366. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
  367. - name: Install (immutable)
  368. run: pnpm install --frozen-lockfile
  369. - name: Run critical Linux typecheck lane
  370. if: matrix.platform == 'linux'
  371. run: pnpm run typecheck
  372. - name: Run critical Windows production-site lane
  373. if: matrix.platform == 'windows'
  374. run: pnpm run docs:build
  375. # Manual comparison of the intended low-fanout topology. Linux runs the
  376. # complete unsharded primary aggregate with bounded in-runner parallelism;
  377. # Windows runs both blocking build surfaces concurrently through run-gates.
  378. consolidated-runner-benchmark:
  379. if: github.event_name == 'workflow_dispatch' && inputs.suite == 'consolidated-runner-benchmark'
  380. runs-on: ${{ matrix.runner }}
  381. timeout-minutes: 15
  382. strategy:
  383. fail-fast: false
  384. max-parallel: 12
  385. matrix:
  386. include:
  387. - platform: linux
  388. cores: '4'
  389. runner: dsh-ubuntu-24-04-4core
  390. workers: '4'
  391. - platform: linux
  392. cores: '8'
  393. runner: dsh-ubuntu-24-04-8core
  394. workers: '8'
  395. - platform: linux
  396. cores: '16'
  397. runner: dsh-ubuntu-24-04-16core
  398. workers: '16'
  399. - platform: linux
  400. cores: '32'
  401. runner: dsh-ubuntu-24-04-32core
  402. workers: '32'
  403. - platform: linux
  404. cores: '64'
  405. runner: dsh-ubuntu-24-04-64core
  406. workers: '32'
  407. - platform: linux
  408. cores: '96'
  409. runner: dsh-ubuntu-24-04-96core
  410. workers: '32'
  411. - platform: windows
  412. cores: '4'
  413. runner: dsh-windows-2025-4core
  414. workers: '2'
  415. - platform: windows
  416. cores: '8'
  417. runner: dsh-windows-2025-8core
  418. workers: '2'
  419. - platform: windows
  420. cores: '16'
  421. runner: dsh-windows-2025-16core
  422. workers: '2'
  423. - platform: windows
  424. cores: '32'
  425. runner: dsh-windows-2025-32core
  426. workers: '2'
  427. - platform: windows
  428. cores: '64'
  429. runner: dsh-windows-2025-64core
  430. workers: '2'
  431. - platform: windows
  432. cores: '96'
  433. runner: dsh-windows-2025-96core
  434. workers: '2'
  435. steps:
  436. - uses: actions/checkout@v6
  437. - uses: actions/setup-node@v6
  438. with:
  439. node-version: ${{ env.PRIMARY_NODE_VERSION }}
  440. - name: Report runner capacity
  441. run: >-
  442. node -e "const os = require('node:os');
  443. console.log(JSON.stringify({ arch: process.arch, cpus: os.cpus().length,
  444. memoryGiB: Math.round(os.totalmem() / 2 ** 30) }))"
  445. - name: Enable corepack (pnpm)
  446. run: corepack enable
  447. - name: Resolve pnpm store path (Linux)
  448. if: matrix.platform == 'linux'
  449. id: pnpm-store-linux
  450. run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
  451. - name: Resolve pnpm store path (Windows)
  452. if: matrix.platform == 'windows'
  453. id: pnpm-store-windows
  454. shell: pwsh
  455. run: '"path=$(pnpm store path --silent)" >> $env:GITHUB_OUTPUT'
  456. - uses: actions/cache@v4
  457. with:
  458. path: ${{ steps.pnpm-store-linux.outputs.path || steps.pnpm-store-windows.outputs.path }}
  459. key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
  460. restore-keys: |
  461. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
  462. - uses: actions/cache@v4
  463. if: matrix.platform == 'linux'
  464. with:
  465. path: .cache/eslint
  466. 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') }}
  467. restore-keys: |
  468. ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
  469. - name: Install and prepare Linux
  470. if: matrix.platform == 'linux'
  471. run: |
  472. pnpm install --frozen-lockfile &
  473. install_pid=$!
  474. bash scripts/prepare-ci-bubblewrap.sh &
  475. sandbox_pid=$!
  476. install_status=0
  477. wait "$install_pid" || install_status=$?
  478. sandbox_status=0
  479. wait "$sandbox_pid" || sandbox_status=$?
  480. if (( install_status != 0 )); then exit "$install_status"; fi
  481. exit "$sandbox_status"
  482. - name: Install (immutable)
  483. if: matrix.platform == 'windows'
  484. shell: pwsh
  485. run: pnpm install --frozen-lockfile
  486. - name: Run complete unsharded primary Node CI concurrently
  487. if: matrix.platform == 'linux'
  488. env:
  489. DSH_COVERAGE_MAX_WORKERS: ${{ matrix.workers }}
  490. DSH_ESLINT_CACHE: '1'
  491. DSH_ESLINT_CONCURRENCY: ${{ matrix.workers }}
  492. DSH_GATE_CONCURRENCY: ${{ matrix.workers }}
  493. DSH_PUBLINT_CONCURRENCY: ${{ matrix.workers }}
  494. DSH_SNAPSHOT_MAX_CONCURRENCY: ${{ matrix.workers }}
  495. run: pnpm run check:ci
  496. - name: Run blocking Windows builds concurrently
  497. if: matrix.platform == 'windows'
  498. shell: pwsh
  499. env:
  500. DSH_GATE_CONCURRENCY: ${{ matrix.workers }}
  501. run: pnpm run check:ci:windows-blocking
  502. # Single stable required check for branch protection: require "all checks
  503. # passed" instead of enumerating matrix legs whose names change as lanes and
  504. # node versions evolve. Every blocking job in THIS workflow must be listed in
  505. # `needs`; observational Windows gates share the required Windows job but are
  506. # marked non-blocking inside run-gates. (`needs` cannot reach across workflow
  507. # files; e2e.yml stays its own check.)
  508. # `if: always()` is load-bearing: without it a failed dependency
  509. # would SKIP this job, and GitHub counts a skipped required check as passing
  510. # — so this job always runs and fails on any non-success result, including
  511. # 'cancelled' and 'skipped'.
  512. all-checks-passed:
  513. name: all checks passed
  514. runs-on: ubuntu-latest
  515. needs: [node-24, node-compat, python-sdk, windows]
  516. if: always() && github.event_name == 'pull_request'
  517. steps:
  518. - name: Fail if any needed job did not succeed
  519. if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')
  520. run: |
  521. echo "::error::Needed job results: ${{ join(needs.*.result, ', ') }}"
  522. exit 1
  523. - name: All checks passed
  524. run: echo "All needed jobs succeeded (${{ join(needs.*.result, ', ') }})"