From a4003184f5b5d4c11dc3375286d3d6e1f506e709 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 00:54:26 +0200 Subject: [PATCH 1/8] chore(release): bump the workspace to 0.6.1 0.6.0 cannot be reused: rustmotion-core 0.6.0 reached crates.io before the run failed, and a published version is permanent. Moving every crate to 0.6.1 keeps the four in lockstep and leaves no version half-taken. --- Cargo.lock | 12 ++++++------ crates/rustmotion-cli/Cargo.toml | 2 +- crates/rustmotion-components/Cargo.toml | 4 ++-- crates/rustmotion-core/Cargo.toml | 2 +- crates/rustmotion-html/Cargo.toml | 2 +- crates/rustmotion-studio/Cargo.toml | 2 +- crates/rustmotion/Cargo.toml | 8 ++++---- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4aeb045..061d4b02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5051,7 +5051,7 @@ dependencies = [ [[package]] name = "rustmotion" -version = "0.6.0" +version = "0.6.1" dependencies = [ "gif 0.13.3", "image", @@ -5079,7 +5079,7 @@ dependencies = [ [[package]] name = "rustmotion-cli" -version = "0.6.0" +version = "0.6.1" dependencies = [ "clap", "clap_complete", @@ -5098,7 +5098,7 @@ dependencies = [ [[package]] name = "rustmotion-components" -version = "0.6.0" +version = "0.6.1" dependencies = [ "dashmap", "gif 0.13.3", @@ -5119,7 +5119,7 @@ dependencies = [ [[package]] name = "rustmotion-core" -version = "0.6.0" +version = "0.6.1" dependencies = [ "cosmic-text", "dashmap", @@ -5143,7 +5143,7 @@ dependencies = [ [[package]] name = "rustmotion-html" -version = "0.6.0" +version = "0.6.1" dependencies = [ "html5ever 0.39.0", "markup5ever_rcdom", @@ -5153,7 +5153,7 @@ dependencies = [ [[package]] name = "rustmotion-studio" -version = "0.6.0" +version = "0.6.1" dependencies = [ "clap", "dioxus", diff --git a/crates/rustmotion-cli/Cargo.toml b/crates/rustmotion-cli/Cargo.toml index 5375a1d9..ea6481bf 100644 --- a/crates/rustmotion-cli/Cargo.toml +++ b/crates/rustmotion-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-cli" -version = "0.6.0" +version = "0.6.1" edition = "2021" publish = false diff --git a/crates/rustmotion-components/Cargo.toml b/crates/rustmotion-components/Cargo.toml index c0ad08ac..8265b241 100644 --- a/crates/rustmotion-components/Cargo.toml +++ b/crates/rustmotion-components/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-components" -version = "0.6.0" +version = "0.6.1" edition = "2021" description = "Component library for rustmotion (51 components)" license = "MIT" @@ -14,7 +14,7 @@ default = ["lottie-native"] lottie-native = ["dep:thorvg", "dep:dashmap"] [dependencies] -rustmotion-core = { path = "../rustmotion-core", version = "0.6.0" } +rustmotion-core = { path = "../rustmotion-core", version = "0.6.1" } skia-safe = "0.82" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/crates/rustmotion-core/Cargo.toml b/crates/rustmotion-core/Cargo.toml index 55aaff0f..00dbf180 100644 --- a/crates/rustmotion-core/Cargo.toml +++ b/crates/rustmotion-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-core" -version = "0.6.0" +version = "0.6.1" edition = "2021" description = "Core types, traits, and rendering utilities for rustmotion" license = "MIT" diff --git a/crates/rustmotion-html/Cargo.toml b/crates/rustmotion-html/Cargo.toml index afea36ca..8f81f37e 100644 --- a/crates/rustmotion-html/Cargo.toml +++ b/crates/rustmotion-html/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-html" -version = "0.6.0" +version = "0.6.1" edition = "2021" description = "HTML/CSS front-end transpiler for rustmotion scenarios" license = "MIT" diff --git a/crates/rustmotion-studio/Cargo.toml b/crates/rustmotion-studio/Cargo.toml index df154edc..0558d75b 100644 --- a/crates/rustmotion-studio/Cargo.toml +++ b/crates/rustmotion-studio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-studio" -version = "0.6.0" +version = "0.6.1" edition = "2021" publish = false diff --git a/crates/rustmotion/Cargo.toml b/crates/rustmotion/Cargo.toml index cd242de2..b8c4e141 100644 --- a/crates/rustmotion/Cargo.toml +++ b/crates/rustmotion/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion" -version = "0.6.0" +version = "0.6.1" edition = "2021" description = "A CLI tool that renders motion design videos from JSON scenarios. No browser, no Node.js — just a single Rust binary." license = "MIT" @@ -10,9 +10,9 @@ repository = "https://github.com/LeadcodeDev/rustmotion" path = "src/lib.rs" [dependencies] -rustmotion-core = { path = "../rustmotion-core", version = "0.6.0" } -rustmotion-components = { path = "../rustmotion-components", version = "0.6.0", features = ["lottie-native"] } -rustmotion-html = { path = "../rustmotion-html", version = "0.6.0" } +rustmotion-core = { path = "../rustmotion-core", version = "0.6.1" } +rustmotion-components = { path = "../rustmotion-components", version = "0.6.1", features = ["lottie-native"] } +rustmotion-html = { path = "../rustmotion-html", version = "0.6.1" } skia-safe = "0.82" serde = { version = "1", features = ["derive"] } serde_json = "1" From aa175e81d9f53e4513b3f4ee3ab363233e9c0c8a Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 00:54:26 +0200 Subject: [PATCH 2/8] ci(publish): publish the workspace in one call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The seven hand-rolled steps polled https://crates.io/api/v1/crates// to wait for each crate. That endpoint rejects requests without an identifying User-Agent, so the loop could never succeed — it always spent 150s and exited 1. The 0.6.0 run died there, after rustmotion-core had already been published. cargo publish --workspace packages and rebuilds every selected crate from its own tarball before uploading anything, then uploads in dependency order and waits for index propagation itself. Nothing ships unless all of it can. --- .github/workflows/publish.yaml | 70 ++++++++-------------------------- 1 file changed, 15 insertions(+), 55 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 51c614a3..f022e95f 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -34,58 +34,18 @@ jobs: - name: Run tests run: cargo test --workspace - - name: Publish rustmotion-core - run: cargo publish -p rustmotion-core --token ${{ secrets.CARGO_REGISTRY_TOKEN }} - - - name: Wait for rustmotion-core on crates.io - run: | - VERSION=$(grep '^version' crates/rustmotion-core/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') - for i in $(seq 1 30); do - if curl -sf "https://crates.io/api/v1/crates/rustmotion-core/$VERSION" > /dev/null; then - echo "rustmotion-core $VERSION available" - exit 0 - fi - echo "Waiting... ($i)" - sleep 5 - done - echo "Timeout waiting for rustmotion-core" && exit 1 - - - name: Publish rustmotion-components - run: cargo publish -p rustmotion-components --token ${{ secrets.CARGO_REGISTRY_TOKEN }} - - - name: Wait for rustmotion-components on crates.io - run: | - VERSION=$(grep '^version' crates/rustmotion-components/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') - for i in $(seq 1 30); do - if curl -sf "https://crates.io/api/v1/crates/rustmotion-components/$VERSION" > /dev/null; then - echo "rustmotion-components $VERSION available" - exit 0 - fi - echo "Waiting... ($i)" - sleep 5 - done - echo "Timeout waiting for rustmotion-components" && exit 1 - - # rustmotion dépend de rustmotion-html au même titre que de core et - # components. Sans cette étape, `cargo publish -p rustmotion` échoue sur une - # dépendance introuvable — mais en troisième position, core et components - # étant alors déjà publiées. Une publication crates.io ne se défait pas : - # l'échec obligerait à repasser tout le workspace en version suivante. - - name: Publish rustmotion-html - run: cargo publish -p rustmotion-html --token ${{ secrets.CARGO_REGISTRY_TOKEN }} - - - name: Wait for rustmotion-html on crates.io - run: | - VERSION=$(grep '^version' crates/rustmotion-html/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') - for i in $(seq 1 30); do - if curl -sf "https://crates.io/api/v1/crates/rustmotion-html/$VERSION" > /dev/null; then - echo "rustmotion-html $VERSION available" - exit 0 - fi - echo "Waiting... ($i)" - sleep 5 - done - echo "Timeout waiting for rustmotion-html" && exit 1 - - - name: Publish rustmotion - run: cargo publish -p rustmotion --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + # Un seul appel, et c'est ce qui porte la garantie : cargo empaquette et + # recompile les quatre crates depuis leur propre tarball AVANT de televerser + # quoi que ce soit. Si une seule ne se construit pas, rien ne part. Il + # televerse ensuite dans l'ordre des dependances et attend lui-meme la + # propagation de l'index. + # + # Les sept etapes manuelles qui precedaient interrogeaient + # https://crates.io/api/v1/crates// pour attendre chaque crate. + # Cet endpoint refuse une requete sans User-Agent identifiant : la boucle ne + # pouvait donc jamais reussir, et la release 0.6.0 s'est arretee la — apres + # avoir publie rustmotion-core, definitivement. + # + # studio et cli ne sont pas publiees. + - name: Publish all crates + run: cargo publish --workspace --exclude rustmotion-studio --exclude rustmotion-cli --token ${{ secrets.CARGO_REGISTRY_TOKEN }} From 726d83fc9c1e3b714e1484d4eae72294ae2d3086 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 00:58:24 +0200 Subject: [PATCH 3/8] refactor(workspace): declare the version once, in the workspace manifest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The version was written ten times — one per manifest, plus one per internal dependency requirement. Nothing kept them in agreement, and a single stale one fails the publish after the earlier crates have already shipped, which cannot be undone. [workspace.package] and [workspace.dependencies] now hold it; the six crates inherit. The tag check reads cargo metadata instead of grepping a manifest, since the manifest no longer contains a literal to grep. --- .github/workflows/publish.yaml | 8 +++++++- Cargo.toml | 15 +++++++++++++++ crates/rustmotion-cli/Cargo.toml | 2 +- crates/rustmotion-components/Cargo.toml | 4 ++-- crates/rustmotion-core/Cargo.toml | 2 +- crates/rustmotion-html/Cargo.toml | 2 +- crates/rustmotion-studio/Cargo.toml | 2 +- crates/rustmotion/Cargo.toml | 8 ++++---- 8 files changed, 32 insertions(+), 11 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index f022e95f..3bb13074 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -22,9 +22,15 @@ jobs: - uses: dtolnay/rust-toolchain@stable + # La version se lit via `cargo metadata`, pas en grepant un manifeste : elle + # est déclarée dans `[workspace.package]` et héritée, donc un `grep + # '^version'` sur la crate tomberait sur `version.workspace = true` et + # comparerait le tag à cette chaîne. cargo répond la version résolue, où + # qu'elle soit écrite. - name: Verify tag matches Cargo.toml version run: | - CARGO_VERSION=$(grep '^version' crates/rustmotion/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + CARGO_VERSION=$(cargo metadata --format-version 1 --no-deps \ + | jq -r '.packages[] | select(.name=="rustmotion") | .version') TAG_VERSION=${GITHUB_REF#refs/tags/} if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then echo "Tag $TAG_VERSION does not match Cargo.toml version $CARGO_VERSION" diff --git a/Cargo.toml b/Cargo.toml index df2fe971..498dbb32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,21 @@ members = [ "crates/rustmotion-html", ] +# Les six crates avancent ensemble. La version se change ici, et nulle part +# ailleurs : elle était auparavant répétée dix fois — une par manifeste, plus une +# par dépendance interne — et une seule oubliée fait échouer la publication après +# que les précédentes soient parties, ce qui ne se rattrape pas. +[workspace.package] +version = "0.6.1" + +# Les dépendances internes portent aussi la version, donc elles se déclarent ici +# pour la même raison. `path` sert au développement, `version` à ce que cargo +# écrit dans le paquet publié : les deux doivent coexister, et rester d'accord. +[workspace.dependencies] +rustmotion-core = { path = "crates/rustmotion-core", version = "0.6.1" } +rustmotion-components = { path = "crates/rustmotion-components", version = "0.6.1" } +rustmotion-html = { path = "crates/rustmotion-html", version = "0.6.1" } + # Optimize dependencies even in dev builds. Our own crates stay at opt-level 0 # (fast incremental + debuggable), but heavy compute in deps (image encoding, # etc.) runs optimized — without this, `cargo run` image encode is ~20x slower. diff --git a/crates/rustmotion-cli/Cargo.toml b/crates/rustmotion-cli/Cargo.toml index ea6481bf..df660b79 100644 --- a/crates/rustmotion-cli/Cargo.toml +++ b/crates/rustmotion-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-cli" -version = "0.6.1" +version.workspace = true edition = "2021" publish = false diff --git a/crates/rustmotion-components/Cargo.toml b/crates/rustmotion-components/Cargo.toml index 8265b241..7ed52bdd 100644 --- a/crates/rustmotion-components/Cargo.toml +++ b/crates/rustmotion-components/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-components" -version = "0.6.1" +version.workspace = true edition = "2021" description = "Component library for rustmotion (51 components)" license = "MIT" @@ -14,7 +14,7 @@ default = ["lottie-native"] lottie-native = ["dep:thorvg", "dep:dashmap"] [dependencies] -rustmotion-core = { path = "../rustmotion-core", version = "0.6.1" } +rustmotion-core.workspace = true skia-safe = "0.82" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/crates/rustmotion-core/Cargo.toml b/crates/rustmotion-core/Cargo.toml index 00dbf180..34e984d1 100644 --- a/crates/rustmotion-core/Cargo.toml +++ b/crates/rustmotion-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-core" -version = "0.6.1" +version.workspace = true edition = "2021" description = "Core types, traits, and rendering utilities for rustmotion" license = "MIT" diff --git a/crates/rustmotion-html/Cargo.toml b/crates/rustmotion-html/Cargo.toml index 8f81f37e..f5827ec7 100644 --- a/crates/rustmotion-html/Cargo.toml +++ b/crates/rustmotion-html/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-html" -version = "0.6.1" +version.workspace = true edition = "2021" description = "HTML/CSS front-end transpiler for rustmotion scenarios" license = "MIT" diff --git a/crates/rustmotion-studio/Cargo.toml b/crates/rustmotion-studio/Cargo.toml index 0558d75b..1e568e66 100644 --- a/crates/rustmotion-studio/Cargo.toml +++ b/crates/rustmotion-studio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion-studio" -version = "0.6.1" +version.workspace = true edition = "2021" publish = false diff --git a/crates/rustmotion/Cargo.toml b/crates/rustmotion/Cargo.toml index b8c4e141..fad36df4 100644 --- a/crates/rustmotion/Cargo.toml +++ b/crates/rustmotion/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustmotion" -version = "0.6.1" +version.workspace = true edition = "2021" description = "A CLI tool that renders motion design videos from JSON scenarios. No browser, no Node.js — just a single Rust binary." license = "MIT" @@ -10,9 +10,9 @@ repository = "https://github.com/LeadcodeDev/rustmotion" path = "src/lib.rs" [dependencies] -rustmotion-core = { path = "../rustmotion-core", version = "0.6.1" } -rustmotion-components = { path = "../rustmotion-components", version = "0.6.1", features = ["lottie-native"] } -rustmotion-html = { path = "../rustmotion-html", version = "0.6.1" } +rustmotion-core.workspace = true +rustmotion-components = { workspace = true, features = ["lottie-native"] } +rustmotion-html.workspace = true skia-safe = "0.82" serde = { version = "1", features = ["derive"] } serde_json = "1" From e1fbc7ef7a70a23465fb2265b7b8c97a94af1d23 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 01:00:31 +0200 Subject: [PATCH 4/8] ci: enforce that every crate and internal dependency share one version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [workspace.package] now holds the version and the six crates inherit it, but cargo cannot inherit it into a dependency requirement: an entry in [workspace.dependencies] must carry a literal, because a published crate cannot depend on a bare path. So the package version and the three internal requirements can silently disagree, and cargo only notices at publish time — once the earlier crates are already on crates.io. The check fails on either kind of drift: a requirement that no longer matches the workspace version, or a crate that stopped inheriting it. --- .github/workflows/ci.yaml | 13 +++++++++++++ scripts/check-version-agreement.py | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100755 scripts/check-version-agreement.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index afd85abe..66d0c8cc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -53,6 +53,19 @@ jobs: # dossier situé hors de la crate, donc absent de l'archive. Sans ce job, cette # famille de défaut ne se découvre qu'en publiant — et une publication # crates.io ne se défait pas, elle se yanke. + # La version est déclarée une fois dans [workspace.package] et héritée, mais + # cargo n'a aucune syntaxe pour injecter cette même version dans une exigence de + # dépendance interne : [workspace.dependencies] doit porter un littéral, puisque + # une crate publiée ne peut pas dépendre d'un simple `path`. Rien dans cargo ne + # vérifie donc que les deux s'accordent, et un désaccord ne se voit qu'à la + # publication — après que les crates précédentes soient parties. + version-agreement: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check every crate and internal dependency agree on the version + run: python3 scripts/check-version-agreement.py + package: runs-on: ubuntu-latest steps: diff --git a/scripts/check-version-agreement.py b/scripts/check-version-agreement.py new file mode 100755 index 00000000..928d1740 --- /dev/null +++ b/scripts/check-version-agreement.py @@ -0,0 +1,26 @@ +import sys, tomllib, pathlib + +root = tomllib.loads(pathlib.Path("Cargo.toml").read_text()) +ws = root["workspace"] +want = ws["package"]["version"] +bad = [] + +for name, spec in ws.get("dependencies", {}).items(): + if isinstance(spec, dict) and "path" in spec: + got = spec.get("version") + if got != want: + bad.append(f" [workspace.dependencies] {name}: {got!r} != {want!r}") + +for m in ws["members"]: + p = pathlib.Path(m) / "Cargo.toml" + pkg = tomllib.loads(p.read_text())["package"] + v = pkg.get("version") + if v != {"workspace": True}: + bad.append(f" {p}: version is {v!r}, expected inherited from the workspace") + +if bad: + print(f"Version drift — the workspace declares {want}:") + print("\n".join(bad)) + print("\nEvery crate and every internal dependency moves together; change it in\n[workspace.package] and let the rest inherit.") + sys.exit(1) +print(f"All crates and internal dependencies agree on {want}") From 75113d6beaa65c4e48f7c0a0acf9178484ca2dcf Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 01:04:30 +0200 Subject: [PATCH 5/8] ci: drop the version check and the redundant excludes publish = false in the studio and cli manifests already keeps them out of cargo publish --workspace and cargo package --workspace, verified by running both without the flags: cargo selects exactly the four publishable crates. Repeating that in the workflow duplicated a fact the manifests already carry. --- .github/workflows/ci.yaml | 18 ++---------------- .github/workflows/publish.yaml | 4 ++-- scripts/check-version-agreement.py | 26 -------------------------- 3 files changed, 4 insertions(+), 44 deletions(-) delete mode 100755 scripts/check-version-agreement.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 66d0c8cc..65ae429f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -53,19 +53,6 @@ jobs: # dossier situé hors de la crate, donc absent de l'archive. Sans ce job, cette # famille de défaut ne se découvre qu'en publiant — et une publication # crates.io ne se défait pas, elle se yanke. - # La version est déclarée une fois dans [workspace.package] et héritée, mais - # cargo n'a aucune syntaxe pour injecter cette même version dans une exigence de - # dépendance interne : [workspace.dependencies] doit porter un littéral, puisque - # une crate publiée ne peut pas dépendre d'un simple `path`. Rien dans cargo ne - # vérifie donc que les deux s'accordent, et un désaccord ne se voit qu'à la - # publication — après que les crates précédentes soient parties. - version-agreement: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Check every crate and internal dependency agree on the version - run: python3 scripts/check-version-agreement.py - package: runs-on: ubuntu-latest steps: @@ -75,6 +62,5 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Package publishable crates - # studio et cli ne sont pas publiées ; les exclure évite d'installer la - # pile GTK/WebKit ici pour rien. - run: cargo package --workspace --exclude rustmotion-studio --exclude rustmotion-cli + # studio et cli portent `publish = false` : cargo les saute tout seul. + run: cargo package --workspace diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 3bb13074..e3299ce1 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -52,6 +52,6 @@ jobs: # pouvait donc jamais reussir, et la release 0.6.0 s'est arretee la — apres # avoir publie rustmotion-core, definitivement. # - # studio et cli ne sont pas publiees. + # studio et cli portent `publish = false` : cargo les saute tout seul. - name: Publish all crates - run: cargo publish --workspace --exclude rustmotion-studio --exclude rustmotion-cli --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish --workspace --token ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/scripts/check-version-agreement.py b/scripts/check-version-agreement.py deleted file mode 100755 index 928d1740..00000000 --- a/scripts/check-version-agreement.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys, tomllib, pathlib - -root = tomllib.loads(pathlib.Path("Cargo.toml").read_text()) -ws = root["workspace"] -want = ws["package"]["version"] -bad = [] - -for name, spec in ws.get("dependencies", {}).items(): - if isinstance(spec, dict) and "path" in spec: - got = spec.get("version") - if got != want: - bad.append(f" [workspace.dependencies] {name}: {got!r} != {want!r}") - -for m in ws["members"]: - p = pathlib.Path(m) / "Cargo.toml" - pkg = tomllib.loads(p.read_text())["package"] - v = pkg.get("version") - if v != {"workspace": True}: - bad.append(f" {p}: version is {v!r}, expected inherited from the workspace") - -if bad: - print(f"Version drift — the workspace declares {want}:") - print("\n".join(bad)) - print("\nEvery crate and every internal dependency moves together; change it in\n[workspace.package] and let the rest inherit.") - sys.exit(1) -print(f"All crates and internal dependencies agree on {want}") From 21c8d00694f70bf6ee52193c4bf494fa2a5f57d6 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 01:06:45 +0200 Subject: [PATCH 6/8] ci: restore the package excludes, which were not redundant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cargo publish --workspace and cargo package --workspace do not treat publish = false the same way. publish skips those crates; package archives them anyway and fails on rustmotion-studio, which depends on rustmotion by path with no version — an unversioned dependency cannot be packaged. Removing the flags from both commands generalised a check run only against publish. Reproduced locally: with the excludes the job exits 0, without them it exits 101 on that manifest. --- .github/workflows/ci.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 65ae429f..2a3e09d2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -62,5 +62,10 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Package publishable crates - # studio et cli portent `publish = false` : cargo les saute tout seul. - run: cargo package --workspace + # Les exclusions sont nécessaires ICI et pas dans publish.yaml : les deux + # commandes ne traitent pas `publish = false` de la même façon. + # `cargo publish --workspace` saute ces crates ; `cargo package + # --workspace` les empaquette quand même, et échoue sur studio, qui + # dépend de rustmotion par `path` sans version — une dépendance sans + # version ne peut pas être empaquetée. + run: cargo package --workspace --exclude rustmotion-studio --exclude rustmotion-cli From 897807dfc631a1d35400b6ab10b88057eaf18b4b Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 01:07:21 +0200 Subject: [PATCH 7/8] ci: drop the package job, publishing belongs to the tag cargo publish --workspace already packages and rebuilds every crate from its own tarball before uploading anything, so a packaging defect now fails the release with nothing published. Repeating that work on every PR guarded against a risk the tag workflow already removes. --- .github/workflows/ci.yaml | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2a3e09d2..07e10293 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -46,26 +46,3 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Run tests run: cargo test --workspace - - # Empaquette les crates publiées et les recompile depuis leur tarball. Aucun - # `cargo test` ne fait ça, et c'est la seule étape qui voit ce qui manque au - # paquet : la release 0.6.0 s'est arrêtée sur 65 `include_str!` visant un - # dossier situé hors de la crate, donc absent de l'archive. Sans ce job, cette - # famille de défaut ne se découvre qu'en publiant — et une publication - # crates.io ne se défait pas, elle se yanke. - package: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Install system dependencies - run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev libfreetype6-dev - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - name: Package publishable crates - # Les exclusions sont nécessaires ICI et pas dans publish.yaml : les deux - # commandes ne traitent pas `publish = false` de la même façon. - # `cargo publish --workspace` saute ces crates ; `cargo package - # --workspace` les empaquette quand même, et échoue sur studio, qui - # dépend de rustmotion par `path` sans version — une dépendance sans - # version ne peut pas être empaquetée. - run: cargo package --workspace --exclude rustmotion-studio --exclude rustmotion-cli From 24ed83143427dc7155c1521bd13fc06b187d80fe Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 20 Aug 2026 01:09:15 +0200 Subject: [PATCH 8/8] ci(publish): dry-run the workspace before publishing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The publish step already packages and verifies every crate before uploading, so this catches nothing new and rebuilds all four a second time. What it buys is a readable failure: a packaging defect now stops before the publish command runs at all, so the log cannot be mistaken for a release that started and broke halfway — which is how 0.6.0 ended, with one crate already on crates.io. --- .github/workflows/publish.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index e3299ce1..5a2a02ed 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -40,6 +40,16 @@ jobs: - name: Run tests run: cargo test --workspace + # Repetition deliberee : l'etape suivante empaquette et verifie deja tout + # avant de televerser, donc ce dry-run recompile les quatre crates une + # seconde fois et n'attrape rien de plus. Ce qu'il achete est un signal, pas + # une garantie — un echec ici arrive avant que la commande de publication + # soit lancee, donc le log dit sans ambiguite que rien n'a pu partir. Apres + # 0.6.0, qui s'est arretee avec une crate deja publiee, la distinction vaut + # le temps de compilation. + - name: Dry-run the workspace publish + run: cargo publish --workspace --dry-run + # Un seul appel, et c'est ce qui porte la garantie : cargo empaquette et # recompile les quatre crates depuis leur propre tarball AVANT de televerser # quoi que ce soit. Si une seule ne se construit pas, rien ne part. Il