Skip to content

feat(clap_usage)!: expose spec(), publish against usage-lib 4 - #743

Merged
jdx merged 2 commits into
mainfrom
feat/clap-usage-4
Jul 25, 2026
Merged

feat(clap_usage)!: expose spec(), publish against usage-lib 4#743
jdx merged 2 commits into
mainfrom
feat/clap-usage-4

Conversation

@jdx

@jdx jdx commented Jul 25, 2026

Copy link
Copy Markdown
Owner

clap_usage on crates.io is still 2.0.3, requiring usage-lib ^2.0.3 — even though the in-repo crate has been building against the workspace version for a while. Its source hasn't changed since 2.0.3, so release-plz never had a reason to bump it, and it silently fell two majors behind.

That pin is why hk, pitchfork and communique couldn't adopt effect=:

  1. generate() renders straight to a writer, so the Spec never escapes and there's nothing to annotate; and
  2. even with an accessor, 2.x has no effect field to set.

All three ended up inlining generate()'s four lines and depending on usage-lib directly (jdx/hk#1121, jdx/pitchfork#666, jdx/communique#240).

The addition

spec() — returns the Spec with bin already set:

let mut spec = clap_usage::spec(&mut cmd, "mycli");
spec.cmd.subcommands.get_mut("rm").unwrap().effect = Some(SpecCommandEffect::Destructive);
println!("{spec}");

generate() is now literally spec() plus two writeln!s, so its output is byte-identical — there's a test asserting the header and body are unchanged.

Version

Straight to 4.0.0, matching usage-lib and usage-cli. A crate whose whole purpose is producing usage-lib types is less confusing tracking their major than carrying an independent one, and it makes the 2.x → current gap unambiguous rather than looking like a small bump.

What this unblocks

Those three PRs can go back to using clap_usage instead of inlining it, which drops a direct usage-lib dependency from each and leaves them as just their effects tables plus a two-line change. I'll rework them once this releases — no rush on your side, they're correct either way, just more verbose than they need to be.

Verified

cargo test --workspace passes, clippy --all-features --all-targets and fmt --check clean. Two new integration tests plus a compiling doctest on spec().

Note the workspace clap_usage pin in the root Cargo.toml also had to move to 4.0.0 — usage-cli depends on it via workspace = true, so the build fails without it.

This PR was generated by an AI coding assistant.


Note

Low Risk
Additive API with preserved generate() output; main impact is the intentional semver major bump for dependents upgrading from 2.x.

Overview
clap_usage is bumped to 4.0.0 (workspace and crate) so it tracks usage-lib 4.x, closing the gap where crates.io still shipped 2.0.3.

A new spec() builds the usage::Spec from a clap::Command (with bin set) and returns it for inspection or post-processing—e.g. setting effect= on subcommands that clap cannot describe. generate() now delegates to spec() and only adds the @generated header and write; behavior is unchanged and covered by tests.

The crate re-exports usage and documents that consumers can depend on clap_usage alone to name types like SpecCommandEffect. Integration tests assert annotation works through clap_usage::usage and that generate output is unchanged.

Reviewed by Cursor Bugbot for commit 3d4004f. Bugbot is set up for automated code reviews on this repo. Configure here.

BREAKING CHANGE: clap_usage now requires usage-lib 4. The published 2.0.3
still requires usage-lib ^2.0.3 even though the in-repo crate has built
against the workspace version for a while, so every consumer was pinned to
2.x specs.

That pin is why hk, pitchfork and communique could not adopt `effect=`:
generate() renders straight to a writer, so the Spec never escapes and
there is nothing to annotate, and 2.x has no `effect` field to set anyway.
All three ended up inlining generate()'s four lines and depending on
usage-lib directly.

Add `spec()`, which returns the Spec with `bin` already set. generate() is
now spec() plus two writeln!s, so its output is unchanged:

    let mut spec = clap_usage::spec(&mut cmd, "mycli");
    spec.cmd.subcommands.get_mut("rm").unwrap().effect = Some(Destructive);
    println!("{spec}");

Version goes straight to 4.0.0 to match usage-lib and usage-cli; a crate
whose entire purpose is producing usage-lib types is less confusing tracking
their major than carrying its own.

Two tests: that a spec can be annotated before rendering, and that
generate() still emits the same header and body.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jdx, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 12 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 9dd5c145-0d35-429d-8256-41b12c4f2537

📥 Commits

Reviewing files that changed from the base of the PR and between c63af1f and 3d4004f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • Cargo.toml
  • clap_usage/Cargo.toml
  • clap_usage/src/generate.rs
  • clap_usage/src/lib.rs
  • clap_usage/tests/spec_accessor.rs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR exposes an annotatable clap-derived specification while preserving the existing generation path.

  • Adds clap_usage::spec() and delegates generate() through it.
  • Re-exports the usage crate so consumers can name specification types without a direct dependency.
  • Aligns clap_usage at version 4.0.0 with usage-lib.
  • Adds integration and documentation tests for annotation and generated output.

