From 21072a23ded40ece65a40a24c8724da0ea592c62 Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Thu, 15 Oct 2026 12:55:08 -0400 Subject: [PATCH] xtask: drop the licences --check gate; THIRD-PARTY-LICENSES.txt is a release artifact The file is no longer committed: dependency pull requests from forks failed CI only because it was out of date. The Dependabot workflow that regenerated it is gone. licences now fails when a shipped crate names no licence and carries no licence file. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo --- .gitignore | 1 + AGENTS.md | 4 ++-- NOTICE | 2 +- README.md | 5 +++-- docs/releasing.md | 4 ++++ xtask/src/licences.rs | 26 ++++++++++++-------------- xtask/src/main.rs | 10 ++++------ 7 files changed, 27 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 86f89c9..25dea3d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ .DS_Store *.swp __pycache__/ +/THIRD-PARTY-LICENSES.txt diff --git a/AGENTS.md b/AGENTS.md index ea9963b..3d0c8f9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -120,8 +120,8 @@ People trust FieldCraft with their models; a crash loses their work. **This outr Then remove your worktree and delete your local branch. 5. Never run the full gate locally: no `cargo xtask ci`, no `cargo clippy --workspace`, no `cargo xtask wasm` or `oracle` unless step 2 calls for it. Never watch CI. GitHub CI runs - `cargo xtask ci` (fmt, assets, licences, layers, clippy -D warnings, tests, wasm), the - oracle, the heavy tests and the advisories once per merge on `develop`; the coordinator + `cargo xtask ci` (fmt, assets, layers, clippy -D warnings, tests, wasm), the + oracle, the heavy tests and the dependency licences and advisories once per merge on `develop`; the coordinator watches it and sends a failure back to the change that caused it, which is fixed forward at once. - **Keep the trunk gate fast** (under ~3 minutes on CI). A test that takes more than a few seconds diff --git a/NOTICE b/NOTICE index 7f0a070..30fa325 100644 --- a/NOTICE +++ b/NOTICE @@ -6,7 +6,7 @@ Licensed under the MIT License or the Apache License, Version 2.0, at your optio Third-party material Software dependencies are listed in Cargo.lock; their licences are in THIRD-PARTY-LICENSES.txt -(`cargo xtask licences`). Geometry comes from SolidCraft (https://github.com/bherbruck/solidcraft, +(generated by `cargo xtask licences`, in every release package). Geometry comes from SolidCraft (https://github.com/bherbruck/solidcraft, MIT OR Apache-2.0), which builds on the truck crates (https://github.com/ricosjp/truck, Apache-2.0, Copyright (c) RICOS Co. Ltd.), some with SolidCraft's modifications. diff --git a/README.md b/README.md index d70797c..5dcb0d4 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ against a closed form or a reference solution ([docs/examples.md](docs/examples. ## Build ```sh -cargo xtask ci # fmt, assets, licences, layers, clippy, tests, wasm +cargo xtask ci # fmt, assets, layers, clippy, tests, wasm cargo xtask test --heavy # the heavy (ignored) tests and the doc tests cargo run -p fieldcraft-cli -- commands # every command and its parameters cargo run -p fieldcraft-cli -- run script.json # run a command script @@ -148,7 +148,8 @@ you review and submit yourself, with your session or model attached only if you ## License Dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option. Notices -are in [NOTICE](NOTICE); third-party licences in [THIRD-PARTY-LICENSES.txt](THIRD-PARTY-LICENSES.txt). +are in [NOTICE](NOTICE); third-party licences in +THIRD-PARTY-LICENSES.txt, which every release package carries (`cargo xtask licences` writes it). FieldCraft is an independent project, not affiliated with, sponsored or endorsed by Dassault Systèmes, MSC Software, Siemens or Ansys. Abaqus, Nastran, MSC Nastran, Simcenter Nastran and diff --git a/docs/releasing.md b/docs/releasing.md index aa8c96a..69274ee 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -17,6 +17,10 @@ are in `packaging/` and run the same way on a developer machine. Plus `SHA256SUMS.txt`, its signature `SHA256SUMS.txt.minisig` (below), and the notes from `.github/release-notes.md` followed by GitHub's generated list of changes. Every package carries `README.md`, `LICENSE-MIT`, `LICENSE-APACHE`, `NOTICE` and `THIRD-PARTY-LICENSES.txt` (on macOS in `FieldCraft.app/Contents/Resources/Licenses`). +`THIRD-PARTY-LICENSES.txt` is not committed: each packaging job runs `cargo xtask licences` first, +which fails when a shipped crate names no licence and carries no licence file, and the release +attaches the file on its own too. Which licences a dependency may have is `[licenses]` in +`deny.toml`, which CI checks on every pull request (`cargo deny check licenses`). The application id is `io.github.jyviko.fieldcraft`: the macOS bundle id, the Linux `.desktop` entry and icon name, and the window's Wayland app_id / X11 class. The icons come from `assets/app-icon`: `icon.icns` and `Assets.car` (macOS 26 and later) in the app bundle, diff --git a/xtask/src/licences.rs b/xtask/src/licences.rs index d497615..d761ae8 100644 --- a/xtask/src/licences.rs +++ b/xtask/src/licences.rs @@ -1,8 +1,8 @@ -//! `cargo xtask licences [--check]`: THIRD-PARTY-LICENSES.txt, the licences of every crate built -//! into the shipped programs (fieldcraft, fieldcraft-cli, fieldcraft-web), read from -//! `cargo metadata` and the crates' own licence files, so a release download can carry them. -//! `--check` (part of `cargo xtask ci`) fails when the committed file is out of date, e.g. after a -//! dependency changed. +//! `cargo xtask licences`: THIRD-PARTY-LICENSES.txt, the licences of every crate built into the +//! shipped programs (fieldcraft, fieldcraft-cli, fieldcraft-web), read from `cargo metadata` and +//! the crates' own licence files. The release workflow generates it before packaging, so every +//! download carries it; it is not committed. Which licences are allowed is cargo-deny's +//! `[licenses]` policy (deny.toml), checked on every pull request. use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::path::Path; @@ -14,17 +14,9 @@ use crate::cargo; pub const FILE: &str = "THIRD-PARTY-LICENSES.txt"; const ROOTS: &[&str] = &["fieldcraft", "fieldcraft-cli", "fieldcraft-web"]; -pub fn run(root: &Path, check: bool) -> Result<(), String> { +pub fn run(root: &Path) -> Result<(), String> { let text = generate()?; let path = root.join(FILE); - if check { - let old = std::fs::read_to_string(&path).unwrap_or_default(); - if old.replace("\r\n", "\n") != text { - return Err(format!("{FILE} is out of date (dependencies changed): run `cargo xtask licences` and commit it")); - } - println!("licences: {FILE} is up to date"); - return Ok(()); - } std::fs::write(&path, &text).map_err(|e| format!("{}: {e}", path.display()))?; println!("licences: wrote {FILE} ({} KB)", text.len() / 1024); Ok(()) @@ -87,6 +79,12 @@ fn generate() -> Result { }); } crates.sort_by(|a, b| (&a.name, &a.version).cmp(&(&b.name, &b.version))); + // A package must say what its licence is: a release never ships a crate it cannot account for. + let unresolved: Vec = + crates.iter().filter(|c| c.license.is_empty() && c.files.is_empty()).map(|c| format!("{} {}", c.name, c.version)).collect(); + if !unresolved.is_empty() { + return Err(format!("no licence (Cargo.toml `license` or a licence file) for: {}", unresolved.join(", "))); + } Ok(render(&crates)) } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 0157abb..9cfced8 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -27,9 +27,8 @@ commands: app-icon draw the application icon family (assets/app-icon) with VectorCraft, then write the iconset, icns, ico and Icon Composer document (macOS: sips, iconutil, magick; actool for Assets.car when available) - licences [--check] - write THIRD-PARTY-LICENSES.txt (the licences of every shipped crate); - --check fails when it is out of date + licences write THIRD-PARTY-LICENSES.txt (the licences of every shipped crate; the + release workflow runs it before packaging, the file is not committed) test [--heavy] [CARGO ARGS] [-- TEST ARGS] build the tests with the ci profile, then run every test binary at once; --heavy runs only the ignored tests instead (heavy verification and corpus @@ -44,7 +43,7 @@ commands: --bless freezes a passing case's results in its fixture.json; --quick skips cases marked slow (release build) wasm cargo check every library crate and the web app for wasm32-unknown-unknown - ci fmt --check, assets, licences --check, layers, clippy -D warnings, then the tests + ci fmt --check, assets, layers, clippy -D warnings, then the tests (not the heavy ones) with the wasm check alongside (stops at the first failing step) "; @@ -57,7 +56,7 @@ fn main() -> ExitCode { Some("assets") => assets::run(&root()), Some("icons") => icons::run(&root(), &rest), Some("app-icon") => app_icon::run(&root()), - Some("licences") => licences::run(&root(), rest.contains(&"--check")), + Some("licences") => licences::run(&root()), Some("test") => { let (heavy, rest) = match rest.split_first() { Some((&"--heavy", after)) => (true, after), @@ -200,7 +199,6 @@ fn cmd_ci() -> Result<(), String> { c.args(["fmt", "--all", "--", "--check"]); run(c, "cargo fmt --check")?; assets::run(&root())?; - licences::run(&root(), true)?; cmd_layers()?; let mut c = cargo(); c.args(["clippy", "--workspace", "--all-targets", "--profile", "ci", "--", "-D", "warnings"]);