From 045c8b39a712f30a72209aa479651949e555f7a0 Mon Sep 17 00:00:00 2001 From: aiongg <67543387+aiongg@users.noreply.github.com> Date: Fri, 23 Oct 2026 13:34:21 -0400 Subject: [PATCH] CI: nextest, line tables only, one wasm check (#4269) * CI speed: line tables for workspace crates, no debug info for dependencies * CI speed: xtask ci runs nextest and doctests, one wasm check, the CLI without default features --- Cargo.toml | 12 ++++++------ docs/architecture.md | 7 +++++-- docs/development.md | 13 ++++++++----- xtask/src/gates.rs | 35 ++++++++++++++++++++++++----------- xtask/src/main.rs | 9 +++++++-- 5 files changed, 50 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 92f51290d..2714debb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,20 +89,20 @@ dbg_macro = "warn" todo = "warn" # `"*"` matches every non-workspace package: crates.io dependencies and the -# vendored crates under `vendor/` (excluded from the workspace). Our own crates -# keep full debug info. Dependencies keep only line tables, so backtraces still -# show file and line, but debug info for the whole dependency graph stays out of -# every test binary (each UI test binary had a 500-600 MB PDB on Windows, #454). +# vendored crates under `vendor/` (excluded from the workspace). Dependencies +# carry no debug info and our own crates only line tables: backtraces and +# panics still show file and line, while test binaries and the target dir stay +# small (each UI test binary had a 500-600 MB PDB on Windows, #454). [profile.dev.package."*"] opt-level = 2 -debug = "line-tables-only" +debug = false [profile.dev] opt-level = 1 +debug = "line-tables-only" [profile.low-disk] inherits = "dev" -debug = "line-tables-only" incremental = false [profile.release] diff --git a/docs/architecture.md b/docs/architecture.md index 6b44817e1..c6b64da48 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # PdfCraft architecture -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; Windows CI passes) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-23 · **Change:** minor (xtask ci: nextest, one wasm check) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) How PdfCraft is built today. The design rationale and the planned crates live in `plan/architecture.md` and `plan/adr/` (local-only); this file describes what is on `main`. Each @@ -99,7 +99,9 @@ Every user-facing feature is reachable headlessly (`AGENTS.md` §3): ## Build and quality gates -`cargo xtask ci` runs fmt, clippy (`-D warnings`), tests, the layering check, the WASM check, +`cargo xtask ci` runs fmt, clippy (`-D warnings`), a check of `pdfcraft-cli` without default +features, the tests (`xtask test`: cargo-nextest when installed, else `cargo test`, then the +doctests), the layering check, the WASM check (one `cargo check` over every crate below L8), `xtask assets` (asset licences and hashes), `xtask parity` (checklist claims must cite real commands, tools and tests) and `xtask deny` (dependency licences). Other tasks: `xtask fuzz`, `xtask corpus` and `xtask check` (robustness sweep over the pinned pdf.js corpus), `xtask text-oracle` (word F1 and reading order against `pdftotext`), @@ -110,4 +112,5 @@ built by `.github/workflows/release.yml` ([releasing.md](releasing.md)). | Date | Change | Summary | |---|---|---| +| 2026-10-23 | minor | `xtask ci` runs nextest and doctests, checks the CLI without default features, and checks wasm in one call | | 2026-10-10 | major | Created from the code on main (crate list, `xtask/src/layers.rs`, crate READMEs, `vendor/README.md`) | diff --git a/docs/development.md b/docs/development.md index 1c6cce6a9..1142fed33 100644 --- a/docs/development.md +++ b/docs/development.md @@ -12,11 +12,14 @@ cargo build --profile low-disk -p pdfcraft-cli cargo test --profile low-disk -p pdfcraft-cos --lib ``` -The profile inherits the normal development settings, including debug assertions and overflow -checks. It uses line-table-only debug information for workspace code, which keeps file and line -numbers in backtraces but omits local-variable and parameter details, and it disables incremental -compilation for this profile only. Ordinary `cargo build`, `cargo test`, and release builds keep -their existing profiles. +The profile inherits the normal development settings, including debug assertions, overflow +checks and line-table-only debug information, and disables incremental compilation for this +profile only. Ordinary `cargo build` and `cargo test` keep incremental compilation. + +The development profile itself keeps only line tables for workspace code and no debug information +for dependencies. Backtraces show file and line numbers but no local variables or parameters; for +full debug information in workspace code (for a debugger), build with +`CARGO_PROFILE_DEV_DEBUG=true`. Cargo stores custom-profile artifacts separately under `target/low-disk`. Switching between the normal and low-disk profiles can therefore leave both sets of artifacts on disk. To remove only diff --git a/xtask/src/gates.rs b/xtask/src/gates.rs index 8e7db8cf0..f64ded099 100644 --- a/xtask/src/gates.rs +++ b/xtask/src/gates.rs @@ -78,20 +78,32 @@ pub fn wasm(_: &[String]) -> anyhow::Result<()> { .filter(|c| matches!(layers::classify(&c.name), Some(layers::Class::Layer(_) | layers::Class::Standalone(_)))) .map(|c| c.name) .collect(); - let mut failed = Vec::new(); + // One call over every crate: they share one dependency build, and `--keep-going` reports + // each failing crate instead of stopping at the first. + let mut c = cargo(); + c.args(["check", "--target", "wasm32-unknown-unknown", "--keep-going"]); for pkg in &set { - let mut c = cargo(); - c.args(["check", "--target", "wasm32-unknown-unknown", "-p", pkg]); - if run(c, &format!("cargo check --target wasm32-unknown-unknown -p {pkg}")).is_err() { - failed.push(pkg.clone()); - } + c.args(["-p", pkg]); } - if failed.is_empty() { - println!("wasm32: {} crates ok", set.len()); - Ok(()) + run(c, &format!("cargo check --target wasm32-unknown-unknown --keep-going ({} crates)", set.len()))?; + println!("wasm32: {} crates ok", set.len()); + Ok(()) +} + +/// The workspace tests. Unit and integration tests run under cargo-nextest when it is installed +/// (one process per test, so the run is not held up by its slowest binary), else under +/// `cargo test`; doctests run separately because nextest does not run them. Examples are left +/// out of the test build: clippy `--all-targets` already checks that they compile. +pub fn test(_: &[String]) -> anyhow::Result<()> { + let targets = ["--workspace", "--lib", "--bins", "--tests"]; + let nextest = cargo().args(["nextest", "--version"]).output().is_ok_and(|o| o.status.success()); + if nextest { + run_args(&[&["nextest", "run", "--no-fail-fast"][..], &targets].concat())?; } else { - bail!("wasm32 check failed for: {}", failed.join(", ")) + eprintln!("test: cargo-nextest is not installed, using cargo test (cargo install cargo-nextest --locked)"); + run_args(&[&["test", "--no-fail-fast"][..], &targets].concat())?; } + run_args(&["test", "--workspace", "--doc"]) } pub fn ci(_: &[String]) -> anyhow::Result<()> { @@ -99,7 +111,8 @@ pub fn ci(_: &[String]) -> anyhow::Result<()> { let steps: Vec = vec![ ("fmt", Box::new(|| run_args(&["fmt", "--all", "--", "--check"]))), ("clippy", Box::new(|| run_args(&["clippy", "--workspace", "--all-targets", "--", "-D", "warnings"]))), - ("test", Box::new(|| run_args(&["test", "--workspace"]))), + ("cli-no-default-features", Box::new(|| run_args(&["check", "-p", "pdfcraft-cli", "--no-default-features"]))), + ("test", Box::new(|| test(&[]))), ("layers", Box::new(|| layers(&[]))), ("wasm", Box::new(|| wasm(&[]))), ("assets", Box::new(|| crate::assets::run(&[]))), diff --git a/xtask/src/main.rs b/xtask/src/main.rs index f06c09944..442fcf8a4 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -19,9 +19,14 @@ type Command = fn(&[String]) -> anyhow::Result<()>; const COMMANDS: &[(&str, &str, Command)] = &[ ("version", "Print the workspace version, or `version set X.Y.Z[-pre]` to change it and refresh Cargo.lock", version_cmd), ("layers", "Enforce the crate dependency layering (plan/architecture.md §3)", gates::layers), - ("wasm", "cargo check --target wasm32-unknown-unknown for every crate below L8", gates::wasm), + ("wasm", "cargo check --target wasm32-unknown-unknown for every crate below L8, in one call", gates::wasm), ("deny", "Dependency licences, bans, sources and advisories (deny.toml; needs cargo-deny)", gates::deny), - ("ci", "fmt --check, clippy -D warnings, test, layers, wasm, assets, deny, parity (stops at first failure)", gates::ci), + ( + "ci", + "fmt --check, clippy -D warnings, the CLI without default features, test, layers, wasm, assets, deny, parity (stops at first failure)", + gates::ci, + ), + ("test", "Workspace tests: cargo nextest (cargo test when it is missing), then doctests", gates::test), ("assets", "Enforce the asset policy (AGENTS.md §1) against ATTRIBUTION.toml; --write regenerates ATTRIBUTION.md", assets::run), ("corpus", "Fetch the pinned pdf.js test corpus into corpus/ (git-ignored) and verify it; --update-pin re-records the pin", gates::corpus), ("check", "Robustness sweep over corpus/ with pdfcraft-cli; fails on crashes or regressions vs xtask/baselines", gates::check),