mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
* test(python): exercise installed wheels as black boxes Add an installed-wheel mode that refuses source/editable imports, repository working directories, mismatched SDK/runtime versions, unpinned runtime dependencies, and executables outside the installed runtime distribution. The mode resolves the wheel-owned executable itself, so callers cannot accidentally prove an explicit checkout artifact. Add a real-API scenario that drives two tool-using turns through the public synchronous SDK, verifies the file bytes outside the agent, checks completed turn/tool events and persistence, and projects provider failures without retaining credential-bearing error text. The existing deterministic scenario set remains the keyless behavior oracle. Refs #2952. * ci(python): require installed-wheel checks on every release target Move the complete deterministic runtime scenarios behind construction and clean installation of the SDK and matching runtime wheels. Each native leg runs outside the checkout with source-resolution environment variables removed; Linux manylinux smokes assert the same installed provenance. Expand the required pull-request call from Linux x64 to Linux x64, Linux arm64, and macOS arm64. Trusted heads receive only DEEPSEEK_API_KEY_EXTERNAL for a fail-loud live two-turn smoke on each carrier, while fork and Dependabot heads retain the full keyless path without exposing secrets. Pin the reusable secret declaration, matrix call, aggregate dependency, untrusted-head condition, and live/keyless commands in the workflow contract test. Refs #2952. * docs(testing): make installed wheels the Python CI authority Record the clean-wheel provenance boundary, complete keyless scenario set, trusted real-API contract, secret handling, and three-target required topology in a new implemented testing decision. Update the SEA distribution and portable-CI authorities plus the Python contributor reference to describe the same current state. Archive the fully superseded Linux-x64-only decision after consolidating its rationale and alternatives into the new owner. Preserve its bilingual triplet as a sealed historical snapshot and redirect every active current-state reference. Refs #2952.
496 lines
21 KiB
YAML
496 lines
21 KiB
YAML
name: CI
|
|
|
|
on:
|
|
pull_request:
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
PRIMARY_NODE_VERSION: '24'
|
|
# CI runs must never report to the production telemetry endpoint baked
|
|
# into apps/cli/cordis.yml (AppCLIEntry disables the row when set).
|
|
DSH_TELEMETRY_DISABLED: '1'
|
|
|
|
# Cancel a superseded pull-request run on a new push so a fresh head does not
|
|
# queue a second full 9-job run behind a stale one (paid enterprise runners
|
|
# would otherwise stack with no auto-cancellation).
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
|
|
# Three enterprise jobs isolate coverage, static analysis, and the
|
|
# build-backed consumer tail. The consumer job owns the only Linux build so
|
|
# all three jobs enter runner allocation independently.
|
|
#
|
|
# FAILOVER (Linux): each Linux enterprise job resolves its pool through the
|
|
# DSH_CI_FAILOVER_LINUX repository variable. Unset (normal), the expressions
|
|
# pick the hosted enterprise pools below. Setting the variable to
|
|
# 'selfhosted' (repo Settings → Actions → Variables; writer-manageable
|
|
# repository state — 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 in ci-master.yml. The Windows failover
|
|
# switch is the separate DSH_CI_FAILOVER_WINDOWS variable on the windows-native
|
|
# job below.
|
|
node-24:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER_LINUX == 'selfhosted'
|
|
&& github.event.pull_request.user.login != 'dependabot[bot]'
|
|
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|
|
|| 'dsh-ubuntu-24-04-16core' }}
|
|
name: node 24 / static
|
|
env:
|
|
DSH_GATE_CONCURRENCY: '8'
|
|
steps:
|
|
# Fetch complete history so the archive gate can read the trusted PR base from a reused shallow checkout.
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
dest: ${{ runner.temp }}/setup-pnpm
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Configure pnpm store path
|
|
id: pnpm-store
|
|
run: |
|
|
store_root="$HOME/.local/share/pnpm/store"
|
|
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
|
|
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
|
|
echo "path=$store_path" >> "$GITHUB_OUTPUT"
|
|
|
|
# Pull requests consume the default-branch cache but do not put cache
|
|
# compression and upload on the paid latency-critical path. Skipped
|
|
# under failover — see the coverage lane's identical rationale.
|
|
- uses: actions/cache/restore@v4
|
|
if: vars.DSH_CI_FAILOVER_LINUX != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
|
|
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 static gates
|
|
env:
|
|
DSH_ARCHIVE_BASE_REF: ${{ github.event.pull_request.base.sha }}
|
|
run: pnpm run check:ci:static
|
|
|
|
node-24-coverage:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER_LINUX == 'selfhosted'
|
|
&& github.event.pull_request.user.login != 'dependabot[bot]'
|
|
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|
|
|| 'dsh-ubuntu-24-04-16core' }}
|
|
name: node 24 / coverage
|
|
env:
|
|
# Partitioning replaces the instrumented share; this budget gives the
|
|
# exempt-heavy gate two workers on both hosted and failover runners.
|
|
DSH_COVERAGE_MAX_WORKERS: '6'
|
|
DSH_COVERAGE_PARTITIONS: '4'
|
|
DSH_GATE_CONCURRENCY: '3'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
dest: ${{ runner.temp }}/setup-pnpm
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Configure pnpm store path
|
|
id: pnpm-store
|
|
run: |
|
|
store_root="$HOME/.local/share/pnpm/store"
|
|
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
|
|
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
|
|
echo "path=$store_path" >> "$GITHUB_OUTPUT"
|
|
|
|
# Skipped under failover: the self-hosted VM's persistent pnpm store
|
|
# already serves warm installs, while restoring the hosted archive
|
|
# would spend ~52 s pulling ~180 MB into that populated store.
|
|
- uses: actions/cache/restore@v4
|
|
if: vars.DSH_CI_FAILOVER_LINUX != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
|
|
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 dependencies and prepare bubblewrap
|
|
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: Run exhaustive coverage
|
|
run: pnpm run check:ci:coverage
|
|
|
|
node-24-consumers:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER_LINUX == 'selfhosted'
|
|
&& github.event.pull_request.user.login != 'dependabot[bot]'
|
|
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|
|
|| 'dsh-ubuntu-24-04-16core' }}
|
|
name: node 24 / snapshots and artifacts
|
|
env:
|
|
DSH_GATE_CONCURRENCY: '8'
|
|
DSH_NODE_COMPAT_SKIP_TYPECHECK: '1'
|
|
DSH_OXLINT_THREADS: '8'
|
|
DSH_PUBLINT_CONCURRENCY: '8'
|
|
DSH_WEB_SNAPSHOT_WORKERS: '6'
|
|
# Failover halves snapshot concurrency for the shared 64-core VM.
|
|
DSH_SNAPSHOT_MAX_CONCURRENCY: ${{ vars.DSH_CI_FAILOVER_LINUX == 'selfhosted' && github.event.pull_request.user.login != 'dependabot[bot]' && '12' || '32' }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
dest: ${{ runner.temp }}/setup-pnpm
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Configure pnpm store path
|
|
id: pnpm-store
|
|
run: |
|
|
store_root="$HOME/.local/share/pnpm/store"
|
|
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
|
|
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
|
|
echo "path=$store_path" >> "$GITHUB_OUTPUT"
|
|
|
|
# Pull requests restore the pnpm store and Playwright caches without paying
|
|
# compression and upload on the required path. No master job saves these
|
|
# hosted cache keys, so each restore-keys fallback hits the matching archived
|
|
# entry until it evicts, after which the store is cold. Skipped under failover
|
|
# — the self-hosted VM's persistent store is already warm.
|
|
- uses: actions/cache/restore@v4
|
|
if: vars.DSH_CI_FAILOVER_LINUX != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
|
|
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-
|
|
|
|
# Skipped under failover: the VM's persistent browser cache is already warm.
|
|
- uses: actions/cache/restore@v4
|
|
if: vars.DSH_CI_FAILOVER_LINUX != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-playwright-
|
|
|
|
- name: Install dependencies and prepare bubblewrap
|
|
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 Playwright Chromium and hosted dependencies
|
|
if: vars.DSH_CI_FAILOVER_LINUX != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
|
|
run: pnpm --filter @deepseek-ai/dsh-web-frontend exec playwright install --with-deps chromium
|
|
|
|
# The persistent VM image owns Playwright's Linux system packages; do
|
|
# not mutate the shared host with apt on every failover run.
|
|
- name: Install Playwright Chromium on the failover VM
|
|
if: vars.DSH_CI_FAILOVER_LINUX == 'selfhosted' && github.event.pull_request.user.login != 'dependabot[bot]'
|
|
run: pnpm --filter @deepseek-ai/dsh-web-frontend exec playwright install chromium
|
|
|
|
- name: Run compatibility, snapshot, and artifact gates
|
|
run: pnpm run check:ci:consumers
|
|
|
|
|
|
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: pnpm/action-setup@v4
|
|
with:
|
|
dest: ${{ runner.temp }}/setup-pnpm
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ matrix.node }}
|
|
cache: pnpm
|
|
|
|
- name: Install (immutable)
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run compatibility smokes
|
|
env:
|
|
DSH_BUILD_CLIENT_PROFILE: official
|
|
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.3.0
|
|
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
|
|
|
|
# The reusable builder owns each published executable, wheel, clean-install,
|
|
# keyless black-box, and trusted real-API path. All native release targets are
|
|
# required because a platform wheel cannot be validated by another carrier.
|
|
python-runtime:
|
|
if: github.event_name == 'pull_request'
|
|
name: python runtime / release-shaped matrix
|
|
uses: ./.github/workflows/build-exe-for-python-sdk.yml
|
|
with:
|
|
targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64
|
|
ci: true
|
|
secrets:
|
|
DEEPSEEK_API_KEY_EXTERNAL: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
|
|
|
|
# The pull-request Windows signals cover complementary hosts. The two fast
|
|
# win32 toolchain surfaces (workspace build, production site) execute with
|
|
# real, checksum-verified Windows Node under Wine on standard hosted Linux.
|
|
# The windows-native job below keeps the complete native-kernel inventory —
|
|
# including the observational portability gates this lane does not run —
|
|
# on real Windows. This job only provisions runner state (caches,
|
|
# apt); scripts/wine-windows-gates.sh owns the gate logic and is the same
|
|
# script the optional local gate `pnpm run check:windows-wine` runs.
|
|
# Current topology and fidelity limits live in
|
|
# .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md
|
|
windows:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
name: windows node 24 / wine blocking
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
dest: ${{ runner.temp }}/setup-pnpm
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
|
|
|
- name: Configure pnpm store path
|
|
id: pnpm-store
|
|
run: |
|
|
store_root="$HOME/.local/share/pnpm/store"
|
|
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
|
|
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
|
|
echo "path=$store_path" >> "$GITHUB_OUTPUT"
|
|
|
|
- uses: actions/cache/restore@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-
|
|
|
|
# Master's wine-apt-cache job in ci-master.yml seeds the default-branch
|
|
# scope every pull request can read; a save from this job only reaches
|
|
# reruns of the same merge ref.
|
|
- name: Compose Wine apt cache key
|
|
id: wine-cache-key
|
|
run: echo "key=wine-debs-${ImageOS:-linux}-${ImageVersion:-v0}" >> "$GITHUB_OUTPUT"
|
|
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: ~/wine-debs
|
|
key: ${{ steps.wine-cache-key.outputs.key }}
|
|
|
|
# Runner provisioning only — a developer machine installs Wine through
|
|
# its own package manager; the gate script assumes a wine binary and
|
|
# fails loud without one. Wine from the apt cache when present; else
|
|
# download the full dependency closure once and keep it for the next
|
|
# run. The `wine` dispatcher package (not bare `wine64`) is what puts a
|
|
# binary on PATH.
|
|
- name: Install Wine
|
|
run: |
|
|
if compgen -G "$HOME/wine-debs/*.deb" > /dev/null; then
|
|
# The restored archive is the full --download-only closure of
|
|
# `wine` for this runner image, so installing the .debs directly
|
|
# with dpkg needs no repository access. apt-get would instead
|
|
# re-download the same 100+ MB closure from the mirror, which has
|
|
# stalled the job past its budget on a degraded runner network.
|
|
# If the archive cannot satisfy the closure, fall back to the apt
|
|
# network install.
|
|
if ! sudo DEBIAN_FRONTEND=noninteractive dpkg -i "$HOME"/wine-debs/*.deb; then
|
|
sudo DEBIAN_FRONTEND=noninteractive dpkg --configure -a || true
|
|
sudo apt-get install -y --no-install-recommends "$HOME"/wine-debs/*.deb
|
|
fi
|
|
else
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends --download-only wine
|
|
mkdir -p "$HOME/wine-debs"
|
|
cp /var/cache/apt/archives/*.deb "$HOME/wine-debs/" 2>/dev/null || true
|
|
sudo apt-get install -y --no-install-recommends wine
|
|
fi
|
|
|
|
- name: Run the Wine Windows gates
|
|
run: bash scripts/wine-windows-gates.sh
|
|
|
|
- name: Shut down wineserver
|
|
if: always()
|
|
run: wineserver -k 2>/dev/null || true
|
|
|
|
# Every pull request also gets a real Windows-kernel signal. Its unmasked
|
|
# conclusion is a dependency of all-checks-passed, so failure, cancellation,
|
|
# or omission blocks the required verdict. Under normal operation it runs on
|
|
# the hosted larger runner. DSH_CI_FAILOVER_WINDOWS=selfhosted retargets it
|
|
# onto the in-house self-hosted Windows pool. Dependabot PRs are excluded
|
|
# from the self-hosted pool and stay queued for the hosted runner — see the failover
|
|
# runbook. This Windows switch is independent of the Linux
|
|
# DSH_CI_FAILOVER_LINUX variable that retargets the three required Linux jobs
|
|
# and the all-checks-passed verdict above.
|
|
windows-native:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER_WINDOWS == 'selfhosted'
|
|
&& github.event.pull_request.user.login != 'dependabot[bot]'
|
|
&& fromJSON('["self-hosted", "dsh-win-ci", "windows"]')
|
|
|| 'dsh-windows-2025-16core' }}
|
|
name: windows node 24 / native complete
|
|
timeout-minutes: 120
|
|
env:
|
|
# Partitioned coverage finishes before the heavy uninstrumented gate;
|
|
# the latter can use four workers without competing with sixteen shards.
|
|
DSH_COVERAGE_MAX_WORKERS: '12'
|
|
DSH_COVERAGE_PARTITIONS: '16'
|
|
# Instrumented process and polling fixtures can exceed Vitest's defaults
|
|
# under the complete lane's concurrent gate load.
|
|
DSH_COVERAGE_TEST_TIMEOUT_MS: '30000'
|
|
# After the threshold merge, the heavy gate overlaps lightweight
|
|
# observational checks within this post-coverage worker budget.
|
|
DSH_GATE_CONCURRENCY: '8'
|
|
DSH_PUBLINT_CONCURRENCY: '8'
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- 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: pnpm/action-setup@v4
|
|
with:
|
|
dest: ${{ runner.temp }}/setup-pnpm-js
|
|
|
|
- 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 on hosted Windows runners, and saving it adds latency after
|
|
# the gates. The self-hosted VM's persistent store makes caching
|
|
# redundant.
|
|
- name: Install (immutable)
|
|
shell: pwsh
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run complete native Windows gate inventory
|
|
shell: pwsh
|
|
run: pnpm run check:ci:windows-complete
|
|
|
|
# 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`, including both the Wine `windows` job and the real-kernel
|
|
# `windows-native` job. (`needs` cannot reach across workflow files; the
|
|
# master-only jobs in ci-master.yml are intentionally not part of this PR
|
|
# verdict.)
|
|
# `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
|
|
# This bookkeeping-only verdict must not depend on custom-pool
|
|
# provisioning — and under Linux failover it follows the same selector as
|
|
# the worker jobs it aggregates, so a standard-hosted outage cannot strand
|
|
# the branch-protection verdict either. It retargets with the Linux switch
|
|
# (DSH_CI_FAILOVER_LINUX), not the Windows one, because this bookkeeping job
|
|
# itself runs on Linux; the native dependency resolves its Windows pool
|
|
# independently.
|
|
runs-on: >-
|
|
${{ vars.DSH_CI_FAILOVER_LINUX == 'selfhosted'
|
|
&& github.event.pull_request.user.login != 'dependabot[bot]'
|
|
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|
|
|| 'ubuntu-latest' }}
|
|
needs: [node-24, node-24-coverage, node-24-consumers, node-compat, python-sdk, python-runtime, windows, windows-native]
|
|
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, ', ') }})"
|