Skip to content

fix(backend): respect install_before in latest lookup#9193

Merged
jdx merged 2 commits intojdx:mainfrom
risu729:fix/latest-install-before
Apr 18, 2026
Merged

fix(backend): respect install_before in latest lookup#9193
jdx merged 2 commits intojdx:mainfrom
risu729:fix/latest-install-before

Conversation

@risu729
Copy link
Copy Markdown
Contributor

@risu729 risu729 commented Apr 17, 2026

Summary

  • Centralize backend latest-version cutoff resolution so latest_stable_version is only used when no effective install_before / --before cutoff is active.
  • Rename the backend latest lookup API to the single latest_version(config, query, before_date) path and update callers.
  • Remove the npm-specific install_before workaround from NPMBackend::latest_stable_version and extend the npm regression test for per-tool install_before.

Why

This fixes a pre-existing bug in backend-direct latest lookups. Install/upgrade flows already go through ToolRequest::resolve, which computes the effective cutoff from --before, per-tool install_before, and global install_before. Direct latest lookups such as mise latest npm:prettier and the edit provider call the backend latest API directly, so they bypassed that resolution path.

For npm, that meant latest_stable_version could return the registry latest dist-tag even when an install_before cutoff should have selected an older version. The previous npm-specific workaround handled this only inside NPMBackend; this moves the cutoff check to the shared backend latest lookup path.

Tests

  • mise run format (includes cargo check --all-features)
  • cargo test --all-features test_effective_before_date
  • mise run test:e2e e2e/backend/test_npm_install_before built successfully, then aborted before assertions because local npm was not found in PATH.

Caveats

  • Date filtering still depends on backend VersionInfo::created_at metadata. Existing behavior keeps versions without timestamps in the candidate set.
  • latest_stable_version remains available as the backend-specific fast path, but callers should go through latest_version(..., before_date) so the effective cutoff can be applied first.

This PR was generated with assistance from an AI coding assistant.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 17, 2026

Greptile Summary

This PR fixes a pre-existing bug where mise latest, mise edit, and mise outdated/upgrade (without --before) bypassed install_before cutoffs because they called the backend latest API directly, skipping the effective-date resolution that the install path performs. The fix centralizes cutoff resolution in a new effective_latest_before_date helper called from the renamed latest_version(config, query, before_date) entry point, and removes the npm-specific workaround that partially addressed the same issue.

Confidence Score: 5/5

Safe to merge — clean API consolidation with correct cutoff resolution and no regressions identified.

All call sites are updated consistently. The effective_latest_before_date guard prevents double-application from callers that already carry a fully-resolved date. The npm-specific workaround removal is sound because latest_stable_version is now only reached from latest_version when no cutoff is active. No P0 or P1 findings were identified.

No files require special attention.

Important Files Changed

Filename Overview
src/backend/mod.rs Core change: renames latest_version_with_optslatest_version (3-param), adds effective_latest_before_date free function to centralize cutoff resolution, and keeps latest_version_for_query as the internal implementation layer. The guard if before_date.is_some() { return Ok(before_date); } prevents double-application from callers that already carry a fully-resolved date.
src/backend/npm.rs Removes the npm-specific install_before workaround from latest_stable_version. Safe because effective_latest_before_date now handles the cutoff before latest_stable_version is ever reached. Fallback inside the cache initializer correctly updated to latest_version_for_query(..., None).
src/backend/spm.rs Upgrades SPM install path from latest_stable_version (no cutoff awareness) to latest_version(..., ctx.before_date) so install_before is respected during SPM tool installation.
src/toolset/outdated_info.rs Renames latest_version_with_optslatest_version in the bump path. When opts.before_date is None, effective_latest_before_date will now correctly apply per-tool and global install_before.
e2e/backend/test_npm_install_before Extends the existing npm install_before test with a per-tool install_before case: creates a mise.toml with install_before = "2023-06-01" for npm:prettier and asserts mise latest npm:prettier returns 2.8.8.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["CLI: mise latest / mise edit"] --> B["backend.latest_version(config, query, None)"]
    C["toolset install path\nbefore_date already computed"] --> B
    D["outdated / upgrade"] --> B

    B --> E["effective_latest_before_date()"]
    E --> F{"before_date\nalready set?"}
    F -- Yes --> G["return as-is"]
    F -- No --> H{"ba opts\ninstall_before?"}
    H -- Yes --> I["parse and return"]
    H -- No --> J{"config tool opts\ninstall_before?"}
    J -- Yes --> K["parse and return"]
    J -- No --> L{"Settings\ninstall_before?"}
    L -- Yes --> M["parse and return"]
    L -- No --> N["None — no cutoff"]

    G --> O{"query provided?"}
    I --> O
    K --> O
    M --> O
    N --> O

    O -- "Some + cutoff active" --> P["latest_version_for_query\nwith date filter"]
    O -- "None + cutoff active" --> P
    O -- "None, no cutoff" --> Q["latest_stable_version\nbackend fast path"]
