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 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-15 13:24:45 -04:00
1 parent 840b4b7dc5
commit 21072a23de
7 files changed
+27 -25

No files matched your search

+1
View File
@@ -7,3 +7,4 @@
.DS_Store .DS_Store
*.swp *.swp
__pycache__/ __pycache__/
/THIRD-PARTY-LICENSES.txt
+2 -2
View File
@@ -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. 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 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 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 `cargo xtask ci` (fmt, assets, layers, clippy -D warnings, tests, wasm), the
oracle, the heavy tests and the advisories once per merge on `develop`; the coordinator 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 watches it and sends a failure back to the change that caused it, which is fixed forward
at once. at once.
- **Keep the trunk gate fast** (under ~3 minutes on CI). A test that takes more than a few seconds - **Keep the trunk gate fast** (under ~3 minutes on CI). A test that takes more than a few seconds
+1 -1
View File
@@ -6,7 +6,7 @@ Licensed under the MIT License or the Apache License, Version 2.0, at your optio
Third-party material Third-party material
Software dependencies are listed in Cargo.lock; their licences are in THIRD-PARTY-LICENSES.txt 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, 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. Copyright (c) RICOS Co. Ltd.), some with SolidCraft's modifications.
+3 -2
View File
@@ -114,7 +114,7 @@ against a closed form or a reference solution ([docs/examples.md](docs/examples.
## Build ## Build
```sh ```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 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 -- commands # every command and its parameters
cargo run -p fieldcraft-cli -- run script.json # run a command script 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 ## License
Dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option. Notices 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 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 Systèmes, MSC Software, Siemens or Ansys. Abaqus, Nastran, MSC Nastran, Simcenter Nastran and
+4
View File
@@ -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 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`, 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`). `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` 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 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, `assets/app-icon`: `icon.icns` and `Assets.car` (macOS 26 and later) in the app bundle,
+12 -14
View File
@@ -1,8 +1,8 @@
//! `cargo xtask licences [--check]`: THIRD-PARTY-LICENSES.txt, the licences of every crate built //! `cargo xtask licences`: THIRD-PARTY-LICENSES.txt, the licences of every crate built into the
//! into the shipped programs (fieldcraft, fieldcraft-cli, fieldcraft-web), read from //! shipped programs (fieldcraft, fieldcraft-cli, fieldcraft-web), read from `cargo metadata` and
//! `cargo metadata` and the crates' own licence files, so a release download can carry them. //! the crates' own licence files. The release workflow generates it before packaging, so every
//! `--check` (part of `cargo xtask ci`) fails when the committed file is out of date, e.g. after a //! download carries it; it is not committed. Which licences are allowed is cargo-deny's
//! dependency changed. //! `[licenses]` policy (deny.toml), checked on every pull request.
use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::path::Path; use std::path::Path;
@@ -14,17 +14,9 @@ use crate::cargo;
pub const FILE: &str = "THIRD-PARTY-LICENSES.txt"; pub const FILE: &str = "THIRD-PARTY-LICENSES.txt";
const ROOTS: &[&str] = &["fieldcraft", "fieldcraft-cli", "fieldcraft-web"]; 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 text = generate()?;
let path = root.join(FILE); 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()))?; std::fs::write(&path, &text).map_err(|e| format!("{}: {e}", path.display()))?;
println!("licences: wrote {FILE} ({} KB)", text.len() / 1024); println!("licences: wrote {FILE} ({} KB)", text.len() / 1024);
Ok(()) Ok(())
@@ -87,6 +79,12 @@ fn generate() -> Result<String, String> {
}); });
} }
crates.sort_by(|a, b| (&a.name, &a.version).cmp(&(&b.name, &b.version))); 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<String> =
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)) Ok(render(&crates))
} }
+4 -6
View File
@@ -27,9 +27,8 @@ commands:
app-icon draw the application icon family (assets/app-icon) with VectorCraft, then app-icon draw the application icon family (assets/app-icon) with VectorCraft, then
write the iconset, icns, ico and Icon Composer document (macOS: sips, write the iconset, icns, ico and Icon Composer document (macOS: sips,
iconutil, magick; actool for Assets.car when available) iconutil, magick; actool for Assets.car when available)
licences [--check] licences write THIRD-PARTY-LICENSES.txt (the licences of every shipped crate; the
write THIRD-PARTY-LICENSES.txt (the licences of every shipped crate); release workflow runs it before packaging, the file is not committed)
--check fails when it is out of date
test [--heavy] [CARGO ARGS] [-- TEST ARGS] test [--heavy] [CARGO ARGS] [-- TEST ARGS]
build the tests with the ci profile, then run every test binary at once; 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 --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 --bless freezes a passing case's results in its fixture.json; --quick skips
cases marked slow (release build) cases marked slow (release build)
wasm cargo check every library crate and the web app for wasm32-unknown-unknown 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 (not the heavy ones) with the wasm check alongside (stops at the first failing
step) step)
"; ";
@@ -57,7 +56,7 @@ fn main() -> ExitCode {
Some("assets") => assets::run(&root()), Some("assets") => assets::run(&root()),
Some("icons") => icons::run(&root(), &rest), Some("icons") => icons::run(&root(), &rest),
Some("app-icon") => app_icon::run(&root()), Some("app-icon") => app_icon::run(&root()),
Some("licences") => licences::run(&root(), rest.contains(&"--check")), Some("licences") => licences::run(&root()),
Some("test") => { Some("test") => {
let (heavy, rest) = match rest.split_first() { let (heavy, rest) = match rest.split_first() {
Some((&"--heavy", after)) => (true, after), Some((&"--heavy", after)) => (true, after),
@@ -200,7 +199,6 @@ fn cmd_ci() -> Result<(), String> {
c.args(["fmt", "--all", "--", "--check"]); c.args(["fmt", "--all", "--", "--check"]);
run(c, "cargo fmt --check")?; run(c, "cargo fmt --check")?;
assets::run(&root())?; assets::run(&root())?;
licences::run(&root(), true)?;
cmd_layers()?; cmd_layers()?;
let mut c = cargo(); let mut c = cargo();
c.args(["clippy", "--workspace", "--all-targets", "--profile", "ci", "--", "-D", "warnings"]); c.args(["clippy", "--workspace", "--all-targets", "--profile", "ci", "--", "-D", "warnings"]);