CI #528
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # The merge queue creates a temporary branch and fires `merge_group`; without | |
| # this trigger the required checks never start and queued PRs stall forever. | |
| merge_group: | |
| branches: [main] | |
| types: [checks_requested] | |
| # Manual trigger for on-demand E2E runs on the self-hosted GPU runners, without | |
| # waiting on a push/PR or the full gate. Dispatch against any ref | |
| # (`gh workflow run ci.yml --ref <branch> -f platform=... -f tier=...`) — GitHub | |
| # runs THAT ref's copy of this file, so the E2E jobs it selects live on the ref. | |
| # A dispatch skips build-and-test (see its `if:`) for a fast loop. This trigger | |
| # must exist on the default branch for the workflow to be dispatchable at all. | |
| workflow_dispatch: | |
| inputs: | |
| platform: | |
| description: Which runner(s) to target | |
| type: choice | |
| default: all | |
| options: [all, mock, app-dev-gpu, strix-ubuntu, strix-windows] | |
| tier: | |
| description: Which scenario tier(s) to run | |
| type: choice | |
| default: both | |
| options: [both, expect-pass, known-bugs] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| # Decide which file categories a change touches so unaffected jobs can skip | |
| # their expensive work. Filtering runs ONLY on pull_request; on push and in the | |
| # merge queue every category is forced true, so post-merge `main` and queued | |
| # PRs always run the full suite. That keeps the skip from ever starving a | |
| # required check in the merge queue (a never-produced required check stalls the | |
| # queue forever — see the `commit-signatures` note below). Each output folds in | |
| # `.github/workflows/**`, so any change to CI itself triggers a full run. | |
| changes: | |
| runs-on: ubuntu-latest | |
| # paths-filter reads the PR's changed-file list from the API on | |
| # pull_request events; that needs pull-requests:read on top of the | |
| # workflow-wide contents:read (job-level permissions replace the default | |
| # set, so contents:read is repeated here for checkout). | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| # `<filter> || <fallback>`: the filter result on PRs (empty string when the | |
| # filter step is skipped off-PR), otherwise the forced 'true'. | |
| rust: ${{ steps.filter.outputs.rust || steps.all.outputs.forced }} | |
| heavy: ${{ steps.filter.outputs.heavy || steps.all.outputs.forced }} | |
| lint: ${{ steps.filter.outputs.lint || steps.all.outputs.forced }} | |
| tpn: ${{ steps.filter.outputs.tpn || steps.all.outputs.forced }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Filter changed paths (pull requests only) | |
| id: filter | |
| if: github.event_name == 'pull_request' | |
| uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3.0.2 | |
| with: | |
| filters: | | |
| # Rust-only checks (fmt, clippy, coverage). | |
| rust: | |
| - '**/*.rs' | |
| - '**/Cargo.toml' | |
| - 'Cargo.lock' | |
| - 'rust-toolchain*' | |
| # clippy runs `cargo xtask manifest --check` against this file. | |
| - 'MANIFEST.md' | |
| - '.github/workflows/**' | |
| # build-and-test runs cargo AND the python/shell smoke + acceptance | |
| # steps, so it depends on the Rust set plus those scripts. | |
| heavy: | |
| - '**/*.rs' | |
| - '**/Cargo.toml' | |
| - 'Cargo.lock' | |
| - 'rust-toolchain*' | |
| - 'scripts/**' | |
| - 'engines/**' | |
| - '**/*.py' | |
| - '**/*.sh' | |
| - '**/*.ps1' | |
| - '**/*.feature' | |
| - 'install*' | |
| - '.github/workflows/**' | |
| # THIRD_PARTY_NOTICES.txt staleness gate: anything that changes the | |
| # dependency tree, the cargo-about config/template, the generator, or | |
| # the generated file itself. | |
| tpn: | |
| - 'Cargo.lock' | |
| - '**/Cargo.toml' | |
| - 'about.toml' | |
| - 'about.hbs' | |
| - 'THIRD_PARTY_NOTICES.txt' | |
| - 'xtask/**' | |
| - '.github/workflows/**' | |
| # Python / Shell / PowerShell lint job. | |
| lint: | |
| - 'scripts/**' | |
| - 'engines/**' | |
| - '**/*.py' | |
| - '**/*.sh' | |
| - '**/*.ps1' | |
| - 'ruff.toml' | |
| - 'PSScriptAnalyzerSettings.psd1' | |
| - '.github/workflows/**' | |
| - name: Force full run off pull requests | |
| id: all | |
| if: github.event_name != 'pull_request' | |
| run: echo "forced=true" >> "$GITHUB_OUTPUT" | |
| build-and-test: | |
| runs-on: ubuntu-latest | |
| # Don't spend per-OS build/test cycles unless the cheap lint gate is green. | |
| needs: [changes, clippy, prek] | |
| # A manual E2E dispatch skips this heavy job for a fast loop; the E2E jobs | |
| # tolerate a skipped build-and-test in their own `if:` guards. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install native build deps | |
| if: needs.changes.outputs.heavy == 'true' | |
| run: sudo apt-get update && sudo apt-get install -y pkg-config libcap-dev | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| if: needs.changes.outputs.heavy == 'true' | |
| # Build the runtime binaries the smoke + acceptance steps below need (every | |
| # engine binary; smoke hard-fails on a missing one). Unit/integration tests | |
| # run in the dedicated `test` job on only the crates a change can affect; | |
| # `clippy --all-targets` is the compile-check for the non-binary targets, so | |
| # dropping `--all-targets` here loses no coverage. | |
| - name: Build | |
| if: needs.changes.outputs.heavy == 'true' | |
| run: cargo build --workspace | |
| - name: Local no-fallback smoke | |
| if: needs.changes.outputs.heavy == 'true' | |
| run: python scripts/smoke_local.py --skip-build | |
| - name: Acceptance harness self-tests | |
| if: needs.changes.outputs.heavy == 'true' | |
| run: | | |
| python scripts/comfyui_therock_gpu_test.py --self-test | |
| python scripts/local_assistant_therock_gpu_test.py --self-test | |
| python scripts/vllm_therock_gpu_test.py --self-test | |
| python scripts/wsl_preflight.py --self-test | |
| - name: Portable WSL build deps self-test | |
| if: needs.changes.outputs.heavy == 'true' | |
| run: bash scripts/setup-wsl-portable-build-deps.sh --self-test | |
| - name: Release readiness self-test | |
| if: needs.changes.outputs.heavy == 'true' | |
| run: python scripts/release_readiness.py --self-test | |
| - name: Acceptance install lifecycle | |
| if: needs.changes.outputs.heavy == 'true' | |
| run: ./scripts/acceptance-install-upgrade-tui-uninstall.sh | |
| # Fine-grained test selection (the second half of smarter CI; the path-based | |
| # job skip is the `changes` job above). Runs cargo's unit + integration tests | |
| # for only the crates a change can reach — the changed crates plus their | |
| # transitive dependents, computed by `cargo xtask affected` from the workspace | |
| # dependency graph — instead of the whole workspace. | |
| # | |
| # Merge-queue safety: the narrowing happens ONLY on pull_request. On push and | |
| # in the merge queue the selection is forced to `--workspace`, so post-merge | |
| # `main` and every queued PR run the full suite — a required check is never | |
| # starved and the queue cannot stall. The full Windows suite | |
| # (windows-build-and-test) also runs the whole workspace on every change, so it | |
| # backstops any crate a graph-based selection could miss (e.g. an integration | |
| # test that drives another crate only at runtime). | |
| test: | |
| name: Test (affected crates) | |
| runs-on: ubuntu-latest | |
| # Same lint gate as the OS build jobs: don't spend a test cycle until the | |
| # cheap checks are green. | |
| needs: [changes, clippy, prek] | |
| # A manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| # `cargo xtask affected` diffs origin/<base>...HEAD, so it needs the | |
| # base history and the real PR head (not the synthetic merge ref). | |
| fetch-depth: 0 | |
| ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || '' }} | |
| - name: Install native build deps | |
| if: needs.changes.outputs.rust == 'true' | |
| run: sudo apt-get update && sudo apt-get install -y pkg-config libcap-dev | |
| - uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0 | |
| if: needs.changes.outputs.rust == 'true' | |
| with: | |
| # Keep the PR (subset) and push/merge (`--workspace`) builds in separate | |
| # cache lanes. A subset build resolves Cargo features differently than | |
| # the whole workspace, so a shared cache would make the two evict and | |
| # recompile each other's artifacts on every alternation. | |
| cache-key: ${{ github.event_name == 'pull_request' && 'affected-pr' || 'full' }} | |
| - name: Install cargo-nextest | |
| if: needs.changes.outputs.rust == 'true' | |
| uses: taiki-e/install-action@9bcaee1dcae34154180f412e2fa69355a7cda9f6 # v2.82.6 | |
| with: | |
| tool: nextest | |
| - name: Select affected crates | |
| id: sel | |
| if: needs.changes.outputs.rust == 'true' | |
| run: | | |
| # The `cargo xtask` alias builds xtask in release (target/release), so | |
| # computing the selection doesn't perturb the debug feature resolution | |
| # the nextest build below uses. | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| sel=$(cargo xtask affected --base "origin/${{ github.base_ref }}") | |
| else | |
| sel="--workspace" | |
| fi | |
| echo "affected selection: ${sel:-<no rust crates changed>}" | |
| echo "sel=$sel" >> "$GITHUB_OUTPUT" | |
| - name: Test (nextest) | |
| # Skip cleanly when nothing Rust-relevant resolved to a crate, so the | |
| # required check still reports success. | |
| if: needs.changes.outputs.rust == 'true' && steps.sel.outputs.sel != '' | |
| # `sel` is intentionally unquoted: it expands to either `--workspace` or | |
| # several `-p <crate>` flags that must word-split into separate argv | |
| # entries. The values are crate names from our own tool, not user input. | |
| run: cargo nextest run ${{ steps.sel.outputs.sel }} | |
| windows-build-and-test: | |
| runs-on: windows-latest | |
| env: | |
| CARGO_INCREMENTAL: "0" | |
| # Don't spend per-OS build/test cycles unless the cheap lint gate is green. | |
| needs: [changes, clippy, prek] | |
| # A manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| if: needs.changes.outputs.heavy == 'true' | |
| with: | |
| cache-on-failure: true | |
| - name: Build | |
| if: needs.changes.outputs.heavy == 'true' | |
| shell: pwsh | |
| run: | | |
| cargo build --workspace --all-targets | |
| cargo build --release -p rocm -p rocmd -p rocm-engine-lemonade -p rocm-engine-vllm -p xtask | |
| - name: Test | |
| if: needs.changes.outputs.heavy == 'true' | |
| shell: pwsh | |
| run: cargo test --workspace --all-targets | |
| - name: Local no-fallback smoke | |
| if: needs.changes.outputs.heavy == 'true' | |
| shell: pwsh | |
| run: python .\scripts\smoke_local.py --skip-build | |
| - name: Acceptance harness self-tests | |
| if: needs.changes.outputs.heavy == 'true' | |
| shell: pwsh | |
| run: | | |
| python .\scripts\comfyui_therock_gpu_test.py --self-test | |
| python .\scripts\local_assistant_therock_gpu_test.py --self-test | |
| python .\scripts\vllm_therock_gpu_test.py --self-test | |
| python .\scripts\wsl_preflight.py --self-test | |
| - name: Release readiness self-test | |
| if: needs.changes.outputs.heavy == 'true' | |
| shell: pwsh | |
| run: python .\scripts\release_readiness.py --self-test | |
| - name: Check PowerShell installer syntax | |
| if: needs.changes.outputs.heavy == 'true' | |
| shell: pwsh | |
| run: | | |
| $null = [scriptblock]::Create((Get-Content .\install.ps1 -Raw)) | |
| $null = [scriptblock]::Create((Get-Content .\scripts\package-windows-release.ps1 -Raw)) | |
| - name: Acceptance install lifecycle | |
| if: needs.changes.outputs.heavy == 'true' | |
| shell: pwsh | |
| run: .\scripts\acceptance-install-upgrade-tui-uninstall.ps1 | |
| prek: | |
| # The fast lint gate: every toolchain-light lint/hygiene check, run from the | |
| # single source of truth in .pre-commit-config.yaml — hygiene + Python (ruff) | |
| # + Shell (shellcheck) + cargo fmt (rustfmt only, no compile). | |
| # `--no-group local-tools` skips the hooks that need a full Rust compile, | |
| # hawkeye, or PowerShell — those have their own jobs (clippy, build-and-test, | |
| # license-headers, powershell-lint). | |
| name: prek (lint / hygiene) | |
| runs-on: ubuntu-latest | |
| # Always-on: prek is the cheapest gate (no compile) and its hygiene hooks run | |
| # on every file type, so it is relevant to any change — including docs-only | |
| # PRs that match no `changes` category. Like license-headers and | |
| # commit-signatures, it is not gated. | |
| # Exception: a manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| # cargo-fmt hook needs rustfmt (no build). | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| components: rustfmt | |
| cache: false | |
| # Supply-chain hardening: the action is pinned to a commit SHA and prek to | |
| # an exact version. The action ships a hardcoded SHA-256 checksum map | |
| # (src/known-checksums.ts) and verifies the downloaded prek archive against | |
| # it, so a tampered release can't be installed. This commit is past the | |
| # v2.0.4 tag because it is the one that added prek 0.4.5 to that map — pin | |
| # an earlier commit and the action would not know 0.4.5 and skip the check. | |
| - uses: j178/prek-action@dec4adcd2fa1db9d50a39668b22112a37235e730 # prek 0.4.5 checksums | |
| with: | |
| prek-version: 0.4.5 | |
| extra-args: --all-files --no-group local-tools | |
| clippy: | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| # A manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| if: needs.changes.outputs.rust == 'true' | |
| - name: Clippy | |
| if: needs.changes.outputs.rust == 'true' | |
| run: cargo clippy --locked --workspace --all-targets -- -D warnings | |
| - name: MANIFEST.md dependency table is current | |
| if: needs.changes.outputs.rust == 'true' | |
| run: cargo xtask manifest --check | |
| third-party-notices: | |
| name: Third-party notices current | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| # A manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| if: needs.changes.outputs.tpn == 'true' | |
| # Pin the cargo-about version so the check compares against the exact same | |
| # generator contributors use; a different version can format the notices | |
| # differently and fail the byte-for-byte comparison. This version has no | |
| # prebuilt release binary and its `cargo install` needs the `cli` feature, | |
| # so build from source (cached by version); `--locked` uses cargo-about's | |
| # own lockfile for a reproducible generator. | |
| - name: Cache cargo-about | |
| if: needs.changes.outputs.tpn == 'true' | |
| id: cache-cargo-about | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.cargo/bin/cargo-about | |
| key: ${{ runner.os }}-cargo-about-0.9.1 | |
| - name: Install cargo-about | |
| if: needs.changes.outputs.tpn == 'true' && steps.cache-cargo-about.outputs.cache-hit != 'true' | |
| run: cargo install cargo-about@0.9.1 --locked --features cli | |
| - name: THIRD_PARTY_NOTICES.txt is current | |
| if: needs.changes.outputs.tpn == 'true' | |
| run: cargo xtask tpn --check | |
| coverage: | |
| name: Coverage (rocm-dash crates, ratcheted) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| # A manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install native build deps | |
| if: needs.changes.outputs.rust == 'true' | |
| run: sudo apt-get update && sudo apt-get install -y pkg-config libcap-dev | |
| - uses: dtolnay/rust-toolchain@1.96.0 | |
| if: needs.changes.outputs.rust == 'true' | |
| with: | |
| components: llvm-tools-preview | |
| - name: Install cargo-llvm-cov | |
| if: needs.changes.outputs.rust == 'true' | |
| uses: taiki-e/install-action@9bcaee1dcae34154180f412e2fa69355a7cda9f6 # v2.82.6 | |
| with: | |
| tool: cargo-llvm-cov | |
| - name: Cache cargo registry and build | |
| if: needs.changes.outputs.rust == 'true' | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-cov-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-cov- | |
| # Ratcheted, fail-on-regression floor scoped to the transplanted rocm-dash | |
| # crates (the clean anchor) — deliberately NOT the whole workspace, so the | |
| # gate does not over-claim coverage of the large untyped rocm-cli core | |
| # Baseline measured 2026-06-11: 73.7% lines across the four | |
| # crates. Floor set just below measured; ratchet upward as the larger TUI | |
| # tab files (bench/overview/modal) gain tests. | |
| - name: Coverage gate (rocm-dash crates, >= 70% lines) | |
| if: needs.changes.outputs.rust == 'true' | |
| run: | | |
| cargo llvm-cov --no-cfg-coverage \ | |
| -p rocm-dash-core -p rocm-dash-collectors \ | |
| -p rocm-dash-daemon -p rocm-dash-tui \ | |
| --fail-under-lines 70 | |
| powershell-lint: | |
| # Runs the prek `powershell-script-analyzer` hook's logic (cargo xtask | |
| # powershell-lint) under BOTH PowerShell editions. windows-latest is the only | |
| # runner with Windows PowerShell 5.1 (`powershell`); it also ships PowerShell | |
| # 7 (`pwsh`). Kept separate from windows-build-and-test so it runs in parallel | |
| # rather than behind that slow job. | |
| name: Lint (PowerShell) | |
| runs-on: windows-latest | |
| needs: changes | |
| # A manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| if: needs.changes.outputs.lint == 'true' | |
| - name: Install PSScriptAnalyzer (PowerShell 7) | |
| if: needs.changes.outputs.lint == 'true' | |
| shell: pwsh | |
| run: Install-Module PSScriptAnalyzer -Scope CurrentUser -Force -RequiredVersion 1.25.0 | |
| - name: Install PSScriptAnalyzer (Windows PowerShell 5.1) | |
| if: needs.changes.outputs.lint == 'true' | |
| shell: powershell | |
| run: | | |
| [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | |
| Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force | Out-Null | |
| Install-Module PSScriptAnalyzer -Scope CurrentUser -Force -RequiredVersion 1.25.0 | |
| - name: PSScriptAnalyzer (PowerShell 7) | |
| if: needs.changes.outputs.lint == 'true' | |
| run: cargo xtask powershell-lint --shell pwsh | |
| - name: PSScriptAnalyzer (Windows PowerShell 5.1) | |
| if: needs.changes.outputs.lint == 'true' | |
| run: cargo xtask powershell-lint --shell powershell | |
| license-headers: | |
| name: License header check (hawkeye) | |
| runs-on: ubuntu-latest | |
| env: | |
| # Install a pinned prebuilt hawkeye binary instead of pulling the | |
| # korandoru/hawkeye Docker image on every run, and verify it against a | |
| # sha256 recorded here. The hash lives in-repo, out of band from the | |
| # release: GitHub release assets are mutable, so a republished/tampered | |
| # artifact (and its co-published .sha256) would pass an upstream-only | |
| # check — pinning the hash here makes that fail instead. To upgrade, bump | |
| # the version and replace the hash with the new release's published | |
| # .sha256 (confirm the bytes first). | |
| HAWKEYE_VERSION: v6.5.1 | |
| HAWKEYE_SHA256: d6eb0505a45a15244f4f789158aafe5e3f1a7dc86c9dc1d7651f3cb1e1b321e0 | |
| HAWKEYE_INSTALL_DIR: ${{ github.workspace }}/.hawkeye-bin | |
| # A manual E2E dispatch only exercises the E2E jobs; skip the rest. | |
| if: github.event_name != 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Cache hawkeye binary | |
| id: cache-hawkeye | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.HAWKEYE_INSTALL_DIR }} | |
| key: ${{ runner.os }}-hawkeye-${{ env.HAWKEYE_VERSION }}-${{ env.HAWKEYE_SHA256 }} | |
| - name: Install hawkeye | |
| if: steps.cache-hawkeye.outputs.cache-hit != 'true' | |
| run: | | |
| tarball="hawkeye-x86_64-unknown-linux-gnu.tar.xz" | |
| curl --proto '=https' --tlsv1.2 -LsSf \ | |
| "https://github.com/korandoru/hawkeye/releases/download/${HAWKEYE_VERSION}/${tarball}" \ | |
| -o "${tarball}" | |
| echo "${HAWKEYE_SHA256} ${tarball}" | sha256sum -c - | |
| mkdir -p "${HAWKEYE_INSTALL_DIR}" | |
| tar -xJf "${tarball}" -C "${HAWKEYE_INSTALL_DIR}" --strip-components=1 | |
| rm -f "${tarball}" | |
| - name: Check license headers | |
| run: | | |
| "${HAWKEYE_INSTALL_DIR}/hawkeye" check | |
| commit-signatures: | |
| name: Commit signatures + sign-off | |
| runs-on: ubuntu-latest | |
| # Runs on pull requests and in the merge queue. Both define a base that | |
| # bounds the commit range. Handling `merge_group` matters once this is a | |
| # *required* check: the queue fires `merge_group` (not `pull_request`), so a | |
| # job gated to PRs only would never produce the required check and the queue | |
| # entry would stall forever. | |
| if: github.event_name == 'pull_request' || github.event_name == 'merge_group' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| # PR: check out the PR head, not the synthetic refs/pull/N/merge commit | |
| # (which is unsigned and lacks a sign-off, and would otherwise appear | |
| # in origin/<base>..HEAD and fail the gate on every PR). | |
| # merge_group: check out the queue head — the rebased/squashed commits | |
| # GitHub built for the group. Merge commits are disabled on this repo, | |
| # so these are normal commits that preserve their Signed-off-by trailer | |
| # and are GitHub "Verified" (web-flow signed). | |
| ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.event.merge_group.head_sha }} | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| - name: Verify commits are signed and signed-off | |
| # `--require-verified` shells out to the `gh` CLI; pass the job token so | |
| # `gh api` is authenticated (avoids the unauthenticated rate limit). | |
| # Base: the PR's base branch, or — in the queue — the exact commit the | |
| # merge group was built on (`base_sha`), so the range is just the queued | |
| # commits and not whatever else has since landed on the base branch. | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| BASE: ${{ github.event_name == 'pull_request' && format('origin/{0}', github.base_ref) || github.event.merge_group.base_sha }} | |
| run: cargo xtask verify-commits --base "$BASE" --require-verified | |
| # Hardware (real AMD GPU / WSL) smoke tests on dedicated self-hosted runners | |
| # are intentionally not part of this workflow yet. See | |
| # docs/ci-hardware-testing.md for the planned design; they will land in a | |
| # follow-up PR. | |
| # ── E2E tests (cucumber-rs) ─────────────────────────────────────────────── | |
| # | |
| # BDD scenarios in Gherkin (.feature files) backed by Rust step functions. | |
| # Three selections: blocking mock tier, non-blocking known bugs, non-blocking | |
| # GPU. Cucumber tag filters are exact-match, so known-bug scenarios carry a | |
| # bare `@expected-failure` (plus `@expected-failure-EAI-NNNN` for traceability) | |
| # and hardware-dependent scenarios carry `@gpu`. | |
| # Blocking mock-tier job: must stay green. Known-bug scenarios and | |
| # hardware-dependent scenarios are excluded here and run in the non-blocking | |
| # jobs below. | |
| e2e: | |
| name: E2E tests | |
| runs-on: ubuntu-latest | |
| needs: [changes, build-and-test] | |
| # On push/PR/merge_group: unchanged — run when build-and-test succeeded and | |
| # the change is heavy. On workflow_dispatch: build-and-test is skipped, so | |
| # tolerate that and gate on the platform/tier inputs instead (mock tier here). | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'mock') | |
| && (inputs.tier == 'both' || inputs.tier == 'expect-pass')) | |
| ) | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install native build deps | |
| run: sudo apt-get update && sudo apt-get install -y pkg-config libcap-dev | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| # The workspace test job selects only affected crates and runs the cucumber | |
| # harness, not the library's own unit tests — run the report generator's | |
| # unit tests (stats counting, scenario status, date formatting) here. | |
| - name: Unit tests (e2e-cucumber lib) | |
| run: cargo test -p e2e-cucumber --lib | |
| - name: Run E2E tests (mock tier, excluding known bugs) | |
| run: cargo xtask e2e -- -t "not @gpu and not @expected-failure" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-report | |
| path: tests/e2e-cucumber/results/ | |
| # Runs ONLY the known-bug scenarios under xfail inversion (`--expect-failures`): | |
| # a tagged scenario failing is the expected, green outcome. The job goes red | |
| # only when a known bug is silently fixed (XPASS — remove its @expected-failure | |
| # tag so it joins the blocking e2e job above), an untagged scenario fails, or a | |
| # parse/hook error occurs — all actionable, so this gates rather than being an | |
| # always-red check reviewers learn to ignore. | |
| e2e-known-bugs: | |
| name: E2E tests (known bugs) | |
| runs-on: ubuntu-latest | |
| needs: [changes, build-and-test] | |
| # See `e2e`: dispatch tolerates skipped build-and-test; mock tier, known-bugs. | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'mock') | |
| && (inputs.tier == 'both' || inputs.tier == 'known-bugs')) | |
| ) | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install native build deps | |
| run: sudo apt-get update && sudo apt-get install -y pkg-config libcap-dev | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| - name: Run known-bug E2E scenarios (mock tier) | |
| run: cargo xtask e2e --expect-failures -- -t "@expected-failure and not @gpu" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-known-bugs-report | |
| path: tests/e2e-cucumber/results/ | |
| # GPU hardware scenarios that are expected to PASS. Mirrors the mock `e2e` job | |
| # but for `@gpu` hardware-dependent scenarios; known-bug `@gpu` scenarios are | |
| # split into e2e-gpu-known-bugs below so a red here always means a real GPU | |
| # regression, never a known bug still reproducing. | |
| e2e-gpu: | |
| name: E2E tests (GPU) | |
| runs-on: [self-hosted, linux, amd-gpu] | |
| needs: [changes, build-and-test] | |
| # See `e2e`: dispatch tolerates skipped build-and-test; app-dev-gpu, expect-pass. | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'app-dev-gpu') | |
| && (inputs.tier == 'both' || inputs.tier == 'expect-pass')) | |
| ) | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v6 | |
| # cache: false — on this self-hosted runner we persist the build cache | |
| # ourselves via CARGO_TARGET_DIR (below). The action's built-in | |
| # Swatinem/rust-cache otherwise tries to SAVE the large target dir to | |
| # GitHub's cache service in a post-step (slow/hangs) and its cleanup wipes | |
| # the local target. | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| cache: false | |
| # `actions/checkout` runs `git clean -ffdx`, which deletes the gitignored | |
| # `target/` inside the repo every job → a full ~15min rebuild each run. | |
| # Point CARGO_TARGET_DIR at a sibling of the checkout ($RUNNER_WORKSPACE is | |
| # the checkout's parent — untouched by git clean and persistent between jobs | |
| # on a self-hosted runner), so cargo rebuilds incrementally: unchanged → | |
| # reused, changed → only the diff. | |
| - name: Run E2E tests on GPU hardware (excluding known bugs) | |
| run: | | |
| export CARGO_TARGET_DIR="$RUNNER_WORKSPACE/e2e-target" | |
| # Share heavy immutable artifacts (TheRock runtimes ~3.3GB, HF weights, | |
| # vLLM venv) across scenarios so they download once per runner, not per | |
| # scenario. Persistent path; service state stays isolated per scenario. | |
| export E2E_SHARED_CACHE_DIR="$RUNNER_WORKSPACE/e2e-shared" | |
| cargo xtask e2e -- -t "@gpu and not @expected-failure" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-gpu-report | |
| path: tests/e2e-cucumber/results/ | |
| # GPU counterpart of e2e-known-bugs: runs ONLY the `@gpu @expected-failure` | |
| # scenarios under xfail inversion (`--expect-failures`). Green when each known | |
| # GPU bug still fails as expected; red only when one is silently fixed (XPASS — | |
| # remove its @expected-failure tag so it joins e2e-gpu above), an untagged | |
| # scenario fails, or a parse/hook error occurs. | |
| e2e-gpu-known-bugs: | |
| name: E2E tests (GPU, known bugs) | |
| runs-on: [self-hosted, linux, amd-gpu] | |
| needs: [changes, build-and-test] | |
| # See `e2e`: dispatch tolerates skipped build-and-test; app-dev-gpu, known-bugs. | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'app-dev-gpu') | |
| && (inputs.tier == 'both' || inputs.tier == 'known-bugs')) | |
| ) | |
| continue-on-error: true | |
| env: | |
| # Known-bug scenarios are expected to fail, so don't grant a serve the full | |
| # cold-start window — fail fast instead of waiting the default 600s when a | |
| # bug manifests as a serve that never becomes ready. | |
| E2E_SERVE_TIMEOUT_SECS: "90" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| # See e2e-gpu: cache: false because we persist the cache ourselves via | |
| # CARGO_TARGET_DIR; the action's rust-cache save/cleanup is slow and harmful | |
| # on this self-hosted runner. | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| cache: false | |
| # See e2e-gpu: keep the build cache out of the checkout (git clean would | |
| # wipe it) for incremental rebuilds across jobs. | |
| - name: Run known-bug E2E scenarios on GPU hardware | |
| run: | | |
| export CARGO_TARGET_DIR="$RUNNER_WORKSPACE/e2e-target" | |
| # See e2e-gpu: share heavy immutable artifacts across scenarios. | |
| export E2E_SHARED_CACHE_DIR="$RUNNER_WORKSPACE/e2e-shared" | |
| cargo xtask e2e --expect-failures -- -t "@gpu and @expected-failure" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-gpu-known-bugs-report | |
| path: tests/e2e-cucumber/results/ | |
| # Second AMD GPU architecture: the Strix Halo (gfx1151) Ubuntu runner. Same | |
| # expect-pass / known-bugs split as app-dev-gpu's e2e-gpu jobs, targeted by the | |
| # `strix-halo` label so it lands only on that runner (app-dev-gpu carries | |
| # `amd-gpu`, not `strix-halo`). Non-blocking while this hardware is proven out. | |
| e2e-gpu-strix-ubuntu: | |
| name: E2E tests (Strix Halo, Ubuntu) | |
| runs-on: [self-hosted, linux, strix-halo] | |
| needs: [changes, build-and-test] | |
| # See `e2e`: dispatch tolerates skipped build-and-test; strix-ubuntu, expect-pass. | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'strix-ubuntu') | |
| && (inputs.tier == 'both' || inputs.tier == 'expect-pass')) | |
| ) | |
| continue-on-error: true | |
| # On this runner `/`, `/home/ubuntu`, and `/tmp` are ALL on a full root | |
| # partition; only /home/ubuntu/actions-runner (a 1.7T nvme) has space. So | |
| # EVERYTHING the job writes must land on the nvme. Point HOME there (catches | |
| # ~/.cache/pip, ~/.config, and any other $HOME writer — pip's cache under the | |
| # real /home/ubuntu is what previously failed `install sdk` with ENOSPC), | |
| # plus the toolchain, temp, and pip cache. The rustup bootstrap still uses | |
| # --no-modify-path so it doesn't touch $HOME/.profile. (The HOME override | |
| # brings back a cosmetic rustup euid/HOME warning — accepted: not filling the | |
| # root disk matters more.) | |
| env: | |
| HOME: /home/ubuntu/actions-runner/e2e-home | |
| CARGO_HOME: /home/ubuntu/actions-runner/.cargo | |
| RUSTUP_HOME: /home/ubuntu/actions-runner/.rustup | |
| TMPDIR: /home/ubuntu/actions-runner/tmp | |
| PIP_CACHE_DIR: /home/ubuntu/actions-runner/pip-cache | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Prepare writable dirs on the nvme | |
| run: mkdir -p /home/ubuntu/actions-runner/e2e-home /home/ubuntu/actions-runner/tmp /home/ubuntu/actions-runner/pip-cache | |
| # Bootstrap rustup ourselves with --no-modify-path so it never writes to | |
| # $HOME/.profile (setup-rust-toolchain doesn't expose that flag). | |
| # rust-toolchain.toml pins the exact toolchain, installed on first cargo | |
| # use. Idempotent. | |
| - name: Ensure Rust toolchain | |
| run: | | |
| if ! command -v cargo >/dev/null 2>&1 && [ ! -x "$CARGO_HOME/bin/cargo" ]; then | |
| curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs \ | |
| | sh -s -- -y --no-modify-path --default-toolchain none | |
| fi | |
| echo "$CARGO_HOME/bin" >> "$GITHUB_PATH" | |
| - name: Run E2E tests on Strix Halo (excluding known bugs) | |
| run: | | |
| export CARGO_TARGET_DIR="$RUNNER_WORKSPACE/e2e-target" | |
| export E2E_SHARED_CACHE_DIR="$RUNNER_WORKSPACE/e2e-shared" | |
| cargo xtask e2e -- -t "@gpu and not @expected-failure" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-gpu-strix-ubuntu-report | |
| path: tests/e2e-cucumber/results/ | |
| e2e-gpu-strix-ubuntu-known-bugs: | |
| name: E2E tests (Strix Halo, Ubuntu, known bugs) | |
| runs-on: [self-hosted, linux, strix-halo] | |
| needs: [changes, build-and-test] | |
| # See `e2e`: dispatch tolerates skipped build-and-test; strix-ubuntu, known-bugs. | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'strix-ubuntu') | |
| && (inputs.tier == 'both' || inputs.tier == 'known-bugs')) | |
| ) | |
| continue-on-error: true | |
| # See e2e-gpu-strix-ubuntu: /, /home/ubuntu, and /tmp are all on a full root | |
| # partition; only the nvme has space. Point HOME + all caches at the nvme so | |
| # nothing writes to root (pip's cache under the real $HOME is what failed | |
| # `install sdk` with ENOSPC). | |
| env: | |
| HOME: /home/ubuntu/actions-runner/e2e-home | |
| CARGO_HOME: /home/ubuntu/actions-runner/.cargo | |
| RUSTUP_HOME: /home/ubuntu/actions-runner/.rustup | |
| TMPDIR: /home/ubuntu/actions-runner/tmp | |
| PIP_CACHE_DIR: /home/ubuntu/actions-runner/pip-cache | |
| # Known-bug tier: fail fast rather than wait the default 600s on a serve | |
| # that a bug prevents from becoming ready. | |
| E2E_SERVE_TIMEOUT_SECS: "90" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Prepare writable dirs on the nvme | |
| run: mkdir -p /home/ubuntu/actions-runner/e2e-home /home/ubuntu/actions-runner/tmp /home/ubuntu/actions-runner/pip-cache | |
| # See e2e-gpu-strix-ubuntu: bootstrap rustup with --no-modify-path so it | |
| # never writes $HOME/.profile on the full root disk. | |
| - name: Ensure Rust toolchain | |
| run: | | |
| if ! command -v cargo >/dev/null 2>&1 && [ ! -x "$CARGO_HOME/bin/cargo" ]; then | |
| curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs \ | |
| | sh -s -- -y --no-modify-path --default-toolchain none | |
| fi | |
| echo "$CARGO_HOME/bin" >> "$GITHUB_PATH" | |
| - name: Run known-bug E2E scenarios on Strix Halo | |
| run: | | |
| export CARGO_TARGET_DIR="$RUNNER_WORKSPACE/e2e-target" | |
| export E2E_SHARED_CACHE_DIR="$RUNNER_WORKSPACE/e2e-shared" | |
| cargo xtask e2e --expect-failures -- -t "@gpu and @expected-failure" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-gpu-strix-ubuntu-known-bugs-report | |
| path: tests/e2e-cucumber/results/ | |
| # First real Windows GPU coverage: the Strix Halo Windows 11 runner. The | |
| # existing windows-build-and-test uses GitHub-hosted windows-latest, which has | |
| # no GPU, so `@gpu` scenarios have never run on Windows hardware. Expect | |
| # first-run breakage to triage; non-blocking so it never gates the PR. | |
| e2e-gpu-strix-windows: | |
| name: E2E tests (Strix Halo, Windows) | |
| runs-on: [self-hosted, windows, strix-halo] | |
| needs: [changes, build-and-test] | |
| # See `e2e`: dispatch tolerates skipped build-and-test; strix-windows, expect-pass. | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'strix-windows') | |
| && (inputs.tier == 'both' || inputs.tier == 'expect-pass')) | |
| ) | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v6 | |
| # setup-rust-toolchain runs an internal bash script, which this Windows | |
| # runner lacks (bash: command not found). Bootstrap rustup with the | |
| # PowerShell-native installer instead; idempotent, so it only downloads on | |
| # a runner that doesn't already have the toolchain. Use `powershell` | |
| # (Windows PowerShell 5.1, always present) rather than `pwsh` (PowerShell 7), | |
| # which this self-hosted runner does not have installed. | |
| - name: Ensure Rust toolchain (PowerShell) | |
| shell: powershell | |
| run: | | |
| if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) { | |
| Invoke-WebRequest https://win.rustup.rs/x86_64 -OutFile $env:TEMP\rustup-init.exe | |
| # --default-toolchain none: rust-toolchain.toml pins the exact | |
| # version (1.96.0 + components), auto-installed on first cargo use. | |
| & $env:TEMP\rustup-init.exe -y --default-toolchain none | |
| "$env:USERPROFILE\.cargo\bin" | Out-File -FilePath $env:GITHUB_PATH -Append | |
| } | |
| - name: Run E2E tests on Strix Halo Windows (excluding known bugs) | |
| shell: powershell | |
| run: cargo xtask e2e -- -t "@gpu and not @expected-failure" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-gpu-strix-windows-report | |
| path: tests/e2e-cucumber/results/ | |
| e2e-gpu-strix-windows-known-bugs: | |
| name: E2E tests (Strix Halo, Windows, known bugs) | |
| runs-on: [self-hosted, windows, strix-halo] | |
| needs: [changes, build-and-test] | |
| # See `e2e`: dispatch tolerates skipped build-and-test; strix-windows, known-bugs. | |
| if: >- | |
| always() | |
| && needs.changes.result == 'success' | |
| && ( | |
| (github.event_name != 'workflow_dispatch' | |
| && needs.build-and-test.result == 'success' | |
| && needs.changes.outputs.heavy == 'true') | |
| || (github.event_name == 'workflow_dispatch' | |
| && (inputs.platform == 'all' || inputs.platform == 'strix-windows') | |
| && (inputs.tier == 'both' || inputs.tier == 'known-bugs')) | |
| ) | |
| continue-on-error: true | |
| # Known-bug tier: fail fast rather than wait the default 600s on a serve that | |
| # a bug prevents from becoming ready. | |
| env: | |
| E2E_SERVE_TIMEOUT_SECS: "90" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| # See e2e-gpu-strix-windows: bootstrap rustup via Windows PowerShell 5.1 | |
| # (`powershell`, not `pwsh`) because this runner has neither bash nor | |
| # PowerShell 7 for setup-rust-toolchain's internal script. | |
| - name: Ensure Rust toolchain (PowerShell) | |
| shell: powershell | |
| run: | | |
| if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) { | |
| Invoke-WebRequest https://win.rustup.rs/x86_64 -OutFile $env:TEMP\rustup-init.exe | |
| # --default-toolchain none: rust-toolchain.toml pins the exact | |
| # version (1.96.0 + components), auto-installed on first cargo use. | |
| & $env:TEMP\rustup-init.exe -y --default-toolchain none | |
| "$env:USERPROFILE\.cargo\bin" | Out-File -FilePath $env:GITHUB_PATH -Append | |
| } | |
| - name: Run known-bug E2E scenarios on Strix Halo Windows | |
| shell: powershell | |
| run: cargo xtask e2e --expect-failures -- -t "@gpu and @expected-failure" | |
| - name: Upload E2E report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-gpu-strix-windows-known-bugs-report | |
| path: tests/e2e-cucumber/results/ | |
| # Consolidate every platform/tier's report into ONE cross-platform report: | |
| # a platform × tier matrix in the run Summary plus a single merged HTML | |
| # artifact. `if: always()` so a failing/non-blocking platform still appears; | |
| # runs on GitHub-hosted ubuntu (no GPU needed — it only parses report.json). | |
| # | |
| # Extensibility: the report CONTENT auto-includes any new platform via the | |
| # `*-report` artifact glob below — no change needed here. The one manual step | |
| # when adding a platform is appending its two job names to `needs:` (for run | |
| # ORDERING only; GitHub Actions has no wildcard `needs`). A future matrix | |
| # refactor of the 8 e2e jobs would remove even that. | |
| e2e-report: | |
| name: E2E consolidated report | |
| runs-on: ubuntu-latest | |
| needs: | |
| - changes | |
| - e2e | |
| - e2e-known-bugs | |
| - e2e-gpu | |
| - e2e-gpu-known-bugs | |
| - e2e-gpu-strix-ubuntu | |
| - e2e-gpu-strix-ubuntu-known-bugs | |
| - e2e-gpu-strix-windows | |
| - e2e-gpu-strix-windows-known-bugs | |
| # Consolidate whatever ran. On dispatch `heavy` is unset, so also run when the | |
| # trigger was manual; `always()` still lets it collect partial/failed tiers. | |
| if: >- | |
| always() | |
| && (needs.changes.outputs.heavy == 'true' | |
| || github.event_name == 'workflow_dispatch') | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| # Pull every e2e artifact. Each extracts to e2e-artifacts/<artifact-name>/, | |
| # which `xtask e2e-report` turns into one labeled platform. The `*-report` | |
| # glob is what makes new platforms appear automatically. | |
| - name: Download all E2E reports | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: '*-report' | |
| path: e2e-artifacts | |
| - name: Build consolidated report + step summary | |
| run: | | |
| mkdir -p consolidated | |
| cargo xtask e2e-report \ | |
| --artifacts-dir e2e-artifacts \ | |
| --html-out consolidated/index.html >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload consolidated report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-consolidated-report | |
| path: consolidated/ |