Skip to content

fix(backend): apply inline tool option overrides#9306

Merged
jdx merged 11 commits intojdx:mainfrom
risu729:codex/backend-inline-opts
May 5, 2026
Merged

fix(backend): apply inline tool option overrides#9306
jdx merged 11 commits intojdx:mainfrom
risu729:codex/backend-inline-opts

Conversation

@risu729
Copy link
Copy Markdown
Contributor

@risu729 risu729 commented Apr 22, 2026

What

  • Add a shared backend option resolver that preserves where each effective option came from.
  • Resolve backend options in this order, with later layers overriding earlier ones:
    1. Registry backend defaults.
    2. Backend alias [...] options from [tool_alias] / [alias] backend entries.
    3. Config options selected by the existing tool config lookup rules.
    4. Inline backend options from the current tool spec, such as tool[...].
  • Apply that resolved option path consistently in GitHub/GitLab/Forgejo, HTTP, S3, UBI, vfox backend plugins, Conda channel resolution, SPM provider/API URL resolution, Java release type listing, versions-host cache filtering, fuzzy version matching, minimum_release_age handling, runtime args, and install request initialization.
  • Preserve inline backend options across the short-name backend cache, so commands like ls-remote 'github:owner/repo[api_url=...]' do not accidentally use a cached installed backend without those inline options.
  • Preserve config options when runtime args include inline overrides, while still letting inline options win for the one command.
  • Switch Go install to use the resolved request options.
  • Fix shorthand parsing for URL-valued inline options such as tool[api_url=https://example/api/v3].

Follow-up

The versions-host behavior for locally overridden backend options has been split into #9568. That PR is stacked on this one and should be rebased after this merges.

Relationship to #9315

This PR does not change which config entry is eligible for a tool. That behavior comes from #9315:

  • Registry short names should not inherit config from their resolved full backend key.
  • Configured aliases can fall back to resolved full-backend config when there is no alias-specific entry.
  • Alias-specific [tools.<alias>] config is more specific than [tools."<resolved-backend>"] config.

This PR builds on that lookup and changes what happens after config has been selected: registry defaults, backend alias options, config options, and inline options are merged through one resolver, with provenance retained for callers that need to distinguish where an option came from.

Relationship to #8902

#8902 was a narrower ls-remote fix for inline backend options. This PR covers the same installed-tool cache failure mode generically: when a caller supplies inline backend options, mise builds a backend from that caller BackendArg instead of returning a short-name cache entry that was loaded from install state without the inline options.

Example

Given config selected through an alias fallback:

[tool_alias]
hw = "github:jdx/mise-test-fixtures[api_url=https://api.github.com]"

[tools."github:jdx/mise-test-fixtures"]
version = "1.0.0"
asset_pattern = "definitely-not-a-real-hello-world-asset"

Inline options should still win for this invocation:

mise install 'hw[asset_pattern=hello-world-1.0.0.tar.gz,bin_path=hello-world-1.0.0/bin]@1.0.0'

Before this PR, the resolved full-backend config could replace the inline asset_pattern, and alias [...] options were only visible as part of a resolved string. After this PR, alias options are their own layer and inline options are applied over the selected config options.

Why

Backend-level code had several config-or-inline branches. Depending on the path:

  • Inline options could be ignored when config existed for the same tool or resolved backend.
  • Inline options could be dropped at the installed-tool backend cache boundary.
  • Config options could be dropped when runtime args included inline options.
  • Backend alias [...] options were not represented as a distinct layer.
  • Backend-specific list/install paths could read raw backend args instead of the resolved tool options.
  • Registry defaults were not always part of the same overlay path as config and inline options.

This PR centralizes that overlay so config-aware paths use the same precedence, while preserving source information separately from the effective option values.

Validation

  • cargo fmt --all
  • git diff --check
  • cargo test --all-features tool_opts
  • cargo test --all-features opts_with_config
  • cargo test --all-features test_git_provider_from_ba
  • mise run test:e2e e2e/backend/test_github_ls_remote_inline_opts

This PR was updated by an AI coding assistant.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 22, 2026

Greptile Summary

This PR centralizes backend option resolution into a shared resolve_tool_opts_with_overrides / get_tool_opts_with_overrides path, applying a four-layer overlay (registry → alias → config → inline) with provenance tracking via ResolvedToolOptions. It also fixes shorthand parsing for URL-valued inline options (e.g. tool[api_url=https://…]) by extracting bracket opts before the first : split, and bypasses the installed-tool backend cache when inline opts are present to prevent those opts from being silently dropped.

  • New option resolver: ResolvedToolOptions + ToolOptionSource track where each effective option came from; all backend list/install paths are updated to call get_tool_opts_with_overrides instead of the old get_tool_opts(…).unwrap_or_else(|| ba.opts()) fallback.
  • Cache bypass: backend::get() now short-circuits to arg_to_backend when ba.explicit_opts().is_some(), ensuring inline opts are never silently replaced by a cached backend that lacks them.
  • Bug fixes: ToolVersionOptions::is_empty() now includes the os field; parse_backend_components strips brackets before the : split, correcting parsing of URLs inside bracket options.

Confidence Score: 5/5

The changes are safe to merge. The new four-layer overlay is applied consistently across all backend list/install paths, the cache bypass correctly prevents inline opts from being dropped, and the URL-in-bracket parsing fix is logically sound.

The PR centralises a previously fragmented option-resolution pattern into a single well-tested path. The logic of applying registry → alias → config → inline is correct, the cache bypass is narrowly scoped to BackendArgs with explicit opts, and the is_empty / bracket-parsing bug fixes are clearly correct. No wrong-data paths or dropped-state issues were identified.

No files require special attention. The test isolation concern in src/config/mod.rs around the env-var test is minor and would only matter if assertions inside that test begin to panic rather than return errors.

Reviews (18): Last reviewed commit: "Merge branch 'main' into codex/backend-i..." | Re-trigger Greptile

Comment thread src/config/mod.rs
Comment thread src/config/mod.rs
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

This pull request centralizes tool option retrieval and override logic by introducing the get_tool_opts_with_overrides method and updating various backends to utilize it. It also refactors backend argument parsing to handle inline options more robustly and adds merging capabilities to ToolVersionOptions. The review feedback identifies duplicated logic in src/toolset/builder.rs and a bug where configuration options are not applied when the default_to_latest flag is active.

Comment thread src/toolset/builder.rs Outdated
@risu729
Copy link
Copy Markdown
Contributor Author

risu729 commented Apr 24, 2026

Waiting for: #9315

@risu729
Copy link
Copy Markdown
Contributor Author

risu729 commented Apr 28, 2026

Might be related to #8902. Will check

@risu729 risu729 force-pushed the codex/backend-inline-opts branch 5 times, most recently from 2b9fd08 to bffd094 Compare May 3, 2026 14:22
@risu729 risu729 force-pushed the codex/backend-inline-opts branch from bffd094 to e3cdcca Compare May 3, 2026 15:15

This comment was marked as outdated.

@risu729
Copy link
Copy Markdown
Contributor Author

risu729 commented May 5, 2026

CI status update for head 9d8a380:

All checks have completed. The build, lint, benchmark, unit jobs, Windows e2e, registry checks, Greptile Review, and the passing Linux e2e shards are green. The release packaging jobs shown as skipped are expected for this PR run.

The remaining failures are e2e-1, e2e-4, e2e-5, and the aggregate test-ci; I am not changing code for them because the logs point to unrelated failures:

  • shell/test_xonsh, cli/test_activate_multiple_xonsh, sync/test_sync_python_uv, and cli/test_deactivate_xonsh all fail while installing aqua:astral-sh/uv@latest (uv@0.11.9) with GitHub artifact attestation verification: expected astral-sh/uv/.github/workflows/release.yml, but the attestation certificate/provenance are None. Other aqua/GitHub verification tests in the same run passed, so this looks specific to the current upstream uv artifact/attestation metadata rather than this PR's backend option layering changes.
  • cli/test_tool_depends failed because its first assertion expects mise install without depends to fail. That test has no dependency edge between dummy and needs-dummy, so both can be scheduled concurrently; in this run dummy completed before needs-dummy, making the install succeed. The test and needs-dummy fixture are unchanged from upstream/main, so this is a pre-existing flaky assertion, not a regression introduced here.

Greptile Review passed on 9d8a380, and the review threads are all resolved.

This comment was generated by an AI coding assistant.

@risu729 risu729 marked this pull request as ready for review May 5, 2026 09:38
@jdx jdx merged commit 2688763 into jdx:main May 5, 2026
34 checks passed
@risu729 risu729 deleted the codex/backend-inline-opts branch May 5, 2026 20:24
jdx pushed a commit that referenced this pull request May 7, 2026
This ignores settings, we still need to handle them later.

## What

- Keep the option-source-based versions-host behavior split out from
#9306.
- Skip `mise-versions` when a backend declares that a locally overridden
tool option affects its remote version listing. Registry defaults still
use the hosted list.
- Keep locally safe options on the existing path: `minimum_release_age`
/ `install_before` still use the existing before-date helper, and
options that only affect install/download selection are not treated as
version-listing inputs.

## Why These Tool Options Affect Remote Version Listing

These options change the upstream queried for versions, the way version
candidates are extracted, or the release class included in the list:

- `github`: `api_url` changes the GitHub-compatible API host queried for
releases/tags; `version_prefix` changes which tags are considered
versions.
- `ubi`: `provider` changes the release provider implementation,
`api_url` changes the API host, and `tag_regex` changes which tags are
extracted as versions.
- `spm`: `provider` changes the git hosting provider used for tags, and
`api_url` changes the provider API host.
- `http`: `version_list_url` changes the source document for versions,
`version_regex` changes extraction from that document,
`version_json_path` changes the JSON field read for versions, and
`version_expr` changes the expression used to derive versions.
- `s3`: `version_list_url` changes the manifest/listing source,
`version_regex` changes extraction, `version_json_path` and
`version_expr` change manifest parsing, `version_prefix` changes S3
object-list filtering, `url` can change the S3 bucket/key used for
listing-based discovery, and `region` / `endpoint` change which
S3-compatible service is queried.
- `vfox`: backend plugins can define arbitrary option semantics and pass
them into plugin version-listing logic, so custom vfox backend plugins
use the all-options sentinel. Regular vfox plugins keep the default
hosted-list behavior.
- `java`: `release_type` switches between GA and EA metadata caches, so
it changes which Java releases appear.
- `conda`: `channel` changes the Anaconda channel queried for package
versions.

`dotnet` is intentionally deferred: `prerelease` currently changes the
NuGet query, but there are no dotnet backend tools in the registry using
the versions host. The code now carries a TODO to revisit this when
dotnet can list the prerelease superset and filter at read time like
github/aqua.

## Validation

- `cargo fmt --check`
- `git diff --check`
- `cargo test backend::tests::test_remote_version_listing_opts`
- `mise run test:e2e e2e/backend/test_github_alias_versions
e2e/backend/test_github_ls_remote_inline_opts`

*This PR was updated by an AI coding assistant.*
mise-en-dev added a commit that referenced this pull request May 7, 2026
### 🚀 Features

- **(aqua)** support registry libc variants by @jdx in
[#9652](#9652)
- **(bin-paths)** add executable names output by @risu729 in
[#9617](#9617)

### 🐛 Bug Fixes

- **(aqua)** preserve configured file extensions by @risu729 in
[#9611](#9611)
- **(aqua)** support registry file links by @risu729 in
[#9610](#9610)
- **(backend)** reject bare package backend names by @risu729 in
[#9608](#9608)
- **(backend)** apply inline tool option overrides by @risu729 in
[#9306](#9306)
- **(backend)** skip versions host for local tool opts by @risu729 in
[#9568](#9568)
- **(github)** chmod explicit archive bin by @risu729 in
[#9609](#9609)
- **(install)** skip remote-versions refresh in prefer-offline mode by
@jdx in [#9627](#9627)
- **(lock)** scope targets to active project root by @risu729 in
[#9319](#9319)
- **(lockfile)** respect existing platforms during auto-lock by @jdx in
[#9621](#9621)
- **(pipx)** filter yanked pypi releases by @risu729 in
[#9607](#9607)
- **(pipx)** declare python as a backend dependency by @jdx in
[#9678](#9678)
- **(schema)** update refs to $defs in mise-registry-tool.json by
@risu729 in [#9671](#9671)
- **(task)** terminate parallel siblings on failure via process groups
by @jdx in [#9655](#9655)
- **(task)** stable MISE_PROJECT_ROOT for monorepo tasks, add
MISE_MONOREPO_ROOT by @jdx in
[#9657](#9657)
- **(trust)** run enter hooks after trusting config by @risu729 in
[#9634](#9634)
- **(ui)** stop clearing screen for prompts by @jdx in
[#9619](#9619)
- use /bin/cp on macos by @pdehlke in
[#9656](#9656)

### 🚜 Refactor

- **(aqua)** store aqua var defaults as strings by @risu729 in
[#9645](#9645)
- **(config)** support structured TOML values in registry backend
options by @risu729 in [#9584](#9584)
- **(deps)** remove serde_derive dependency by @risu729 in
[#9670](#9670)
- **(deps)** remove anyhow dependency by @risu729 in
[#9661](#9661)
- **(deps)** use std::sync::LazyLock instead of once_cell::Lazy by
@risu729 in [#9668](#9668)
- **(schema)** generate task schema from mise schema by @risu729 in
[#9581](#9581)
- **(schema)** reuse task props with unevaluatedProperties by @risu729
in [#9582](#9582)
- **(schema)** reuse registry common types by @risu729 in
[#9648](#9648)
- **(schema)** reuse plugin script config by @risu729 in
[#9647](#9647)
- **(schema)** use $defs in schema files by @risu729 in
[#9646](#9646)

### 📚 Documentation

- **(node)** add tips for enabling node idiomatic by @fu050409 in
[#9675](#9675)

### 🧪 Testing

- **(cli)** remove nondeterministic tool depends assertion by @risu729
in [#9633](#9633)
- **(e2e)** pin uv to 0.11.8 around astral-sh/uv#19278 by @jdx in
[#9618](#9618)
- **(e2e)** wait for docker env cleanup by @risu729 in
[#9631](#9631)
- **(zig)** use official zig instead of mach mirror by @jdx in
[#9659](#9659)

### 📦️ Dependency Updates

- fall through to hash check when providers have no outputs by @jdx in
[#9622](#9622)
- bump Cargo.lock by @jdx in
[#9625](#9625)

### 📦 Registry

- remove registry depends by @risu729 in
[#9571](#9571)
- add code-review-graph (pipx:code-review-graph) by @chautruonglong in
[#9673](#9673)

### Chore

- **(ci)** split large registry test-tool changes by @risu729 in
[#9628](#9628)
- **(ci)** make perf script robust to runner noise by @jdx in
[#9635](#9635)
- **(ci)** skip hyperfine comments without permission by @risu729 in
[#9629](#9629)

### New Contributors

- @chautruonglong made their first contribution in
[#9673](#9673)
- @pdehlke made their first contribution in
[#9656](#9656)

## 📦 Aqua Registry Updates

### New Packages (5)

-
[`anthropics/anthropic-cli`](https://github.com/anthropics/anthropic-cli)
- [`crates.io/wasmi_cli`](https://github.com/wasmi-labs/wasmi)
- [`openclaw/gogcli`](https://github.com/openclaw/gogcli)
- `racket-lang.org/racket-minimal`
- [`runs-on/cli`](https://github.com/runs-on/cli)

### Updated Packages (13)

- [`UpCloudLtd/upcloud-cli`](https://github.com/UpCloudLtd/upcloud-cli)
- [`aristocratos/btop`](https://github.com/aristocratos/btop)
- [`dprint/dprint`](https://github.com/dprint/dprint)
- [`j178/prek`](https://github.com/j178/prek)
- [`jdx/hk`](https://github.com/jdx/hk)
- [`jdx/mise`](https://github.com/jdx/mise)
- [`jdx/usage`](https://github.com/jdx/usage)
- [`jreleaser/jreleaser`](https://github.com/jreleaser/jreleaser)
-
[`jreleaser/jreleaser/standalone`](https://github.com/jreleaser/jreleaser)
- [`pnpm/pnpm`](https://github.com/pnpm/pnpm)
- [`suzuki-shunsuke/cmdx`](https://github.com/suzuki-shunsuke/cmdx)
- [`suzuki-shunsuke/ghir`](https://github.com/suzuki-shunsuke/ghir)
- [`twpayne/chezmoi`](https://github.com/twpayne/chezmoi)
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