-
Notifications
You must be signed in to change notification settings - Fork 26
feat(parse): add Parser builder for custom env var handling #464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a Parser builder pattern to enable custom environment variable handling during command-line parsing. The primary motivation is to support tools like mise where monorepo tasks may define environment variables in child config files rather than the process environment.
Changes:
- Added a
Parserstruct with a builder pattern for configurable parsing options - Modified the existing
parse()function to useParserinternally while maintaining backward compatibility - Exported the new
Parsertype from the library's public API
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| lib/src/parse.rs | Implements the Parser builder struct with with_env() method and refactors environment variable lookups to use either custom or process environment |
| lib/src/lib.rs | Exports the new Parser type alongside the existing parse function |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let get_env = |key: &str| -> Option<String> { | ||
| if let Some(ref env_map) = self.env { | ||
| env_map.get(key).cloned() | ||
| } else { | ||
| // For var=false, return the first default value as String | ||
| out.args.insert( | ||
| Arc::new(arg.clone()), | ||
| ParseValue::String(arg.default[0].clone()), | ||
| ); | ||
| std::env::var(key).ok() | ||
| } | ||
| } | ||
| } | ||
| }; |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The get_env closure is defined inside the parse method but could be extracted as a private method on Parser. This would improve readability and make the logic easier to test independently. Consider adding a method like fn get_env_var(&self, key: &str) -> Option<String>.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #464 +/- ##
==========================================
- Coverage 76.50% 71.43% -5.08%
==========================================
Files 47 47
Lines 6253 6480 +227
Branches 6253 6480 +227
==========================================
- Hits 4784 4629 -155
- Misses 1110 1238 +128
- Partials 359 613 +254 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
lib/src/parse.rs
Outdated
| /// | ||
| /// Returns the parsed arguments and flags, with defaults and env vars applied. | ||
| pub fn parse(self, input: &[String]) -> Result<ParseOutput, miette::Error> { | ||
| let mut out = parse_partial(self.spec, input)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Custom env map ignored during required arg/flag validation
Medium Severity
When using Parser::with_env() with a custom environment map, required args/flags that have env vars defined will incorrectly fail validation if the env var exists in the custom map but not in the process environment. The parse_partial function validates required args/flags by checking std::env::var() directly (ignoring the custom env map), and adds MissingArg/MissingFlag errors before Parser::parse applies the custom env values. These errors then cause the parse to fail even though the env var would have been resolved correctly from the custom map.
Adds a Parser struct that allows customizing parsing behavior,
particularly for providing a custom environment variable map instead
of using the process environment.
This is useful for tools like mise where monorepo tasks may have
env vars defined in child config files that aren't in the current
process environment.
Example usage:
let env: HashMap<String, String> = [...].into();
let result = Parser::new(&spec)
.with_env(env)
.parse(&args)?;
The existing parse() function is now a thin wrapper that uses Parser
with default options.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
When using Parser::with_env() with a custom environment map, required args/flags that have env vars defined now correctly pass validation if the env var exists in the custom map. Previously, parse_partial validated required args/flags by checking std::env::var() directly, ignoring the custom env map. This caused validation to fail even though the env var would have been resolved correctly from the custom map during value application. This fix creates an internal parse_partial_with_env function that accepts the custom env map and uses it during validation. Co-Authored-By: Claude Opus 4.5 <[email protected]>
6e3d078 to
de2f437
Compare
|
bugbot run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
### 🚀 Features - **(parse)** add Parser builder for custom env var handling by [@jdx](https://github.com/jdx) in [#464](#464) ### 🧪 Testing - **(cli)** use fish output format for cleaner assertions by [@ilyagr](https://github.com/ilyagr) in [#461](#461) ### 🔍 Other Changes - add cargo-semver-checks to detect breaking changes by [@jdx](https://github.com/jdx) in [#463](#463)
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [usage](https://github.com/jdx/usage) | minor | `2.13.1` → `2.15.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> ### [`v2.15.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2150---2026-01-26) [Compare Source](jdx/usage@v2.14.0...v2.15.0) ##### 🚀 Features - **(parse)** add Parser builder for custom env var handling by [@​jdx](https://github.com/jdx) in [#​464](jdx/usage#464) ##### 🧪 Testing - **(cli)** use fish output format for cleaner assertions by [@​ilyagr](https://github.com/ilyagr) in [#​461](jdx/usage#461) ##### 🔍 Other Changes - add cargo-semver-checks to detect breaking changes by [@​jdx](https://github.com/jdx) in [#​463](jdx/usage#463) ### [`v2.14.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2140---2026-01-26) [Compare Source](jdx/usage@v2.13.1...v2.14.0) ##### 🚀 Features - **(lint)** add more lint checks by [@​jdx](https://github.com/jdx) in [#​446](jdx/usage#446) - add logo to docs site by [@​jdx](https://github.com/jdx) in [#​442](jdx/usage#442) - add VT323 retro terminal font and --usage branding by [@​jdx](https://github.com/jdx) in [#​443](jdx/usage#443) - add missing builder methods by [@​jdx](https://github.com/jdx) in [#​444](jdx/usage#444) ##### 🐛 Bug Fixes - use pithy LLM-generated title for GitHub releases by [@​jdx](https://github.com/jdx) in [#​441](jdx/usage#441) - replace unwrap calls with proper error handling in fig.rs by [@​jdx](https://github.com/jdx) in [#​454](jdx/usage#454) - improve error messages with more context by [@​jdx](https://github.com/jdx) in [#​449](jdx/usage#449) - skip powershell test if pwsh is not installed by [@​jdx](https://github.com/jdx) in [#​457](jdx/usage#457) - match completion prefix against unescaped names by [@​ilyagr](https://github.com/ilyagr) in [#​460](jdx/usage#460) ##### 🚜 Refactor - simplify Spec::merge with local macros by [@​jdx](https://github.com/jdx) in [#​451](jdx/usage#451) ##### 📚 Documentation - add CLAUDE.md for Claude Code guidance by [@​jdx](https://github.com/jdx) in [#​452](jdx/usage#452) - escape generic type parameters in macro doc comments by [@​jdx](https://github.com/jdx) in [#​453](jdx/usage#453) - add rustdoc for public API functions by [@​jdx](https://github.com/jdx) in [#​450](jdx/usage#450) - add documentation to public API structs by [@​jdx](https://github.com/jdx) in [#​455](jdx/usage#455) - add conventional commit guidance to CLAUDE.md by [@​jdx](https://github.com/jdx) in [#​459](jdx/usage#459) ##### ⚡ Performance - remove unnecessary clone in set\_subcommand\_ancestors by [@​jdx](https://github.com/jdx) in [#​448](jdx/usage#448) ##### 🧪 Testing - add test coverage for untested modules by [@​jdx](https://github.com/jdx) in [#​447](jdx/usage#447) ##### 🔍 Other Changes - remove commented-out trait implementations in mount.rs by [@​jdx](https://github.com/jdx) in [#​445](jdx/usage#445) - make codecov checks informational by [@​jdx](https://github.com/jdx) in [#​456](jdx/usage#456) ##### 📦️ Dependency Updates - lock file maintenance by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​439](jdx/usage#439) ##### New Contributors - [@​ilyagr](https://github.com/ilyagr) made their first contribution in [#​460](jdx/usage#460) </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:eyJjcmVhdGVkSW5WZXIiOiI0Mi45MC4wIiwidXBkYXRlZEluVmVyIjoiNDIuOTIuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
Summary
Parserstruct that allows customizing parsing behaviorThis is needed for tools like mise where monorepo tasks may have env vars defined in child config files that aren't in the current process environment.
Example usage
The existing
parse()function is unchanged and continues to work as before (it now usesParserinternally with default options).API Design
The
Parserstruct uses#[non_exhaustive]to allow adding new options in the future without breaking changes.🤖 Generated with Claude Code
Note
Introduce
Parserfor customizable parsingparse::Parserwithwith_envto supply a customHashMap<String, String>for env lookups;parse()now delegates toParserparse_partialinto internalparse_partial_with_envand update required arg/flag validation to consider the custom env map beforestd::envPublic API:
Parserexported vialib.rsWritten by Cursor Bugbot for commit 6294833. This will update automatically on new commits. Configure here.