Confidence Score: 5/5

The PR appears safe to merge.

The previous effect-type accessibility issue is fixed by publicly re-exporting the usage crate, and the new consumer-style integration test exercises the intended import and annotation path; no blocking failure remains.

Important Files Changed

Filename Overview
clap_usage/src/generate.rs Adds the public spec() accessor and preserves generate() behavior by delegating conversion through it.
clap_usage/src/lib.rs Re-exports both spec() and the usage crate, fully addressing the prior inaccessible-effect-type finding.
clap_usage/tests/spec_accessor.rs Verifies that consumers can import the effect type through clap_usage, annotate a returned spec, and retain generated output structure.
clap_usage/Cargo.toml Updates the package version to 4.0.0 to align with the workspace usage libraries.
Cargo.toml Updates the workspace dependency constraint for clap_usage to 4.0.0.

Reviews (2): Last reviewed commit: "fix(clap_usage): re-export usage so the ..." | Re-trigger Greptile

Comment thread clap_usage/src/lib.rs
The `spec()` example set `effect` via `usage::SpecCommandEffect`, but
clap_usage exported only `generate` and `spec`, so a consumer depending on
clap_usage alone could not name that type. They would have had to keep the
direct usage-lib dependency this accessor exists to remove — the example as
written would not have compiled for them.

Re-export the whole `usage` crate rather than a curated list of types, so
nothing here goes stale as usage grows:

    use clap_usage::usage::SpecCommandEffect;

The integration test now reaches the enum through `clap_usage::usage::`,
which is the path an external consumer has, so it demonstrates the API is
self-sufficient instead of quietly relying on a second dependency.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jdx

jdx commented Jul 25, 2026

Copy link
Copy Markdown
Owner Author

Good catch, and it went to the heart of the PR. Fixed.

The spec() example set effect via usage::SpecCommandEffect, but clap_usage exported only generate and spec — so a consumer depending on clap_usage alone couldn't name that type. They'd have had to keep the direct usage-lib dependency the accessor exists to remove. The documented flow literally wouldn't have compiled for them, which would have made this release pointless for hk, pitchfork and communique.

Now re-exporting the whole crate rather than a curated list, so nothing goes stale as usage grows:

use clap_usage::usage::SpecCommandEffect;

The integration test reaches the enum through clap_usage::usage:: too — the path an external consumer actually has — so it demonstrates self-sufficiency rather than quietly leaning on a second dependency. Both doctests compile; cargo test --workspace, clippy --all-features --all-targets and fmt --check are clean.

Worth noting the test would have kept passing either way: an integration test in this package can reach usage regardless, so it was never going to catch the problem a real consumer hits. Routing it through the public path is what makes it meaningful.

This comment was generated by an AI coding assistant.

@jdx
jdx merged commit 6fa65f8 into main Jul 25, 2026
6 checks passed
@jdx
jdx deleted the feat/clap-usage-4 branch July 25, 2026 22:50
jdx added a commit to jdx/hk that referenced this pull request Jul 25, 2026
clap_usage 4.0.0 is published now (jdx/usage#743), with a spec() accessor
that hands back the Spec before rendering. That is exactly what was missing
when this branch started: generate() writes straight to a writer, so there
was nothing to annotate, and the then-current clap_usage was pinned to
usage-lib 2.x, which has no effect field at all.

So the four inlined lines go back to being a clap_usage call, and the direct
usage-lib dependency is dropped — clap_usage re-exports usage, so
`clap_usage::usage::SpecCommandEffect` covers the types the table needs.

Verified: `hk usage` emits a byte-identical spec apart from
min_usage_version, which moves to 4.0 since the spec now carries
flag-level effects that older CLIs reject. mise.lock moves to usage 4.0.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jdx added a commit to jdx/pitchfork that referenced this pull request Jul 25, 2026
clap_usage 4.0.0 is published (jdx/usage#743) with a spec() accessor that
hands back the Spec before rendering — the thing that was missing when this
branch started, and the reason generate()'s four lines were inlined here.

The direct usage-lib dependency goes away with it: clap_usage re-exports
usage, so `clap_usage::usage::SpecCommandEffect` covers what the table needs.

`pitchfork usage` emits a byte-identical spec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jdx added a commit to jdx/communique that referenced this pull request Jul 25, 2026
codecov flagged the patch, and it was right about something real: every
test here checked the tables against the CLI — complete, no stale entries,
no duplicates — but none checked that `apply` actually transfers them onto
the spec. The tables could have been perfect and silently never applied.

`apply_annotates_commands_and_flags` covers that path directly, including
that a flag with no entry is left alone rather than inheriting one.

Also switches to clap_usage::spec(), now that clap_usage 4.0.0 is published
(jdx/usage#743) with the accessor that was missing when this branch started.
The direct usage-lib dependency goes away — clap_usage re-exports usage.
`communique usage` emits a byte-identical spec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant