Skip to content

Support env-backed choices with choices env=...#548

Merged
jdx merged 13 commits intojdx:mainfrom
mustafa0x:choices-env-pr
Mar 23, 2026
Merged

Support env-backed choices with choices env=...#548
jdx merged 13 commits intojdx:mainfrom
mustafa0x:choices-env-pr

Conversation

@mustafa0x
Copy link
Copy Markdown
Contributor

@mustafa0x mustafa0x commented Mar 18, 2026

Summary

  • add env support to choices so specs can source allowed values from an environment variable
  • honor Parser::with_env(...) without falling back to the process environment when a custom env map is provided
  • reject explicit values when choices env=... resolves to no values instead of silently disabling validation
  • preserve choices env=... when SpecArgBuilder::choices() is called after choices_env(...)
  • resolve env-backed choices for interactive shell completion at completion time
  • preserve choices env=... in help/docs instead of snapshotting live env-backed values into generated output
  • keep Fig suggestions literal-only so usage generate fig does not bake generation-time environment values into a static file

Example

arg "<env>" {
  choices env="DEPLOY_ENVS"
}

With DEPLOY_ENVS="foo,bar baz", valid values become foo, bar, and baz.

Implementation notes

  • choices now accepts an optional env property and preserves it when serializing back to KDL
  • env-backed values are split on commas and/or whitespace, with empty entries ignored
  • env-backed values are appended after literal choices and deduplicated against existing entries
  • parsing uses the caller-provided env map when Parser::with_env(...) is used; it only consults the process environment when no custom env map is provided
  • env-backed choices that resolve to no values now fail validation for explicit CLI input with a targeted error message instead of accepting any value
  • SpecArgBuilder::choices() now preserves any previously configured choices_env(...)
  • help/docs render literal choices as before and also surface the controlling env var for env-backed choices

Tests

  • unit tests for env choice splitting and deduplication
  • parser tests covering arg/flag validation with Parser::with_env(...)
  • parser test covering the empty env-backed choice set case
  • builder test covering .choices_env(...).choices(...) ordering
  • completion test covering env-backed choices
  • dump test covering KDL round-tripping

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the application's argument parsing capabilities by allowing choices for arguments and flags to be dynamically sourced from environment variables. This provides greater flexibility in configuring the application's behavior based on the environment in which it is run.

Highlights

  • Environment Variable Choices: This PR introduces the ability to source argument and flag choices from environment variables using the choices env="..." syntax.
  • Consistent Resolution: The changes ensure that environment-backed choices are resolved consistently across parsing, help/documentation generation, shell completion, and Fig suggestions.
  • KDL Round-Tripping: The PR includes updates to preserve the env property when serializing choices back to KDL, ensuring proper round-tripping.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request successfully introduces support for environment-backed choices using the choices env=... syntax. The implementation is thorough, covering parsing, shell completion, documentation generation, and KDL serialization. The refactoring of choice validation into a dedicated function improves code organization and readability. New tests adequately cover the added functionality, ensuring correctness and robustness.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a84853de12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/src/spec/choices.rs Outdated
Comment on lines +50 to +52
let env_value = env
.and_then(|env_map| env_map.get(env_key).cloned())
.or_else(|| std::env::var(env_key).ok());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep Parser::with_env isolated from process env

When callers use Parser::with_env to parse against a supplied environment map, this path still falls back to std::env::var, so choices env=... can be validated against ambient host variables that were never provided by the caller. That breaks the documented with_env contract in lib/src/parse.rs (“instead of the process environment”) and makes parsing nondeterministic in tests/monorepo tooling—for example, with_env(HashMap::new()) will still reject inputs if the parent process happens to export the same choice variable.

Useful? React with 👍 / 👎.

