feat: bump usage-lib v2 → v3 to render examples in task --help#8890
feat: bump usage-lib v2 → v3 to render examples in task --help#8890
Conversation
20c8347 to
7f047e1
Compare
There was a problem hiding this comment.
Code Review
This pull request updates usage-lib to version 3.0 and refreshes several dependencies including strum, strum_macros, and roff. The code changes in src/task/task_script_parser.rs adapt to the new usage-lib API by refactoring usage::Spec initialization. The review feedback suggests improving code quality in the test suite by using scoped blocks for spec initialization to eliminate unnecessary mutability in the outer scope.
| let mut spec = usage::Spec::default(); | ||
| spec.cmd = cmd; |
There was a problem hiding this comment.
Since spec is not mutated after its initialization, you can remove the mut keyword from the outer scope by using a block for initialization. This improves readability by limiting the scope of mutability, which is a common Rust idiom.
| let mut spec = usage::Spec::default(); | |
| spec.cmd = cmd; | |
| let spec = { | |
| let mut spec = usage::Spec::default(); | |
| spec.cmd = cmd; | |
| spec | |
| }; |
| let mut spec = usage::Spec::default(); | ||
| spec.cmd = cmd; |
There was a problem hiding this comment.
Similar to the previous suggestion, spec is not mutated after initialization. You can improve readability by using a block to construct it, which removes the need for mut in the outer scope.
| let mut spec = usage::Spec::default(); | |
| spec.cmd = cmd; | |
| let spec = { | |
| let mut spec = usage::Spec::default(); | |
| spec.cmd = cmd; | |
| spec | |
| }; |
zeke-ricon
left a comment
There was a problem hiding this comment.
Review from @zeke-ricon
Overall this is clean and mergeable. Notes:
Looks good:
- Cargo.toml bump is straightforward (usage-lib 2 → 3, features unchanged)
- All 4 Spec construction sites correctly adapted to v3 API —
default() + field assignmentis the right pattern - Cargo.lock changes are mechanical (strum 0.28.0/0.28.0, roff 0.2.2 → 1.1.1 as transitive deps from usage-lib v3)
- New test covers the full path:
parse_script→ examples populated →has_any_usage_spec→render_helpoutput. Good coverage of the feature being enabled
One observation (non-blocking):
The test exercises usage-lib's Spec::parse_script and docs::cli::render_help directly — this proves v3 works but doesn't go through mise's own TaskScriptParser. If TaskScriptParser ever strips or drops examples during its processing, this test wouldn't catch it. Consider a follow-up test that feeds a task with #USAGE example directives through TaskScriptParser::parse_run_scripts and asserts examples survive into the final Spec. Not blocking since the construction sites don't touch example fields.
Ship it once CI is green. Nice contribution.
ikma-ricon
left a comment
There was a problem hiding this comment.
Hey Baby Joel — reviewed the diff. Overall clean work. One substantive issue:
has_any_usage_spec checks spec.cmd.examples but parse_script populates spec.examples — potential mismatch
In usage-lib v3, Spec has both spec.examples (top-level) and spec.cmd.examples (on SpecCommand). The parse_script path puts #USAGE example directives into spec.examples. But has_any_usage_spec (line 916) checks:
|| !spec.cmd.examples.is_empty()If a task script has only example directives (no flags/args), has_any_usage_spec returns false — the task falls through to generic help, and examples don't render.
Your test doesn't catch this because the script includes a flag (--name), so has_any_args_defined returns true regardless. I'd:
- Add a test with only an example directive (no flags, no args) and assert
has_any_usage_specreturns true - If that fails (I expect it will), fix
has_any_usage_specto also check!spec.examples.is_empty()
Other notes:
- The four
Spec::default()+spec.cmd = cmdconstruction sites are consistent and correct (forced by#[non_exhaustive]in v3). No issues. - The strum 0.27/0.28 duplication in Cargo.lock is expected — usage-lib v3 pulls strum 0.28 while the rest of the tree stays on 0.27. Fine.
render_helpassertions in the test are solid — good coverage of the rendering path.
— Ikma
Greptile SummaryThis PR bumps
Confidence Score: 5/5Safe to merge; changes are narrowly scoped, well-tested, and deliver the described feature without regressions. All 558 tests pass. The struct-initializer adaptations are correct for non-exhaustive types and compile cleanly. has_any_usage_spec is properly extended to cover the new examples fields. The previously raised reviewer concern about testing the examples-only code path has been proactively addressed with the new test_has_any_usage_spec_examples_only test. No P0 or P1 issues found. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Task script file\n#USAGE example …"] -->|"usage::Spec::parse_script()"| B["usage::Spec\n(spec.examples populated)"]
B --> C["TaskScriptParser\n.parse_run_scripts()"]
C -->|"spec.merge(spec_from_field)"| D["Merged Spec\n(examples preserved)"]
D --> E{"has_any_usage_spec?"}
E -->|"spec.examples non-empty → true"| F["usage::docs::cli::render_help()"]
F --> G["--help output\nwith Examples: section"]
E -->|"false"| H["Generic task help\n(no Examples section)"]
Reviews (5): Last reviewed commit: "[autofix.ci] apply automated fixes" | Re-trigger Greptile |
|
Apologies for the review noise — the reviews from @zeke-ricon and @ikma-ricon were meant to be sent privately, not posted here. We'll address their feedback and keep future coordination off the PR. Sorry about that! |
01f537b to
fdd74fb
Compare
|
Just ran into some usage parsing errors in mise, learned it was a version mismatch (I have usage v3 cli, but this project uses v2). Great timing on this PR. hope it gets merged. |
|
@baby-joel I raised a discussion in discord about the parsing issues related to v2 and I was going to make a PR, but you already have this one open. My working changes include the following files: and the patch (minus the lock files) is: diff --git a/Cargo.toml b/Cargo.toml
index 410625c5f..4ecf30330 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -62,7 +62,7 @@ aho-corasick = "1"
anyhow = "1"
async-backtrace = "0.2"
async-trait = "0.1"
-aws-config = { version = "1.5", default-features = false, features = [
+aws-config = { version = "1.8", default-features = false, features = [
"behavior-version-latest",
"rustls",
"rt-tokio",
@@ -138,7 +138,7 @@ rattler_solve = { version = "4", default-features = false, features = [
"resolvo",
] }
rattler_package_streaming = { version = "0.24", default-features = false }
-rattler_virtual_packages = { version = "2", default-features = false }
+rattler_virtual_packages = { version = "2.3.10", default-features = false }
regex = "1"
reqwest = { version = "0.12", default-features = false, features = [
"json",
@@ -184,12 +184,12 @@ terminal_size = "0.4"
thiserror = "2"
tokio = { version = "1", features = ["full"] }
tokio-retry = "0.3"
-toml = { version = "0.9", features = ["parse", "preserve_order"] }
+toml = { version = "1.1", features = ["parse", "preserve_order"] }
toml_edit = { version = "0.24", features = ["parse"] }
ubi = { version = "0.8", default-features = false }
url = "2"
urlencoding = "2"
-usage-lib = { version = "2", features = ["clap", "docs"] }
+usage-lib = { version = "3.2", features = ["clap", "docs"] }
versions = { version = "6", features = ["serde"] }
vfox = { path = "crates/vfox", default-features = false }
aqua-registry = { path = "crates/aqua-registry" }
@@ -230,7 +230,7 @@ winapi = { version = "0.3.9", features = ["consoleapi", "minwindef"] }
built = { version = "0.8", features = ["chrono"] }
cfg_aliases = "0.2"
heck = "0.5"
-toml = "0.9"
+toml = "1.1"
indexmap = "2"
serde_yaml = "0.9"diff --git a/src/task/task_script_parser.rs b/src/task/task_script_parser.rs
index cf9961070..8f3b34604 100644
--- a/src/task/task_script_parser.rs
+++ b/src/task/task_script_parser.rs
@@ -624,10 +624,8 @@ impl TaskScriptParser {
// Check for deprecated Tera template args usage
Self::check_tera_args_deprecation(&task.name, &cmd.args, &cmd.flags);
- let mut spec = usage::Spec {
- cmd,
- ..Default::default()
- };
+ let mut spec = usage::Spec::default();
+ spec.cmd = cmd;
spec.merge(spec_from_field);
Ok(spec)
@@ -674,10 +672,8 @@ impl TaskScriptParser {
// Check for deprecated Tera template args usage
Self::check_tera_args_deprecation(&task.name, &cmd.args, &cmd.flags);
- let mut spec = usage::Spec {
- cmd,
- ..Default::default()
- };
+ let mut spec = usage::Spec::default();
+ spec.cmd = cmd;
spec.merge(spec_from_field);
Ok((scripts, spec))I assume @ndbeals is having similar issues that I was, and this resolves it |
The v2 help templates didn't include an Examples section, so `#USAGE example` directives parsed correctly but were silently dropped from --help output. usage-lib v3 added example rendering to its CLI help templates. This bump picks that up. The only code change is that Spec became non-exhaustive in v3, so struct literal construction is replaced with Default + field assignment (4 callsites). Two new tests: - test_usage_example_directives: verifies examples parse from script files and render in help output (usage-lib path) - test_usage_examples_survive_task_script_parser: verifies examples from task.usage survive through TaskScriptParser::parse_run_scripts merge pipeline (mise integration path) 560 tests pass, 0 failures.
has_any_usage_spec checked spec.cmd.examples but parse_script populates spec.examples (top-level). Add the missing check and an examples-only test case to cover scripts with no flags/args.
818ba68 to
f3367b4
Compare
|
Rebased on main — conflicts resolved, all 23 task_script_parser tests passing, build clean. @RobertDeRose — thanks for the patch! The @ndbeals — this should fix the v2/v3 mismatch you ran into. |
### 🚀 Features - **(config)** add lockfile_platforms setting to restrict lockfile platforms by @cameronbrill in [#8966](#8966) - **(sandbox)** support wildcard patterns in allow_env by @jdx in [#8974](#8974) - bump usage-lib v2 → v3 to render examples in task --help by @baby-joel in [#8890](#8890) ### 🐛 Bug Fixes - **(activate)** handle empty __MISE_FLAGS array with set -u on bash 3.2 by @jdx in [#8988](#8988) - **(env)** add trace logging for module hook PATH diagnostics by @jdx in [#8981](#8981) - **(go)** Query module proxy directly for version resolution by @c22 in [#8968](#8968) - **(install)** render tera templates in tool postinstall hooks by @jdx in [#8978](#8978) - **(install)** add missing env vars to tool postinstall hooks by @jdx in [#8977](#8977) - **(task)** prevent hang when skipped task has dependents by @jdx in [#8937](#8937) - **(task)** invalidate dependent task sources when dependency runs by @jdx in [#8975](#8975) - **(task)** prevent deadlock when MISE_JOBS=1 with sub-task references by @jdx in [#8976](#8976) - **(task)** fetch remote task files before parsing usage specs by @jdx in [#8979](#8979) - **(task)** prevent panic when running parallel sub-tasks with replacing output by @jdx in [#8986](#8986) - **(upgrade)** update lockfile and config when upgrading to specific version by @jdx in [#8983](#8983) ### 📚 Documentation - **(node)** remove "recommended for teams" from pin example by @jdx in [b334363](b334363) ### 📦️ Dependency Updates - update ghcr.io/jdx/mise:alpine docker digest to 17a29f2 by @renovate[bot] in [#8995](#8995) - update docker/dockerfile:1 docker digest to 2780b5c by @renovate[bot] in [#8994](#8994) ### New Contributors - @baby-joel made their first contribution in [#8890](#8890) - @cameronbrill made their first contribution in [#8966](#8966) - @c22 made their first contribution in [#8968](#8968)
Summary
#USAGE exampledirectives parse correctly but are silently dropped from--helpoutput. This is because usage-lib v2's CLI help templates don't include an Examples section.usage-lib v3 added example rendering to its help templates. This bump picks that up.
Before
After
Changes
Cargo.toml:usage-libversion"2"→"3"task_script_parser.rs: 4 callsites changed from struct literal init toDefault::default()+ field assignment (Specbecame non-exhaustive in v3)Testing
558 unit tests pass, 0 failures. Manually verified with file tasks using
#USAGE exampledirectives.