From a75a4143107c6208645741d0b72e92bb5eade434 Mon Sep 17 00:00:00 2001 From: aiongg Date: Fri, 23 Oct 2026 19:29:31 +0000 Subject: [PATCH] CI: cargo xtask ci is the gate, and the workflow runs it --- .github/workflows/ci.yml | 46 +++++----------------------------------- docs/development.md | 2 +- xtask/src/main.rs | 46 +++++++++++++++++++++++++++++++++++----- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf1a9c04a5..df23bef706 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,8 @@ name: CI # Quality gates for every push to main and every pull request. The Linux gate runs through the -# suite's shared gate workflow in craft-common-actions; the Windows legs, the test variants and -# the corpus, wasm, web and fuzz jobs are PhotoCraft's own. +# suite's shared gate workflow in craft-common-actions (`cargo xtask ci`); the Windows legs, the +# test variant and the corpus, web and fuzz jobs are PhotoCraft's own. on: push: branches: [main] @@ -126,31 +126,15 @@ jobs: # The tests build with the optional craft-fonts input (crates/text/build.rs), so the # Japanese font tests that skip without it run. Same commit as release.yml. craft-fonts-ref: abb83316d96aa59c1cf64784289e378fe9fa5695 - # The wasm32 build is its own job. - targets: "" # Cargo.toml's dev profile already keeps line tables only. dev-debug: "" env: | PHOTOCRAFT_NO_PRINT=1 LPDEST=photocraft-no-such-printer timeout-minutes: 100 - # `--features heif`: official builds open HEIC photos via the optional photocraft-heif crate. - # `--lib --bins --tests` leaves out the examples, which cargo test would build and link but - # never run (Clippy's `--all-targets` still checks they compile). nextest skips doctests, so - # they run last. The `ci` profile fails fast and terminates hung tests (.config/nextest.toml). - # docs/scorecard.md must match its sources; the check reads committed files only. - # panic_hunt: every command against adversarial params must return Err, never panic or hang - # (AGENTS.md Rule 9). It is `#[ignore]`d (slow), so the test run skips it; the same packages, - # features and targets keep it from rebuilding anything. - command: | - cargo fmt --all -- --check - cargo clippy --workspace --all-targets --locked --features heif -- -D warnings - cargo xtask layers - cargo xtask scorecard --check - cargo nextest run --profile ci --workspace --locked --features heif --lib --bins --tests - cargo nextest run --profile ci --workspace --locked --features heif --lib --bins --tests \ - --run-ignored only -E 'binary_id(photocraft-engine::panic_hunt)' - cargo test --workspace --locked --features heif --doc + # fmt, clippy, layers, scorecard, tests, panic_hunt, doctests and the wasm32 check, with + # `--locked --features heif` (xtask/src/main.rs). + command: cargo xtask ci # Windows tests run as two legs in parallel: the unit tests and the integration tests. As one job # they took ~28 min on the Windows runner; the legs take ~13 and ~15. Splitting the integration @@ -316,26 +300,6 @@ jobs: - name: Corpus tests run: cargo xtask test-corpus - wasm: - if: github.event.action != 'labeled' || github.event.label.name == 'full-ci' - timeout-minutes: 30 - name: wasm32 check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable - with: - targets: wasm32-unknown-unknown - - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - with: - key: wasm32 - save-if: ${{ github.ref == 'refs/heads/main' }} - cache-on-failure: true - - name: Check wasm-safe crates - run: cargo xtask wasm - web: timeout-minutes: 60 name: web build and wasm size gate diff --git a/docs/development.md b/docs/development.md index 4b47202d8e..fb61b4a660 100644 --- a/docs/development.md +++ b/docs/development.md @@ -40,7 +40,7 @@ cargo run --release -p photocraft -- --control 7878 --control-token-file .privat --automation-read-root work --automation-write-root work cargo test --workspace # everything cargo xtask test # tests (nextest when installed) + doctests -cargo xtask ci # fmt + clippy + tests + doctests + layers + wasm +cargo xtask ci # the CI gate: fmt, clippy, layers, scorecard, tests, panic_hunt, doctests, wasm cargo xtask stats # tests and lines per crate cargo xtask parity # Photoshop menu coverage -> docs/parity-checklist.md ``` diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 0f40543829..ad603238f4 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -26,7 +26,9 @@ commands: wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates (one call, plus one per optional web feature) test workspace tests (cargo nextest when installed, else cargo test), then doctests - ci fmt --check, clippy -D warnings, test, doctest, layers, wasm (stops at first failure) + ci the CI gate: fmt --check, clippy -D warnings, layers, scorecard --check, tests + (nextest --profile ci), panic_hunt, doctests and wasm, with --locked --features heif + (stops at first failure) corpus [--all | --pngsuite | --psd | --psd-tools | --pixls | --atn | --photoshop | --gimp] [--local] [--update-manifest] show where test corpora live and their pins (xtask/src/corpus_pins.rs), or fetch them into corpus/ (pinned commits, sha256-verified; --all = every corpus but pixls, @@ -213,6 +215,31 @@ fn cmd_test() -> Result<(), String> { run(c, &format!("cargo {tool} {}", TEST_TARGETS.join(" "))) } +/// What the CI gate adds to every build: `--locked`, and the optional photocraft-heif crate that +/// official builds open HEIC photos with. +const GATE_ARGS: [&str; 4] = ["--workspace", "--locked", "--features", "heif"]; + +/// The gate's tests. nextest's `ci` profile stops at the first failure and terminates hung tests +/// (.config/nextest.toml). `panic_hunt` runs only the engine's `#[ignore]`d panic hunt (AGENTS.md +/// Rule 9) with the same packages, features and targets as the tests, so nothing rebuilds. +fn cmd_gate_tests(panic_hunt: bool) -> Result<(), String> { + let mut c = cargo(); + if nextest_available() { + c.args(["nextest", "run", "--profile", "ci"]).args(GATE_ARGS).args(&TEST_TARGETS[1..]); + if panic_hunt { + c.args(["--run-ignored", "only", "-E", "binary_id(photocraft-engine::panic_hunt)"]); + } + } else if panic_hunt { + // `-- --ignored` across the workspace would run every ignored test, not only the hunt. + c.args(["test", "-p", "photocraft-engine", "--locked", "--test", "panic_hunt", "--", "--ignored"]); + } else { + eprintln!("note: cargo-nextest is not installed, running cargo test (cargo install cargo-nextest --locked)"); + c.arg("test").args(GATE_ARGS).args(&TEST_TARGETS[1..]); + } + let what = format!("cargo {}", c.get_args().map(|a| a.to_string_lossy()).collect::>().join(" ")); + run(c, &what) +} + /// nextest does not run doctests. fn cmd_doctest() -> Result<(), String> { let mut c = cargo(); @@ -241,13 +268,22 @@ fn cmd_ci() -> Result<(), String> { "clippy", Box::new(|| { let mut c = cargo(); - c.args(["clippy", "--workspace", "--all-targets", "--keep-going", "--", "-D", "warnings"]); - run(c, "cargo clippy --workspace --all-targets --keep-going -- -D warnings") + c.arg("clippy").args(GATE_ARGS).args(["--all-targets", "--keep-going", "--", "-D", "warnings"]); + run(c, "cargo clippy --workspace --locked --features heif --all-targets --keep-going -- -D warnings") }), ), - ("test", Box::new(cmd_test)), - ("doctest", Box::new(cmd_doctest)), ("layers", Box::new(cmd_layers)), + ("scorecard", Box::new(|| scorecard::run(&root(), &["--check"]))), + ("test", Box::new(|| cmd_gate_tests(false))), + ("panic_hunt", Box::new(|| cmd_gate_tests(true))), + ( + "doctest", + Box::new(|| { + let mut c = cargo(); + c.arg("test").args(GATE_ARGS).arg("--doc"); + run(c, "cargo test --workspace --locked --features heif --doc") + }), + ), ("wasm", Box::new(cmd_wasm)), ]; let mut done = Vec::new();