Comment thread cli/src/cli/generate/fig.rs Outdated
template: FigArg::get_template(&arg.name),
generators: FigArg::get_generator(&arg.name),
suggestions: arg.choices.clone().map(|c| c.choices).unwrap_or_default(),
suggestions: arg.choices.as_ref().map(|c| c.values()).unwrap_or_default(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid baking current env into generated Fig suggestions

usage generate fig writes a static completion file, but this now resolves choices env=... immediately into suggestions. That means the generated script snapshots whatever environment was present when usage generate fig ran (or nothing at all if the variable was unset), so users of a checked-in/CI-generated Fig spec will see stale or empty suggestions instead of their own runtime env-backed choices.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 18, 2026

Greptile Summary

This PR adds choices env=... support to the usage KDL spec format, allowing allowed values for args and flags to be sourced from an environment variable at parse and completion time rather than hard-coded in the spec. It is guarded by the unstable_choices_env feature flag.

Key changes:

  • SpecChoices gains an optional env field; values_with_env(custom_env) resolves literal + env-backed choices, correctly using the caller-supplied map exclusively when Parser::with_env(...) is active and falling back to std::env::var only when no custom map is provided.
  • Choice validation is refactored into choice_error / validate_choices / validate_choice_value helpers and threaded through all parse paths (explicit CLI values, env-var defaults, scalar and variadic defaults).
  • Shell completion uses choices.values() (process env) which is correct for the interactive shell context; the new has_explicit_choices flag prevents file-path fallback when an env-backed choices constraint is configured but resolves to empty at completion time.
  • The SpecArgBuilder::choices() builder method now preserves a previously set choices_env(), avoiding silent loss of the env key when both are combined.
  • Help output and Markdown docs render the env var name directly instead of snapshotting live values, so documentation stays meaningful when the env var is absent at generation time.
  • Fig static output continues to use only literal choices, avoiding baking runtime env values into the generated file.
  • Tests cover splitting/deduplication, parser validation with a custom env map, empty-env error messages, builder ordering, KDL round-tripping, and shell completions.

Confidence Score: 4/5

  • PR is on the happy path to merge; previous thread concerns are addressed and no new blocking issues found.
  • All three concerns raised in prior review rounds appear to be resolved: values_with_env now correctly isolates the custom env map from the process environment; the Tera templates render the env key rather than snapshotting live values; and the new unstable_choices_env tests avoid process-env mutation entirely. No new P0/P1 issues were identified. Score is 4 rather than 5 only because the feature is brand-new and gated behind unstable_choices_env, warranting a brief stabilisation period before broader adoption.
  • lib/src/parse.rs — three pre-existing tests (test_parser_with_custom_env_for_required_arg, test_parser_with_custom_env_for_required_flag, test_parser_with_custom_env_still_fails_when_missing) still call std::env::remove_var outside unsafe; this was flagged in a prior review thread and does not affect production correctness.

Important Files Changed

Filename Overview
lib/src/spec/choices.rs Core change: adds optional feature-gated env field, values_with_env(env) method that only falls back to process env when no custom map is provided, and KDL serialization of env=... property; logic is sound and properly isolated.
lib/src/parse.rs Threads custom_env through all choice-validation paths; introduces ChoiceTarget, choice_error, validate_choices, validate_choice_value, and validate_choice_values; three pre-existing tests still call std::env::remove_var outside unsafe (flagged in a prior review thread); no new issues with the feature-gated tests.
cli/src/cli/complete_word.rs Adds has_explicit_choices to suppress file-path fallback when a choices env=... constraint is configured but resolves to empty; completions correctly call choices.values() (process env) rather than a custom env map.
lib/src/spec/builder.rs Updated choices() to preserve an existing choices_env() setting when the feature is enabled; new choices_env() builder method is cleanly feature-gated; tests cover both orderings.
lib/src/docs/cli/templates/spec_template_long.tera Templates now separately render literal choices and the choices env name, correctly preserving the env reference at doc-generation time instead of resolving live values.
lib/tests/dump.rs Adds a feature-gated KDL round-trip test confirming choices env=DEPLOY_ENVS serialises and parses back to the same representation.
cli/tests/complete_word.rs Three new completion tests cover env-backed values, unset env (empty output), and the default-subcommand file-fallback regression; all use .env() / .env_remove() on the test command, not process-env mutation.
examples/env-choices.usage.kdl Minimal KDL fixture used by the new completion tests; correct syntax.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI user
    participant PW as parse_partial_with_env
    participant VC as validate_choices
    participant CE as choice_error
    participant SC as SpecChoices::values_with_env
    participant ENV as Environment

    CLI->>PW: parse(["--env", "prod"], custom_env)
    PW->>VC: validate_choices(target, "prod", choices, custom_env)
    VC->>SC: values_with_env(custom_env)
    alt custom_env provided (Parser::with_env)
        SC->>SC: lookup key in custom_env map only
    else no custom_env
        SC->>ENV: std::env::var(env_key)
        ENV-->>SC: env value (or None)
    end
    SC-->>VC: ["dev", "staging"] (split on comma/whitespace, deduped)
    VC->>VC: is_help_arg? and value not in list?
    VC-->>PW: Ok(true) — push help error & return early
    VC->>CE: choice_error(target, "prod", choices, custom_env)
    alt values is empty (env unset)
        CE-->>VC: "no choices resolved from env DEPLOY_ENVS"
    else value not in list
        CE-->>VC: "expected one of dev, staging"
    else value found
        CE-->>VC: None (valid)
    end
    VC-->>PW: bail!(err) or Ok(false)
    PW-->>CLI: ParseOutput or Error
Loading

Reviews (6): Last reviewed commit: "parse: fast-path help choice checks befo..." | Re-trigger Greptile

Comment thread lib/src/spec/choices.rs
Comment thread lib/src/parse.rs Outdated
Comment thread lib/src/docs/models.rs Outdated
@mustafa0x
Copy link
Copy Markdown
Contributor Author

Addressed review feedback in 5519652.

Changes made:

  • fixed SpecChoices::values_with_env(...) to avoid process-env fallback when Parser::with_env(...) provides a custom env map
  • reverted Fig suggestions to literal choices only (no env snapshot at generation time)
  • docs/help now preserve and render choices env: ... instead of resolving away env-backed source
  • removed unnecessary std::env::remove_var(...) calls from parser tests
  • added a guard test for no-fallback behavior with custom env maps

I could not run cargo test in this container because cargo is not available on PATH here.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 55196528b5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/src/parse.rs Outdated
Comment on lines +649 to +650
let values = choices.values_with_env(custom_env);
if !values.is_empty() && !values.iter().any(|choice| choice == value) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject inputs when env-backed choices resolve to no values

For specs that use only choices env=..., values_with_env returns an empty list when that variable is unset, and this guard then skips validation entirely. That means any explicit CLI value is accepted even though the spec declared a constrained choice set, so a missing env var in CI or a custom Parser::with_env map silently disables the new restriction instead of failing fast.

Useful? React with 👍 / 👎.

Comment thread lib/src/spec/builder.rs Outdated
Comment on lines 310 to 313
self.inner.choices = Some(SpecChoices {
choices: choices.into_iter().map(Into::into).collect(),
env: None,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve choices_env when choices() is called later

The new builder API is order-sensitive here: choices() recreates SpecChoices with env: None, so .choices_env("DEPLOY_ENVS").choices(["local"]) drops the env-backed values completely. Callers building specs programmatically can easily hit this and end up with parser/completion behavior that no longer matches the intended combined literal+env choices.

Useful? React with 👍 / 👎.

@mustafa0x
Copy link
Copy Markdown
Contributor Author

Addressed the two additional review comments in c49eff4.

Updates:

  • validate_choices(...) now rejects explicit values when choices env=... resolves to an empty set, with a targeted error message
  • SpecArgBuilder::choices() now preserves an existing choices_env(...) configuration instead of replacing SpecChoices
  • added focused tests for both cases (parse empty-env behavior and builder ordering preservation)

I also updated the PR description to the v3 message.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c49eff4d7d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cli/src/cli/complete_word.rs Outdated
Comment on lines +268 to +270
if let Some(choices) = &arg.choices {
return Ok(choices
.choices
.iter()
.map(|c| (c.clone(), String::new()))
.filter(|(c, _)| c.starts_with(ctoken))
.collect());
let values = choices.values();
if !values.is_empty() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return no completions when env-backed choices resolve empty

When an arg/flag is constrained only by choices env=... and that variable is unset in the completion process, choices.values() is empty and this branch falls through instead of short-circuiting. In complete_word(), an empty result is then treated as “no known completion” and we fall back to complete.run/filesystem suggestions, so pressing Tab for examples/env-choices.usage.kdl with DEPLOY_ENVS unset will suggest arbitrary paths even though the parser rejects every value. Treating the presence of arg.choices as authoritative here avoids advertising impossible completions.

Useful? React with 👍 / 👎.

@mustafa0x
Copy link
Copy Markdown
Contributor Author

Addressed the latest completion feedback in de8e0d1.

Changes:

  • completion now treats explicit arg.choices as authoritative and skips filesystem fallback even when resolved values are empty (e.g. choices env=... unset)
  • added regression test: complete_word_choices_from_env_unset_returns_empty

Verification run:

  • mise x -- cargo test -p usage-cli complete_word_choices_from_env (passes, including the new test).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de8e0d15a5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/src/parse.rs
Comment on lines +504 to +512
if validate_choices(
spec,
&out.cmd,
&mut out.errors,
"arg",
&arg.name,
&w,
arg.choices.as_ref(),
custom_env,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Revalidate env/default-populated values against resolved choices

The new choice check only runs while consuming argv words here. Parser::parse still fills missing args/flags from arg.env, flag.env, and defaults afterwards without rechecking them, so a spec like arg <env> env="CURRENT_ENV" { choices env="DEPLOY_ENVS" } will accept CURRENT_ENV=prod even when DEPLOY_ENVS=dev,staging. That means the new choices env=... constraint is bypassed whenever the value comes from env/defaults instead of the command line.

Useful? React with 👍 / 👎.

Comment thread cli/src/cli/complete_word.rs Outdated
if let Some(default_cmd) = spec.cmd.find_subcommand(default_name) {
// Include completions from default subcommand's first arg
if let Some(arg) = default_cmd.args.first() {
has_explicit_choices = has_explicit_choices || arg.choices.is_some();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep root file fallback when default subcommand has choices

This marks has_explicit_choices based on the default subcommand's first arg even when the active completion target is still a root positional arg. In CompleteWord::complete_word, that suppresses the file fallback at lines 161-165, so a command shaped like cmd <path> loses filesystem suggestions as soon as its default_subcommand happens to start with a choices-constrained arg.

Useful? React with 👍 / 👎.

@mustafa0x
Copy link
Copy Markdown
Contributor Author

Addressed the latest two review comments in 82adee1.

Fixes:

  • revalidated env/default-populated arg/flag values against choices during Parser::parse (not only argv-consumed values)
  • kept root path fallback behavior when default-subcommand arg has choices by narrowing when explicit choices suppress fallback

Regression tests added:

  • test_parser_rejects_arg_env_value_not_in_choices_env
  • test_parser_rejects_flag_default_value_not_in_choices_env
  • complete_word_default_subcommand_choices_do_not_block_root_file_fallback

Targeted verification:

  • mise x -- cargo test -p usage-lib test_parser_rejects_arg_env_value_not_in_choices_env
  • mise x -- cargo test -p usage-lib test_parser_rejects_flag_default_value_not_in_choices_env
  • mise x -- cargo test -p usage-cli complete_word_default_subcommand_choices_do_not_block_root_file_fallback

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

if let Some(arg) = default_cmd.args.first() {
choices.extend(self.complete_arg(

P2 Badge Mark default-subcommand choices before falling back to files

When the root command has no positional arg of its own but default_subcommand does, this branch appends the default subcommand’s first-arg completions without updating has_explicit_choices. If the current token matches none of those choices, line 161 falls back to filesystem suggestions even though parse() will route that word into the default subcommand and reject every path. A spec like default_subcommand "run" with cmd "run" { arg "<env>" { choices "prod" "staging" } } will therefore suggest files for tool x<Tab> instead of returning no completions.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/src/parse.rs Outdated
Comment on lines +123 to +127
if !arg.default.is_empty() {
for default_value in &arg.default {
validate_choices(
self.spec,
&out.cmd,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate only the default value a scalar arg can emit

For non-variadic args, parse() still returns only arg.default[0], but this new loop rejects every entry in arg.default before we reach that branch. Specs built with SpecArgBuilder::default_values([..]) (which the builder tests already allow for scalar args) will now start failing choice validation on later defaults that are never observable at runtime—for example, default_values(["dev", "prod"]) plus choices ["dev"] now errors even though parsing would still yield "dev". The same regression is repeated in the nested flag-arg default block below.

Useful? React with 👍 / 👎.

@jdx
Copy link
Copy Markdown
Owner

jdx commented Mar 22, 2026

i think you need to rebase

@jdx jdx marked this pull request as draft March 22, 2026 16:34
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 22, 2026

Codecov Report

❌ Patch coverage is 67.06349% with 166 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.94%. Comparing base (1e81f1b) to head (bffa882).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
lib/src/parse.rs 66.75% 30 Missing and 89 partials ⚠️
lib/src/spec/choices.rs 79.34% 16 Missing and 3 partials ⚠️
cli/src/cli/complete_word.rs 0.00% 1 Missing and 10 partials ⚠️
lib/src/spec/builder.rs 74.28% 5 Missing and 4 partials ⚠️
lib/src/spec/arg.rs 0.00% 4 Missing ⚠️
lib/src/spec/flag.rs 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #548      +/-   ##
==========================================
- Coverage   70.04%   61.94%   -8.10%     
==========================================
  Files          48       48              
  Lines        7080     7629     +549     
  Branches     7080     7629     +549     
==========================================
- Hits         4959     4726     -233     
- Misses       1322     1542     +220     
- Partials      799     1361     +562     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mustafa0x
Copy link
Copy Markdown
Contributor Author

Addressed the latest review comment in 90f47e9.

What changed:

  • for scalar defaults (var=false), choice validation now checks only the emitted default value (default[0]), not every configured default entry
  • this applies to both scalar args and scalar nested flag-arg defaults
  • kept full-list validation for variadic defaults (var=true)

Regression coverage added:

  • test_arg_var_false_validates_only_first_default_choice
  • test_flag_arg_default_var_false_validates_only_first_default_choice

Targeted verification:

  • mise x -- cargo test -p usage-lib test_arg_var_false_validates_only_first_default_choice
  • mise x -- cargo test -p usage-lib test_flag_arg_default_var_false_validates_only_first_default_choice
  • mise x -- cargo test -p usage-lib test_parser_rejects_flag_default_value_not_in_choices_env

@mustafa0x
Copy link
Copy Markdown
Contributor Author

Addressed the latest scalar-default review point and the current CI lint failure in 26ab9f3.

Changes:

  • scalar-default choice validation now checks only the emitted value (default[0]) for var=false
  • variadic defaults (var=true) still validate all default values
  • fixed clippy-denied patterns in parser/choices code (unnecessary_unwrap, field_reassign_with_default, and argument-count shape via ChoiceTarget)

Local verification:

  • mise x -- cargo fmt --all
  • mise x -- cargo clippy --all --all-features -- -D warnings
  • focused tests for scalar-default and env/default choice behavior still pass

@jdx
Copy link
Copy Markdown
Owner

jdx commented Mar 23, 2026

is it ready?

@mustafa0x
Copy link
Copy Markdown
Contributor Author

is it ready?

I hope so! Full disclaimer: heavily AI-assisted.

@jdx jdx marked this pull request as ready for review March 23, 2026 14:05
@jdx jdx merged commit f1af365 into jdx:main Mar 23, 2026
8 checks passed
@mustafa0x mustafa0x deleted the choices-env-pr branch March 23, 2026 18:16
jdx pushed a commit that referenced this pull request Mar 23, 2026
### 🚀 Features

- Support env-backed choices with `choices env=...` by
[@mustafa0x](https://github.com/mustafa0x) in
[#548](#548)

### 🐛 Bug Fixes

- **(zsh)** escape parentheses and brackets in completion descriptions
by [@jdx](https://github.com/jdx) in
[#559](#559)

### New Contributors

- @mustafa0x made their first contribution in
[#548](#548)
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Apr 2, 2026
⚠️ **CAUTION: this is a major update, indicating a breaking change!** ⚠️

This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [usage](https://github.com/jdx/usage) | major | `2.18.2` → `3.2.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>jdx/usage (usage)</summary>

### [`v3.2.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#320---2026-03-23)

[Compare Source](jdx/usage@v3.1.0...v3.2.0)

##### 🚀 Features

- Support env-backed choices with `choices env=...` by [@&#8203;mustafa0x](https://github.com/mustafa0x) in [#&#8203;548](jdx/usage#548)

##### 🐛 Bug Fixes

- **(zsh)** escape parentheses and brackets in completion descriptions by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;559](jdx/usage#559)

##### New Contributors

- [@&#8203;mustafa0x](https://github.com/mustafa0x) made their first contribution in [#&#8203;548](jdx/usage#548)

### [`v3.1.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#310---2026-03-22)

[Compare Source](jdx/usage@v3.0.0...v3.1.0)

##### 🚀 Features

- **(cli)** render all doc-related fields in --help output by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;554](jdx/usage#554)
- **(cli)** support reading spec from stdin via --file - by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;555](jdx/usage#555)

##### 🐛 Bug Fixes

- **(zsh)** remove trailing space from completions and add directory slash by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;556](jdx/usage#556)
- use field assignment for non-exhaustive Spec in benchmarks by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;552](jdx/usage#552)

##### 📦️ Dependency Updates

- update apple-actions/import-codesign-certs digest to [`fe74d46`](jdx/usage@fe74d46) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;550](jdx/usage#550)
- update codecov/codecov-action digest to [`1af5884`](jdx/usage@1af5884) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;551](jdx/usage#551)
- lock file maintenance by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;547](jdx/usage#547)

### [`v3.0.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#300---2026-03-13)

[Compare Source](jdx/usage@v2.18.2...v3.0.0)

##### 🚀 Features

- **(spec)** **breaking** add support for license, before/after help metadata by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;542](jdx/usage#542)

##### 🐛 Bug Fixes

- **(cobra)** escape newlines, tabs, and carriage returns in kdlQuoteAlways by [@&#8203;thecodesmith](https://github.com/thecodesmith) in [#&#8203;539](jdx/usage#539)
- bump major version for breaking changes in release automation by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;544](jdx/usage#544)
- add custom\_major\_increment\_regex for breaking change detection by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;545](jdx/usage#545)
- handle all breaking change commit formats in major bump regex by [@&#8203;jdx](https://github.com/jdx) in [27e1ab1](jdx/usage@27e1ab1)
- normalize breaking change commit format in preprocessor by [@&#8203;jdx](https://github.com/jdx) in [aa72b92](jdx/usage@aa72b92)

##### 📚 Documentation

- add argparse-usage integration by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;531](jdx/usage#531)
- mark KDL code blocks as KDL and use correct inline-comment `//` by [@&#8203;muzimuzhi](https://github.com/muzimuzhi) in [#&#8203;536](jdx/usage#536)
- fix include syntax to match implementation by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;540](jdx/usage#540)
- consolidate integration list to single source by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;541](jdx/usage#541)
- fix link to integrations by [@&#8203;muzimuzhi](https://github.com/muzimuzhi) in [#&#8203;543](jdx/usage#543)

##### 🛡️ Security

- **(deps)** update dependency eslint to v10 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;526](jdx/usage#526)

##### 🔍 Other Changes

- Added an integration with ruby's OptionParser by [@&#8203;packrat386](https://github.com/packrat386) in [#&#8203;533](jdx/usage#533)

##### 📦️ Dependency Updates

- update actions/setup-node digest to [`53b8394`](jdx/usage@53b8394) by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;525](jdx/usage#525)
- update jdx/mise-action action to v3 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;528](jdx/usage#528)
- update rust crate roff to v1 by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;529](jdx/usage#529)

##### New Contributors

- [@&#8203;thecodesmith](https://github.com/thecodesmith) made their first contribution in [#&#8203;539](jdx/usage#539)
- [@&#8203;packrat386](https://github.com/packrat386) made their first contribution in [#&#8203;533](jdx/usage#533)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDIuMTAiLCJ1cGRhdGVkSW5WZXIiOiI0My4xMDIuMTAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbIlJlbm92YXRlIEJvdCIsImF1dG9tYXRpb246Ym90LWF1dGhvcmVkIiwiZGVwZW5kZW5jeS10eXBlOjptYWpvciJdfQ==-->
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.

2 participants