mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-06 20:02:16 +00:00
02e1f18412
A plan job (scripts/ci/kernel_rig_plan.py, with its self-test) maps a pull request's changed files to the areas: tests/kernel-cases/<area>/PATHS for each area, tests/kernel-cases/PATHS-ALL for the shared core, the ladder whenever any area runs. Areas come from the folders, so a new one needs no workflow edit. Pushes, merge groups, the release gate and runs by hand run every area. The kernel-rig check counts a skipped build or shard as passed only when the plan selected none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
235 lines
10 KiB
YAML
235 lines
10 KiB
YAML
# The kernel rig and the complexity ladder as a regression gate. A plan job maps a pull request's
|
|
# changed files to the rig areas they can affect (scripts/ci/kernel_rig_plan.py): an area runs
|
|
# when a file its tests/kernel-cases/<area>/PATHS lists changes, or one of its cases; every area
|
|
# runs when the shared core in tests/kernel-cases/PATHS-ALL changes; the ladder runs whenever any
|
|
# area does. One job then builds solidcraft-cli once (release, SMLib prebuilt), checks that every
|
|
# registry command has a case or an exemption (tests/kernel-cases/EXEMPT), and hands the CLI to a
|
|
# matrix of shards as an artifact, one per selected area plus the ladder, in parallel, so the
|
|
# wall time is the build plus the slowest shard. See tests/kernel-cases/README.md.
|
|
#
|
|
# - An area fails on a regression (a case that fails and its tests/kernel-cases/<area>/KNOWN_FAILING
|
|
# does not list) or on a listed case that passes (it is fixed: remove its line in the same pull
|
|
# request, so the list only shrinks).
|
|
# - The ladder fails on any case whose status or counts differ from
|
|
# tests/kernel-cases/ladder/golden.json; a right change is re-recorded (`--record "why"`).
|
|
#
|
|
# The trigger paths are whole folders that hold every area's PATHS (a self-test,
|
|
# scripts/ci/test_kernel_rig_plan.py, checks they do), so a pull request that touches none of
|
|
# them (the UI, docs, packaging) starts no runner at all, and a new area needs no edit here: the
|
|
# plan finds the areas from the folders. Pushes to main and develop on the same paths, merge groups
|
|
# (once the queue is on), the release gate (release-gate.yml, workflow_call) and a run by hand run
|
|
# every area; those pushes also commit the compiler cache (a Blacksmith sticky disk) that every
|
|
# other run mounts read-only.
|
|
name: Kernel rig
|
|
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize, reopened, ready_for_review]
|
|
paths:
|
|
- "crates/kernel/**"
|
|
- "crates/geom/**"
|
|
- "crates/smlib/**"
|
|
- "crates/step/**"
|
|
- "crates/io/src/**"
|
|
- "crates/doc/src/**"
|
|
- "crates/engine/src/**"
|
|
- "tests/kernel-cases/**"
|
|
# The rig itself: the grading, the runner, the selection and this workflow.
|
|
- "apps/solidcraft-cli/src/kernel_cases.rs"
|
|
- "xtask/src/kernel_cases.rs"
|
|
- "xtask/src/kernel_ladder.rs"
|
|
- "scripts/fetch-smlib.sh"
|
|
- "scripts/ci/kernel_rig_plan.py"
|
|
- "scripts/ci/test_kernel_rig_plan.py"
|
|
- ".github/workflows/kernel-rig.yml"
|
|
push:
|
|
branches: [main, develop]
|
|
# The same paths as pull_request.
|
|
paths:
|
|
- "crates/kernel/**"
|
|
- "crates/geom/**"
|
|
- "crates/smlib/**"
|
|
- "crates/step/**"
|
|
- "crates/io/src/**"
|
|
- "crates/doc/src/**"
|
|
- "crates/engine/src/**"
|
|
- "tests/kernel-cases/**"
|
|
# The rig itself: the grading, the runner, the selection and this workflow.
|
|
- "apps/solidcraft-cli/src/kernel_cases.rs"
|
|
- "xtask/src/kernel_cases.rs"
|
|
- "xtask/src/kernel_ladder.rs"
|
|
- "scripts/fetch-smlib.sh"
|
|
- "scripts/ci/kernel_rig_plan.py"
|
|
- "scripts/ci/test_kernel_rig_plan.py"
|
|
- ".github/workflows/kernel-rig.yml"
|
|
merge_group:
|
|
workflow_call:
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
# A new push to a pull request replaces its old run.
|
|
group: kernel-rig-${{ github.event_name }}-${{ github.ref }}
|
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
|
|
jobs:
|
|
plan:
|
|
name: Select the rig areas
|
|
# Draft pull requests run no CI, as in ci.yml.
|
|
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
|
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
|
timeout-minutes: 5
|
|
outputs:
|
|
# The shard matrix (JSON list of areas and the ladder; [] when nothing is selected).
|
|
shards: ${{ steps.plan.outputs.shards }}
|
|
# Whether the build job, and with it the coverage check, runs.
|
|
build: ${{ steps.plan.outputs.build }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
# A pull request's diff needs its base's history.
|
|
fetch-depth: ${{ github.event_name == 'pull_request' && '0' || '1' }}
|
|
- name: Selection self-test
|
|
run: python3 -I scripts/ci/test_kernel_rig_plan.py
|
|
- id: plan
|
|
name: Map the changed files to areas
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
run: |
|
|
# Pull requests run the areas their diff reaches; pushes, merge groups, the release
|
|
# gate and a run by hand run every area.
|
|
if [ "$EVENT_NAME" = pull_request ]; then
|
|
git diff --no-renames --name-only -z "$BASE_SHA...$HEAD_SHA" > "$RUNNER_TEMP/rig-paths"
|
|
python3 -I scripts/ci/kernel_rig_plan.py --paths "$RUNNER_TEMP/rig-paths" --github-output "$GITHUB_OUTPUT"
|
|
else
|
|
python3 -I scripts/ci/kernel_rig_plan.py --all --github-output "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
build:
|
|
name: Build the CLI
|
|
needs: plan
|
|
if: needs.plan.outputs.build == 'true'
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
timeout-minutes: 60
|
|
env:
|
|
CARGO_INCREMENTAL: "0"
|
|
RUSTC_WRAPPER: sccache
|
|
SCCACHE_DIR: /home/runner/.cache/sccache
|
|
SCCACHE_CACHE_SIZE: 10G
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
- name: Size parallel compiles to the job's memory
|
|
run: scripts/ci/build-jobs.sh
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
# Only pushes to main and develop commit the cache; pull requests, merge groups and forks
|
|
# mount a clone and never write back.
|
|
- name: Mount the compiler cache
|
|
uses: useblacksmith/stickydisk@3f6be1451e3cad893b778bc93495c80452a5da26 # v1.7.2
|
|
continue-on-error: true
|
|
with:
|
|
key: ${{ github.repository }}-sccache-kernel-rig
|
|
path: /home/runner/.cache/sccache
|
|
commit: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') && 'on-change' || 'false' }}
|
|
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
|
with:
|
|
key: kernel-rig
|
|
save-if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') }}
|
|
- name: Fetch SMLib (crates/smlib/SMLIB_REV)
|
|
shell: bash
|
|
run: scripts/fetch-smlib.sh
|
|
- name: Set up compiler cache
|
|
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
with:
|
|
version: v0.16.0
|
|
- name: Build the CLI (release, SMLib) and the rig's runner
|
|
run: |
|
|
cargo build --release --locked -p solidcraft-cli --features smlib
|
|
cargo build --locked -p xtask
|
|
# A tar keeps the executable bits, which an artifact drops. xtask finds the repository from
|
|
# the path it was built in (CARGO_MANIFEST_DIR), which is the same checkout path in every
|
|
# job of this workflow.
|
|
# Every registry command is used by a case or listed in tests/kernel-cases/EXEMPT.
|
|
- name: Every command has a case
|
|
run: target/debug/xtask kernel-cases --coverage --cli target/release/solidcraft-cli
|
|
# A coverage-only run (the registry or the cases changed, no area selected) runs no shard.
|
|
- name: Pack the binaries
|
|
if: needs.plan.outputs.shards != '[]'
|
|
run: tar -cf "$RUNNER_TEMP/kernel-rig-bin.tar" -C target release/solidcraft-cli debug/xtask
|
|
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
if: needs.plan.outputs.shards != '[]'
|
|
with:
|
|
name: kernel-rig-bin
|
|
path: ${{ runner.temp }}/kernel-rig-bin.tar
|
|
retention-days: 1
|
|
- name: Compiler cache statistics
|
|
if: always()
|
|
run: sccache --show-stats
|
|
|
|
shard:
|
|
name: Kernel rig (${{ matrix.shard }})
|
|
needs: [plan, build]
|
|
if: needs.plan.outputs.shards != '[]'
|
|
runs-on: blacksmith-4vcpu-ubuntu-2404
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# The areas of tests/kernel-cases/ the plan selected, and the ladder. On the build box
|
|
# (aarch64, 4 cases at a time) the slowest areas took about 1 minute (booleans, 212 s of
|
|
# cases with one of 84 s; threads, 161 s) and the ladder, one case at a time, 92 s: no area
|
|
# needs splitting.
|
|
shard: ${{ fromJSON(needs.plan.outputs.shards) }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
with:
|
|
name: kernel-rig-bin
|
|
path: ${{ runner.temp }}
|
|
- name: Unpack the binaries
|
|
run: mkdir -p target && tar -xf "$RUNNER_TEMP/kernel-rig-bin.tar" -C target
|
|
- name: Run the cases against the known-failing list (the ladder against its golden)
|
|
env:
|
|
SHARD: ${{ matrix.shard }}
|
|
run: |
|
|
if [ "$SHARD" = ladder ]; then
|
|
set -- --ladder --gate
|
|
else
|
|
set -- --area "$SHARD" --known-failing "tests/kernel-cases/$SHARD/KNOWN_FAILING"
|
|
fi
|
|
target/debug/xtask kernel-cases "$@" --cli target/release/solidcraft-cli --out "$RUNNER_TEMP/kernel-rig"
|
|
- name: Keep the results
|
|
if: always()
|
|
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
with:
|
|
name: kernel-rig-results-${{ matrix.shard }}
|
|
path: ${{ runner.temp }}/kernel-rig/results.json
|
|
if-no-files-found: ignore
|
|
|
|
# One check for the whole gate, for branch protection and the merge queue.
|
|
kernel-rig:
|
|
name: kernel-rig
|
|
needs: [plan, build, shard]
|
|
if: always() && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
|
steps:
|
|
# A skipped build or shard counts as passed only when the plan selected none.
|
|
- name: Every selected job passed
|
|
env:
|
|
PLAN: ${{ needs.plan.result }}
|
|
WANT_BUILD: ${{ needs.plan.outputs.build }}
|
|
WANT_SHARDS: ${{ needs.plan.outputs.shards }}
|
|
BUILD: ${{ needs.build.result }}
|
|
SHARDS: ${{ needs.shard.result }}
|
|
run: |
|
|
echo "plan=$PLAN build=$BUILD shards=$SHARDS selected=$WANT_SHARDS"
|
|
test "$PLAN" = success
|
|
if [ "$WANT_BUILD" = true ]; then test "$BUILD" = success; else test "$BUILD" = skipped; fi
|
|
if [ "$WANT_SHARDS" != '[]' ]; then test "$SHARDS" = success; else test "$SHARDS" = skipped; fi
|