From da8aa07572132da8cf2fbcc12105ad165958a05e Mon Sep 17 00:00:00 2001 From: default <216188+jdx@users.noreply.github.com> Date: Tue, 11 Aug 2026 18:50:49 +0000 Subject: [PATCH] fix(ci): unblock releases by cutting usage-derive's dev-dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release job has failed on every run since usage-derive became publishable: failed to select a version for `usage-argv` package `usage-derive` depends on `usage-argv` with feature `spec` but `usage-argv` does not have that feature usage-argv 5.1.0 went to crates.io before the `spec` feature existed, and crates.io versions are immutable, so nothing at 5.1.0 can ever depend on that feature. `cargo publish` resolves dev-dependencies against the registry, so usage-derive was unpublishable — and the failure came before the release PR that would have bumped the version, leaving the pipeline stuck rather than merely delayed. The dev-dependency is gone rather than worked around. A proc-macro that dev-depends on the runtime it emits code for recreates this cycle every time that runtime gains a feature mid-version; serde_derive avoids it the same way. This crate emits tokens and links nothing, so it now depends on usage-argv not at all. Its crate-level example moves to conformance/tests/derive.rs, where the derive is tested anyway, so it is still compiled and run rather than becoming an `ignore` block nobody checks. Both sides point at each other. Co-Authored-By: Claude Fable 5 --- Cargo.lock | 1 - conformance/tests/derive.rs | 42 +++++++++++++++++++++++++++++++++++++ derive/Cargo.toml | 12 +++++++---- derive/src/lib.rs | 6 +++++- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d38184cf..7ebbeeff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2029,7 +2029,6 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.3", - "usage-argv", ] [[package]] diff --git a/conformance/tests/derive.rs b/conformance/tests/derive.rs index b2b46041..36a46db9 100644 --- a/conformance/tests/derive.rs +++ b/conformance/tests/derive.rs @@ -480,3 +480,45 @@ fn reaching_the_tables_is_free() { "the tables should be one static, not a build" ); } + +/// The crate-level example from usage-derive's documentation, kept here because +/// that crate cannot dev-depend on usage-argv without making itself unpublishable +/// — see the note in `derive/Cargo.toml`. If this changes, change the docs too. +mod docs_example { + use super::argv; + use usage_derive::Cli; + + /// A tool that does things + #[derive(Cli)] + #[usage(bin = "ex", version = "1.0")] + struct Cli { + /// How many jobs to run at once + #[usage(short = 'j', long, env = "EX_JOBS", default = "4")] + jobs: Option, + + /// Print more + #[usage(short = 'v', long, count)] + verbose: u8, + + /// Colorize output + #[usage(long, negate = "--no-color", default = "true")] + color: bool, + + /// Files to process + files: Vec, + } + + #[test] + fn the_crate_level_example_from_the_docs() { + let a = argv(["-j8", "--no-color", "a.txt"]); + let cli = Cli::parse_from(&a).unwrap(); + assert_eq!(cli.jobs.as_deref(), Some("8")); + assert!(!cli.color); + assert_eq!(cli.files, ["a.txt"]); + assert_eq!(cli.verbose, 0); + + // The same declaration is also the spec, which is what generates docs, + // manpages, and completions. + assert!(Cli::to_kdl().contains(r#"flag "-j --jobs""#)); + } +} diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 4c9380b1..c5658f31 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -24,7 +24,11 @@ quote = "1" # needs the newer API, and matching what is there avoids a second copy. syn = { version = "3", features = ["full"] } -# The generated code refers to usage-argv, so the doc examples need it in scope to -# compile. Not a real dependency: this crate emits tokens and links nothing. -[dev-dependencies] -usage-argv = { workspace = true, features = ["spec"] } +# No dependency on usage-argv, not even for tests. This crate emits tokens and +# links nothing, and dev-depending on the runtime it emits code for creates a cycle +# at publish time: `cargo publish` resolves dev-dependencies against the registry, +# so a feature added to usage-argv within a version makes this crate unpublishable +# until the version bumps. serde_derive avoids the same trap the same way. +# +# The crate-level example is therefore `ignore`d here and compiled for real in +# conformance/tests/derive.rs, which is where the derive is tested anyway. diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 3810d9e6..125267f0 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -7,7 +7,11 @@ //! to build before a parse can start — and a successful parse touches only the //! first of the three. //! -//! ``` +//! Not compiled here, because this crate deliberately does not depend on +//! usage-argv — see the note in its `Cargo.toml`. The same example runs as a test +//! in `conformance/tests/derive.rs`, as `the_crate_level_example_from_the_docs`. +//! +//! ```ignore //! # use usage_derive::Cli; //! /// A tool that does things //! #[derive(Cli)]