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 f4aeb04..061d4b0 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 5375a1d..ea6481b 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 c0ad08a..8265b24 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 55aaff0..00dbf18 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 afea36c..8f81f37 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 df154ed..0558d75 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 cd242de..b8c4e14 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 51c614a..f022e95 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 f022e95..3bb1307 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 df2fe97..498dbb3 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 ea6481b..df660b7 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 8265b24..7ed52bd 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 00dbf18..34e984d 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 8f81f37..f5827ec 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 0558d75..1e568e6 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 b8c4e14..fad36df 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 afd85ab..66d0c8c 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 0000000..928d174 --- /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 66d0c8c..65ae429 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 3bb1307..e3299ce 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 928d174..0000000 --- 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 65ae429..2a3e09d 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 2a3e09d..07e1029 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 e3299ce..5a2a02e 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