Loading

Reviews (6): Last reviewed commit: "Merge branch 'main' into fix/latest-inst..." | Re-trigger Greptile

Comment thread src/backend/mod.rs Outdated
Comment thread src/backend/npm.rs Outdated
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 refactors the version resolution logic to consistently handle the install_before cutoff across different backends. It introduces effective_latest_before_date to centralize the resolution of the cutoff date from tool options, configuration, and global settings, and merges latest_version_with_opts into a unified latest_version method. Feedback was provided regarding the potential for redundant asynchronous configuration lookups and multiple re-resolutions of the cutoff date within the effective_latest_before_date method, suggesting that these values could be cached or resolved at a higher level to improve performance.

Comment thread src/backend/mod.rs Outdated
@risu729 risu729 marked this pull request as draft April 17, 2026 12:12
@risu729 risu729 force-pushed the fix/latest-install-before branch 3 times, most recently from 082e720 to 78d894f Compare April 17, 2026 19:13
@risu729 risu729 force-pushed the fix/latest-install-before branch from 78d894f to 02cac76 Compare April 17, 2026 19:22
@risu729 risu729 marked this pull request as ready for review April 17, 2026 19:28
@jdx jdx merged commit 51a8133 into jdx:main Apr 18, 2026
32 of 33 checks passed
@risu729 risu729 deleted the fix/latest-install-before branch April 18, 2026 01:32
jdx pushed a commit that referenced this pull request Apr 18, 2026
## Summary

- Treat an explicit `latest` query the same as no query in the shared
backend latest resolver.
- Route both forms directly through `latest_stable_version` when no
effective `install_before` / `--before` cutoff is active.
- Preserve the date-filtered version-listing path when a cutoff is
active, so the behavior from #9193 remains intact.
- Add unit and e2e coverage that verifies `tool@latest` uses the
stable-latest path and does not regress date-filtered latest resolution.

## Regression Risk

No expected regressions.

The intentional behavior change is that `tool@latest` now follows the
same backend-specific stable-latest fast path as `tool`. If a backend's
generic version list disagreed with its stable-latest endpoint/script,
explicit `@latest` will now return the same value as the unqualified
tool lookup. Date-filtered lookups still bypass that fast path, so
`install_before` / `--before` behavior continues to use version
metadata.

## Tests

- `cargo fmt --all -- --check`
- `shellcheck e2e/cli/test_latest_explicit_latest`
- `shfmt -d -s e2e/cli/test_latest_explicit_latest`
- `cargo test --all-features latest_version_tests`
- `mise run test:e2e e2e/cli/test_latest_explicit_latest`

*This PR was generated with assistance from an AI coding assistant.*
jdx pushed a commit that referenced this pull request Apr 18, 2026
### 🐛 Bug Fixes

