fix(install): preserve config options and registry defaults#8044
Conversation
…LI version When running `mise install tool@version` for a tool that has options (e.g. postinstall) in mise.toml, the config options were lost because: 1. CLI args replaced config entries in the ToolRequestSet merge without preserving config options like postinstall 2. init_request_options() used backend arg opts (empty for CLI tools) instead of config request options, overwriting any merged options This fix: - Merges config options into CLI tool requests in load_runtime_args() when the CLI request has no options of its own - Updates init_request_options() to prefer config request options over backend arg opts Fixes #7979 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary of ChangesHello @jdx, 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 addresses a critical bug in Highlights
Changelog
Activity
Using Gemini Code AssistThe 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
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 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. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Pull request overview
Fixes mise install tool@version dropping tool options from mise.toml by preserving/merging request options when a CLI version is explicitly provided.
Changes:
- Prefer config-derived tool options (e.g.,
postinstall) during install option initialization. - Merge config options into CLI tool requests when CLI specifies a version but omits options.
- Add an e2e regression test ensuring
postinstallruns formise install dummy@latest.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/toolset/toolset_install.rs | Pulls options from config requests (when present) instead of only backend arg opts. |
| src/toolset/tool_request_set.rs | Merges config options into CLI-provided version requests to retain tool config. |
| e2e/cli/test_install_postinstall_cli_version | Adds regression test validating postinstall runs with explicit CLI version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/toolset/toolset_install.rs
Outdated
| let config_opts = tvl.requests.first().map(|r| r.options()); | ||
| let options = if let Some(ref opts) = config_opts | ||
| && !opts.is_empty() | ||
| { | ||
| opts.clone() | ||
| } else { | ||
| tvl.backend.opts() | ||
| }; |
There was a problem hiding this comment.
The comment says 'Use config request options if available', but the implementation reads tvl.requests.first() without ensuring that the first request is actually the config-sourced request. If request ordering changes (or the first request is the CLI/argument request), this can still skip config options. Consider selecting the request by source (e.g., find the config ToolRequest in tvl.requests) rather than relying on .first().
src/toolset/toolset_install.rs
Outdated
| let config_opts = tvl.requests.first().map(|r| r.options()); | ||
| let options = if let Some(ref opts) = config_opts | ||
| && !opts.is_empty() | ||
| { | ||
| opts.clone() |
There was a problem hiding this comment.
This clones opts after already materializing options into config_opts. You can avoid the extra clone by taking ownership of the options (e.g., using an iterator/filter pattern to directly produce an owned ToolVersionOptions when non-empty). This reduces allocations/copies when options are present.
| let config_opts = tvl.requests.first().map(|r| r.options()); | |
| let options = if let Some(ref opts) = config_opts | |
| && !opts.is_empty() | |
| { | |
| opts.clone() | |
| let options = if let Some(opts) = tvl | |
| .requests | |
| .first() | |
| .map(|r| r.options()) | |
| .filter(|opts| !opts.is_empty()) | |
| { | |
| opts |
| # Remove any existing dummy installation to force reinstall | ||
| rm -rf ~/.local/share/mise/installs/dummy |
There was a problem hiding this comment.
The test hard-codes the install location under ~/.local/share/mise, which may not match the test environment if $HOME, XDG_DATA_HOME, or a tool-specific MISE_DATA_DIR is set by the harness. Use the configured mise data dir (env var if available) or a mise command/API used elsewhere in the test suite to resolve the installs path before deleting.
| @@ -0,0 +1,37 @@ | |||
| #!/usr/bin/env bash | |||
There was a problem hiding this comment.
Consider adding set -euo pipefail near the top so unexpected command failures or unset variables fail the test immediately. This tends to make e2e failures more deterministic and easier to diagnose.
| #!/usr/bin/env bash | |
| #!/usr/bin/env bash | |
| set -euo pipefail |
There was a problem hiding this comment.
Code Review
This pull request effectively addresses an issue where configuration options were being dropped when installing a tool with an explicit version from the command line. The changes in tool_request_set.rs and toolset_install.rs correctly preserve these options by merging them from the configuration. The addition of a new end-to-end test provides solid verification for this fix. The logic is sound, and I have a couple of suggestions to make the Rust code more idiomatic and maintainable.
src/toolset/tool_request_set.rs
Outdated
| if let Some(config_versions) = trs.tools.get(&arg.ba) { | ||
| if let Some(config_tvr) = config_versions.first() { | ||
| let config_opts = config_tvr.options(); | ||
| if !config_opts.is_empty() { | ||
| tvr.set_options(config_opts); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The nested if let statements can be simplified by using and_then to make the code more concise and less nested. This improves readability.
if let Some(config_tvr) = trs.tools.get(&arg.ba).and_then(|v| v.first()) {
let config_opts = config_tvr.options();
if !config_opts.is_empty() {
tvr.set_options(config_opts);
}
}
src/toolset/toolset_install.rs
Outdated
| let options = if let Some(ref opts) = config_opts | ||
| && !opts.is_empty() | ||
| { | ||
| opts.clone() | ||
| } else { | ||
| tvl.backend.opts() | ||
| }; |
There was a problem hiding this comment.
When using table syntax like `ansible = { version = "latest" }`, install-time
registry defaults (e.g. uvx=false, pipx_args=--include-deps) were being
stripped. The install-time key filtering in mise_toml.rs correctly removes
stale install-state cache but also removed registry defaults. After filtering
and merging user options, re-apply registry defaults for any keys not
explicitly set by the user.
Fixes #8039
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Simplify nested if-let chains with and_then and Option::filter - Use $MISE_DATA_DIR instead of hardcoded path in e2e test Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.6 x -- echo |
21.6 ± 0.3 | 21.0 | 24.3 | 1.00 |
mise x -- echo |
22.6 ± 0.6 | 21.8 | 26.1 | 1.05 ± 0.03 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.6 env |
21.1 ± 0.6 | 20.4 | 27.6 | 1.00 |
mise env |
22.0 ± 0.6 | 20.8 | 25.6 | 1.04 ± 0.04 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.6 hook-env |
22.0 ± 0.3 | 21.3 | 23.8 | 1.00 |
mise hook-env |
22.6 ± 0.4 | 21.9 | 25.5 | 1.03 ± 0.02 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.6 ls |
20.0 ± 0.5 | 19.3 | 25.0 | 1.00 |
mise ls |
20.5 ± 0.4 | 19.8 | 22.1 | 1.02 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.2.6 | mise | Variance |
|---|---|---|---|
| install (cached) | 115ms | 117ms | -1% |
| ls (cached) | 73ms | 74ms | -1% |
| bin-paths (cached) | 77ms | 78ms | -1% |
| task-ls (cached) | 554ms | 555ms | +0% |
|
bugbot run |
### 🚀 Features - **(shim)** add native .exe shim mode for Windows by @jdx in [#8045](#8045) ### 🐛 Bug Fixes - **(install)** preserve config options and registry defaults by @jdx in [#8044](#8044) - **(link)** linked versions override lockfile during resolution by @jdx in [#8050](#8050) - **(release)** preserve aqua-registry sections in changelog across releases by @jdx in [#8047](#8047) - ls --all-sources shows duplicate entries by @roele in [#8042](#8042) ### 📚 Documentation - replace "inherit" terminology with config layering by @jdx in [#8046](#8046) ### 📦 Registry - switch oxlint to npm backend by default by @risu729 in [#8038](#8038) - add orval (npm:orval) by @zdunecki in [#8051](#8051) ### New Contributors - @zdunecki made their first contribution in [#8051](#8051)
## Summary - **fix(install): preserve config options when installing with explicit CLI version** — When running `mise install tool@version` with an explicit version, tool-level config options (e.g. `postinstall`) from `mise.toml` were being lost. The CLI args merge in `load_runtime_args()` replaced config entries entirely, and `init_request_options()` overwrote options with empty backend arg opts. Fixed by merging config options into CLI requests and preferring config request options in `init_request_options()`. - **fix(config): preserve registry defaults when using table syntax (jdx#8039)** — When using table syntax like `ansible = { version = "latest" }`, install-time registry defaults (e.g. `uvx=false`, `pipx_args=--include-deps`) were stripped. The install-time key filtering correctly removes stale install-state cache, but also removed registry defaults. Fixed by re-applying registry defaults after filtering for any keys not explicitly set by the user. ## Test plan - [x] New e2e test `test_install_postinstall_cli_version` verifies postinstall fires with both `mise install dummy@latest` and `mise install dummy` - [x] New unit test `test_table_syntax_preserves_registry_defaults` verifies registry defaults (uvx, pipx_args) are preserved with table syntax and that user overrides take precedence - [x] All 447 unit tests pass - [x] All lints pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes tool option resolution/merging during installs and config parsing, which can subtly affect install behavior across many backends. Coverage is improved via new e2e/unit tests, but option precedence changes may have edge cases. > > **Overview** > Ensures tool installs invoked with an explicit CLI version (e.g. `mise install dummy@latest`) still inherit tool options defined in `mise.toml` (notably `postinstall`) by merging config options into argument-sourced `ToolRequest`s and preferring config request options during install request initialization. > > Fixes a regression in `mise.toml` *table syntax* tool definitions where filtering install-time keys also removed registry defaults; registry default options are now re-applied for keys the user didn’t override. Adds an e2e regression test for `postinstall` behavior and a unit test verifying registry defaults are preserved and user overrides win. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 039ab54. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### 🚀 Features - **(shim)** add native .exe shim mode for Windows by @jdx in [jdx#8045](jdx#8045) ### 🐛 Bug Fixes - **(install)** preserve config options and registry defaults by @jdx in [jdx#8044](jdx#8044) - **(link)** linked versions override lockfile during resolution by @jdx in [jdx#8050](jdx#8050) - **(release)** preserve aqua-registry sections in changelog across releases by @jdx in [jdx#8047](jdx#8047) - ls --all-sources shows duplicate entries by @roele in [jdx#8042](jdx#8042) ### 📚 Documentation - replace "inherit" terminology with config layering by @jdx in [jdx#8046](jdx#8046) ### 📦 Registry - switch oxlint to npm backend by default by @risu729 in [jdx#8038](jdx#8038) - add orval (npm:orval) by @zdunecki in [jdx#8051](jdx#8051) ### New Contributors - @zdunecki made their first contribution in [jdx#8051](jdx#8051)
Summary
mise install tool@versionwith an explicit version, tool-level config options (e.g.postinstall) frommise.tomlwere being lost. The CLI args merge inload_runtime_args()replaced config entries entirely, andinit_request_options()overwrote options with empty backend arg opts. Fixed by merging config options into CLI requests and preferring config request options ininit_request_options().ansible = { version = "latest" }, install-time registry defaults (e.g.uvx=false,pipx_args=--include-deps) were stripped. The install-time key filtering correctly removes stale install-state cache, but also removed registry defaults. Fixed by re-applying registry defaults after filtering for any keys not explicitly set by the user.Test plan
test_install_postinstall_cli_versionverifies postinstall fires with bothmise install dummy@latestandmise install dummytest_table_syntax_preserves_registry_defaultsverifies registry defaults (uvx, pipx_args) are preserved with table syntax and that user overrides take precedence🤖 Generated with Claude Code
Note
Medium Risk
Changes tool option resolution/merging during installs and config parsing, which can subtly affect install behavior across many backends. Coverage is improved via new e2e/unit tests, but option precedence changes may have edge cases.
Overview
Ensures tool installs invoked with an explicit CLI version (e.g.
mise install dummy@latest) still inherit tool options defined inmise.toml(notablypostinstall) by merging config options into argument-sourcedToolRequests and preferring config request options during install request initialization.Fixes a regression in
mise.tomltable syntax tool definitions where filtering install-time keys also removed registry defaults; registry default options are now re-applied for keys the user didn’t override. Adds an e2e regression test forpostinstallbehavior and a unit test verifying registry defaults are preserved and user overrides win.Written by Cursor Bugbot for commit 039ab54. This will update automatically on new commits. Configure here.