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 ([email protected]) 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.*
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