- **(backend)** respect install_before in latest lookup by @risu729 in
[#9193](#9193)
- **(backend)** route explicit latest through stable lookup by @risu729
in [#9228](#9228)
- **(backends)** deprecate b shorthand by @risu729 in
[#9234](#9234)
- **(config)** warn for deprecated env keys by @risu729 in
[#9205](#9205)
- **(config)** treat enable_tools empty as disable-all by @risu729 in
[#9108](#9108)
- **(github)** avoid auth on release asset downloads by @risu729 in
[#9060](#9060)
- **(gitlab)** warn when glab OAuth2 token is expired by @stanhu in
[#9195](#9195)
- **(npm)** honor install_before without day drift by @risu729 in
[#9157](#9157)
- **(npm)** warn on old bun and pnpm for install_before by @risu729 in
[#9232](#9232)
- **(pipx)** honor install_before for uv and pipx installs by @risu729
in [#9190](#9190)
- **(registry)** allow shfmt on Windows by @zeitlinger in
[#9191](#9191)

### 🚜 Refactor

- **(backend)** remove unused rolling release helper by @risu729 in
[#9175](#9175)
- **(backend)** use file util for removals by @risu729 in
[#9206](#9206)

### 📚 Documentation

- **(config)** clarify always_keep_download behavior by @risu729 in
[#9235](#9235)
- **(configuration)** add rust to idiomatic version files by @jjt in
[#9233](#9233)
- **(contributing)** expand contribution guide introduction by
@marianwolf in [#9208](#9208)
- **(github)** document multiple release assets workaround by @risu729
in [#9236](#9236)

### 📦️ Dependency Updates

- update actions/setup-node action to v6 by @renovate[bot] in
[#9183](#9183)
- update dependency @types/node to v25 by @renovate[bot] in
[#9187](#9187)
- update crazy-max/ghaction-import-gpg action to v7 by @renovate[bot] in
[#9186](#9186)
- update actions/cache action to v5 by @renovate[bot] in
[#9181](#9181)
- update amannn/action-semantic-pull-request action to v6 by
@renovate[bot] in [#9184](#9184)
- update apple-actions/import-codesign-certs action to v6 by
@renovate[bot] in [#9185](#9185)
- update dependency eslint to v10 by @renovate[bot] in
[#9200](#9200)
- update dependency toml to v4 by @renovate[bot] in
[#9201](#9201)
- update rust crate reqwest to 0.13 by @renovate[bot] in
[#9171](#9171)
- update ghcr.io/jdx/mise:deb docker digest to 523d826 by @renovate[bot]
in [#9198](#9198)
- update ghcr.io/jdx/mise:alpine docker digest to 05617e0 by
@renovate[bot] in [#9196](#9196)
- update ghcr.io/jdx/mise:rpm docker digest to c1992f9 by @renovate[bot]
in [#9199](#9199)
- update ghcr.io/jdx/mise:copr docker digest to 90db6cd by
@renovate[bot] in [#9197](#9197)
- update taiki-e/install-action digest to 58e8625 by @renovate[bot] in
[#9209](#9209)
- update fedora docker tag to v45 by @renovate[bot] in
[#9213](#9213)
- update docker/setup-buildx-action action to v4 by @renovate[bot] in
[#9212](#9212)
- update docker/metadata-action action to v6 by @renovate[bot] in
[#9211](#9211)
- update docker/login-action action to v4 by @renovate[bot] in
[#9210](#9210)
- update dependency typescript to v6 by @renovate[bot] in
[#9202](#9202)
- update docker/build-push-action action to v7 by @renovate[bot] in
[#9203](#9203)
- update github artifact actions (major) by @renovate[bot] in
[#9215](#9215)
- update rust crate duct to v1 by @renovate[bot] in
[#9220](#9220)
- update rust crate demand to v2 by @renovate[bot] in
[#9219](#9219)
- update rust crate clx to v2 by @renovate[bot] in
[#9218](#9218)
- update nick-fields/retry action to v4 by @renovate[bot] in
[#9217](#9217)
- update jdx/mise-action action to v4 by @renovate[bot] in
[#9216](#9216)
- update rust crate self_update to 0.44 by @renovate[bot] in
[#9174](#9174)
- migrate eslint config to flat format for v10 compat by @jdx in
[#9222](#9222)
- update actions/checkout action to v6 by @renovate[bot] in
[#9182](#9182)
- update rust crate toml to v1 by @renovate[bot] in
[#9225](#9225)
- update rust crate versions to v7 by @renovate[bot] in
[#9226](#9226)
- update rust crate which to v8 by @renovate[bot] in
[#9227](#9227)
- update rust crate rmcp to v1 by @renovate[bot] in
[#9221](#9221)

### 📦 Registry

- add sheldon by @3w36zj6 in
[#9104](#9104)
- add pocketbase by @ranfdev in
[#9123](#9123)
- add worktrunk ([aqua:max-sixty/worktrunk,
cargo:worktrunk](https://github.com/max-sixty/worktrunk,
cargo:worktrunk))#1 by @edouardr in
[#8796](#8796)
- add dependency-check
([aqua:dependency-check/DependencyCheck](https://github.com/dependency-check/DependencyCheck))
by @kapitoshka438 in [#9204](#9204)
- add janet by @ranfdev in
[#9241](#9241)

### New Contributors

- @ranfdev made their first contribution in
[#9241](#9241)
- @jjt made their first contribution in
[#9233](#9233)
- @marianwolf made their first contribution in
[#9208](#9208)
- @edouardr made their first contribution in
[#8796](#8796)

## 📦 Aqua Registry Updates

#### New Packages (3)

- [`LargeModGames/spotatui`](https://github.com/LargeModGames/spotatui)
-
[`android-sms-gateway/cli`](https://github.com/android-sms-gateway/cli)
- [`velero-io/velero`](https://github.com/velero-io/velero)

#### Updated Packages (1)

- [`skim-rs/skim`](https://github.com/skim-rs/skim)
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