Skip to content

fix(backend): scope PEP 440 prerelease detection to Python backends#9558

Merged
jdx merged 1 commit intomainfrom
fix/version-regex-go-pseudo-versions
May 3, 2026
Merged

fix(backend): scope PEP 440 prerelease detection to Python backends#9558
jdx merged 1 commit intomainfrom
fix/version-regex-go-pseudo-versions

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented May 3, 2026

Summary

Two regressions visible in the release PR (#9485):

  • mise install go:.../@latest returns "no versions found" when the latest is a Go pseudo-version (e.g. go:github.com/go-kratos/kratos/cmd/kratos/v2) — the e2e-0 / backend/test_go_install_slow failure.
  • (After narrowing the rule too aggressively in earlier revs of this PR: mise latest python returned 3.15.0a8 instead of a stable. Fixed below.)

Cause

The ([abc])[0-9]+ alternative in the shared VERSION_REGEX was unanchored, so it false-positived on any a/b/c followed by a digit anywhere in a string — including the random hex hash inside Go pseudo-versions (e.g. c1 inside f149714c1d54).

#9500 enabled mark_prereleases_from_version_pattern: true for the go backend on May 1, which is what made it user-visible — the regex was already over-permissive but no Go-flavored input had been feeding it before.

Fix

The rule is PEP 440-specific (Python's separator-less alpha/beta/rc shorthand). Move it out of the general regex into PEP440_PRERELEASE_REGEX and consult it only from Python-flavored backends.

  • VERSION_REGEX (in src/plugins/mod.rs): drop the ([abc])[0-9]+ alternative.
  • PEP440_PRERELEASE_REGEX (new): (?i)[0-9](?:a|b|c|rc)[0-9]+(?:\$|[^a-z0-9]) — grounded in PEP 440's canonical grammar [N!]N(.N)*[{a|b|rc}N][.postN][.devN]. The leading digit anchors the prerelease segment to follow the release segment (so it can't trigger inside arbitrary identifiers); c is included as PEP 440's recognized alternate spelling for rc; the trailing boundary stops it from matching inside hex hashes even when those start with a digit.
  • pipx:
    • Stamps PEP 440 prereleases on VersionInfo in _list_remote_versions so the cache reflects it.
    • Overrides fuzzy_match_filter to drop them from match results.
  • python core plugin: same fuzzy_match_filter override (python-build returns 3.15.0a8-style alphas).
  • Both share a new fuzzy_match_versions_pep440 helper in src/backend/mod.rs so the override is one line each.

Test plan

  • cargo test test_pep440_prerelease_regex (new) — Python suffixes match, Go pseudo-versions and bare-b identifiers don't, .post doesn't.
  • cargo test test_version_regex_filters_prerelease — confirms PEP 440 cases now negative on the general regex.
  • cargo test test_mark_prerelease_flags_regex_matches — added a Go pseudo-version case and a PEP 440 case (both should not be flagged by the general path).
  • cargo test test_fuzzy_match_versions_*, test_filter_cached_prereleases_*, pipx::tests::*.
  • Local repro: mise ls-remote 'go:github.com/go-kratos/kratos/cmd/kratos/v2' returns 2.0.0-20260404020628-f149714c1d54.
  • Local repro: mise latest python returns 3.14.4 (was 3.15.0a8 after the earlier rev of this PR).
  • Wait on CI for e2e-0 / test_go_install_slow and e2e-6 / test_latest.

🤖 Generated with Claude Code


Note

Medium Risk
Adjusts prerelease detection and fuzzy version resolution logic, which can change what versions are considered installable/latest across multiple backends; mistakes could hide valid versions or surface prereleases unexpectedly.

Overview
Fixes prerelease filtering regressions by removing the unanchored ([abc])[0-9]+ clause from the shared VERSION_REGEX (which was incorrectly flagging strings like Go pseudo-versions) and introducing a new Python-scoped PEP440_PRERELEASE_REGEX.

Python-flavored backends (pipx and the core python plugin) now apply PEP 440 prerelease handling explicitly: pipx stamps PEP 440 alphas/betas/rcs onto cached VersionInfo.prerelease, and both backends override fuzzy matching via a new shared helper fuzzy_match_versions_pep440 so latest/prefix queries skip 3.15.0a8-style versions unless explicitly requested.

Adds focused tests to ensure Go pseudo-versions are not filtered by the general regex and that PEP 440 prerelease detection works only where intended.

Reviewed by Cursor Bugbot for commit 287f01d. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 3, 2026

Greptile Summary

This PR fixes two regressions by scoping PEP 440 separator-less prerelease detection (aN/bN/cN/rcN) out of the shared VERSION_REGEX and into a new PEP440_PRERELEASE_REGEX that is only consulted by Python-flavored backends (pipx, python). The root cause was an unanchored ([abc])[0-9]+ alternative in VERSION_REGEX that false-positived on hex substrings in Go pseudo-version hashes (e.g. c1 in f149714c1d54), causing mise install go:.../@latest to return "no versions found".

Confidence Score: 5/5

Safe to merge — the fix is tightly scoped, regression-tested, and does not change behaviour for any non-Python backend.

No P0/P1 issues found. The regex change is correct and well-anchored, the two-layer filtering (VersionInfo stamp + fuzzy_match_filter override) is complementary rather than duplicative, the exact-match bypass is preserved, and the test suite covers Python prereleases, stable versions, Go pseudo-versions, and bare identifiers.

No files require special attention.

Important Files Changed

Filename Overview
src/plugins/mod.rs Removes ([abc])[0-9]+ from VERSION_REGEX and introduces the new PEP440_PRERELEASE_REGEX constant with correct leading-digit anchor and trailing boundary; new unit tests cover Python prereleases, stable releases, Go pseudo-versions, and bare identifiers.
src/backend/mod.rs Adds fuzzy_match_versions_pep440 helper that pre-filters PEP 440 prereleases before delegating to the shared fuzzy_match_versions; includes an exact-match bypass so explicit prerelease requests still resolve; well-tested.
src/backend/pipx.rs Refactors _list_remote_versions to stamp PEP 440 prerelease flags on cached VersionInfo entries and overrides fuzzy_match_filter to drop them from query resolution; clean structural simplification alongside the new behaviour.
src/plugins/core/python.rs Adds fuzzy_match_filter override to delegate to fuzzy_match_versions_pep440, ensuring python-build-style alphas (3.15.0a8) are excluded from latest resolution without touching any other logic.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Backend calls fuzzy_match_filter] --> B{Python-flavored backend?}
    B -- "Yes (pipx / python)" --> C[fuzzy_match_versions_pep440]
    B -- No --> D[fuzzy_match_versions]
    C --> E{filter_prereleases?}
    E -- Yes --> F["Pre-filter: drop PEP440_PRERELEASE_REGEX matches\n(except exact query match)"]
    E -- No --> G[Keep all versions]
    F --> D
    G --> D
    D --> H{filter_prereleases?}
    H -- Yes --> I["Drop VERSION_REGEX matches\n(-rc1, -dev, -alpha …)\nexact match preserved"]
    H -- No --> J[Keep all versions]
    I --> K[Pattern match against query]
    J --> K
    K --> L[Return matched versions]
Loading

Reviews (7): Last reviewed commit: "fix(backend): scope PEP 440 prerelease d..." | Re-trigger Greptile

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 updates the VERSION_REGEX in src/plugins/mod.rs to prevent false positives when matching version strings, specifically addressing issues where hex hashes in Go pseudo-versions were incorrectly identified as prerelease suffixes. It also adds comprehensive test cases to verify the new regex behavior against Python-style suffixes and Go pseudo-versions. I have no feedback to provide.

@jdx jdx force-pushed the fix/version-regex-go-pseudo-versions branch from cfff9d8 to a3ba126 Compare May 3, 2026 10:01
@jdx jdx changed the title fix(backend): don't flag Go pseudo-versions as prereleases fix(backend): scope PEP 440 prerelease detection to pipx only May 3, 2026
@jdx jdx force-pushed the fix/version-regex-go-pseudo-versions branch from a3ba126 to 2be0505 Compare May 3, 2026 10:06
@jdx jdx enabled auto-merge (squash) May 3, 2026 10:20
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 3, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 x -- echo 23.1 ± 0.8 21.6 30.5 1.00
mise x -- echo 24.0 ± 0.8 22.5 28.9 1.04 ± 0.05

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 env 22.9 ± 0.9 21.2 29.6 1.00
mise env 23.1 ± 0.6 21.8 25.6 1.01 ± 0.05

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 hook-env 23.0 ± 0.6 22.0 29.2 1.00
mise hook-env 24.3 ± 0.8 22.6 27.5 1.05 ± 0.05

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.28 ls 20.7 ± 0.7 19.4 25.1 1.00
mise ls 21.3 ± 0.7 19.8 25.3 1.03 ± 0.05

xtasks/test/perf

Command mise-2026.4.28 mise Variance
install (cached) 154ms 160ms -3%
ls (cached) 78ms 81ms -3%
bin-paths (cached) 83ms 85ms -2%
task-ls (cached) 856ms 811ms +5%

@jdx jdx force-pushed the fix/version-regex-go-pseudo-versions branch from 29cc81a to 0919ec8 Compare May 3, 2026 11:01
@jdx jdx changed the title fix(backend): scope PEP 440 prerelease detection to pipx only fix(backend): scope PEP 440 prerelease detection to Python backends May 3, 2026
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0919ec8. Configure here.

Comment thread src/backend/mod.rs
@jdx jdx disabled auto-merge May 3, 2026 11:13
The `([abc])[0-9]+` alternative in the shared `VERSION_REGEX` was
unanchored, so it false-positived on any `a`/`b`/`c` followed by a
digit anywhere in a version string — including the random hex hash
inside Go pseudo-versions (e.g. `c1` inside `f149714c1d54`).

After #9500 enabled `mark_prereleases_from_version_pattern: true` for
the `go` backend, this caused `mise install go:.../@latest` to filter
out the only available version for paths whose latest is a
pseudo-version, e.g. `go:github.com/go-kratos/kratos/cmd/kratos/v2`.

The rule itself is PEP 440-specific (Python's separator-less
alpha/beta/rc shorthand) and shouldn't have been in the general regex.
Move it into a new `PEP440_PRERELEASE_REGEX` consulted only by the
Python-flavored backends — `pipx` and the `python` core plugin. Other
backends would otherwise false-positive on hex hashes / short SHAs.

The new regex is grounded in the canonical PEP 440 grammar,
`[N!]N(.N)*[{a|b|rc}N][.postN][.devN]`: the prerelease segment must
follow the release segment, so the regex requires a leading digit.
`c` is included as PEP 440's recognized alternate spelling for `rc`.
A trailing `(?:$|[^a-z0-9])` boundary keeps it from matching inside
hex identifiers even when those start with a digit.

Both Python-flavored backends share the logic via a new
`fuzzy_match_versions_pep440` helper. `pipx` additionally stamps the
flag on its `VersionInfo` cache entries so `prerelease=true` reflects
upstream metadata as well as fuzzy-match filtering.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@jdx jdx force-pushed the fix/version-regex-go-pseudo-versions branch from 0919ec8 to 287f01d Compare May 3, 2026 11:14
@jdx jdx enabled auto-merge (squash) May 3, 2026 11:26
@jdx jdx merged commit 2e66f3e into main May 3, 2026
37 checks passed
@jdx jdx deleted the fix/version-regex-go-pseudo-versions branch May 3, 2026 11:29
mise-en-dev added a commit that referenced this pull request May 3, 2026
### 🚀 Features

- **(conda)** graduate conda backend out of experimental by @jdx in
[#9544](#9544)
- **(deps)** Add dart and flutter providers by @tjarvstrand in
[#9505](#9505)
- **(registry)** add neo4j by @mnm364 in
[#9525](#9525)
- **(registry)** add rustfs by @mnm364 in
[#9530](#9530)
- **(task)** support exclusion patterns in task sources by
@jlarmstrongiv in [#9496](#9496)
- **(vfox)** add stat function to lua file module by @esteve in
[#9497](#9497)

### 🐛 Bug Fixes

- **(backend)** flag regex prerelease versions by @jdx in
[#9500](#9500)
- **(backend)** mark -nightly/-canary/-experimental as prereleases by
@jdx in [#9523](#9523)
- **(backend)** suppress no-versions warning for unresolved-latest
backends by @jdx in [#9548](#9548)
- **(backend)** include dotnet prereleases from package flags by @jdx in
[#9551](#9551)
- **(backend)** scope PEP 440 prerelease detection to Python backends by
@jdx in [#9558](#9558)
- **(cargo)** Apply install_env during cargo install by @c22 in
[#9502](#9502)
- **(copr)** drop epel-9 chroots since rust >= 1.91 is unavailable by
@jdx in [#9484](#9484)
- **(github)** skip attestations on non-default api_url by @jdx in
[#9486](#9486)
- **(github)** retry ip allow list errors without auth by @risu729 in
[#9506](#9506)
- **(http)** update versions host tracking endpoint by @jdx in
[#9527](#9527)
- **(install)** don't warn for configured tools when version is passed
via CLI by @jdx in [#9522](#9522)
- **(install)** refresh latest before installing missing tools by @jdx
in [#9545](#9545)
- **(install)** don't cache nonexistent install paths by @jdx in
[#9553](#9553)
- **(lockfile)** don't propagate ad-hoc CLI overrides into the project
lockfile by @jdx in [#9562](#9562)
- **(plugin)** detect plugin types after cloning by @risu729 in
[#9540](#9540)
- **(release)** pass --no-git-checks to aube publish by @jdx in
[#9483](#9483)
- **(task)** convert PATH to MSYS Unix form when spawning POSIX shells
on Windows by @JamBalaya56562 in
[#9547](#9547)

### 📚 Documentation

- **(contributing)** require popularity check for registry PRs by @jdx
in
[7bbeebe](7bbeebe)
- **(watch)** update pitchfork domain to en.dev by @risu729 in
[#9536](#9536)
- document ghtkn GitHub token setup by @jdx in
[#9546](#9546)
- clarify registry backend acceptance policy by @jdx in
[#9543](#9543)
- Change exec command to use bash for variable echo by @kuboon in
[#9567](#9567)

### 🧪 Testing

- **(e2e)** run test-tool targets in parallel by @jdx in
[#9564](#9564)
- **(e2e)** run tests in parallel by @jdx in
[#9563](#9563)
- **(e2e)** bind-mount /tmp on disk and surface failed tests in CI
summary by @jdx in [#9570](#9570)
- **(tasks)** migrate test_task_help atask to usage field by @jdx in
[#9549](#9549)

### 📦️ Dependency Updates

- update fedora:45 docker digest to 8b838b3 by @renovate[bot] in
[#9507](#9507)
- update ghcr.io/jdx/mise:deb docker digest to f02194c by @renovate[bot]
in [#9509](#9509)
- update taiki-e/install-action digest to 7769b73 by @renovate[bot] in
[#9512](#9512)
- update ghcr.io/jdx/mise:alpine docker digest to 581f8a8 by
@renovate[bot] in [#9508](#9508)
- update rust crate ctor to v0.10.1 by @renovate[bot] in
[#9515](#9515)
- update ghcr.io/jdx/mise:rpm docker digest to a5c9655 by @renovate[bot]
in [#9510](#9510)
- update rust docker digest to a9cfb75 by @renovate[bot] in
[#9511](#9511)
- update rust crate age to v0.11.3 by @renovate[bot] in
[#9514](#9514)
- update rust crate jiff to v0.2.24 by @renovate[bot] in
[#9516](#9516)
- update dependency vitepress-plugin-tabs to ^0.9.0 by @renovate[bot] in
[#9518](#9518)
- update autofix-ci/action action to v1.3.4 by @renovate[bot] in
[#9513](#9513)
- update rust crate usage-lib to v3.2.1 by @renovate[bot] in
[#9517](#9517)
- update apple-actions/import-codesign-certs action to v7 by
@renovate[bot] in [#9519](#9519)
- update taiki-e/install-action digest to 51cd0b8 by @renovate[bot] in
[#9531](#9531)
- exclude taiki-e/install-action from renovate by @jdx in
[#9532](#9532)
- update rust crate blake3 to v1.8.5 by @renovate[bot] in
[#9533](#9533)

### 📦 Registry

- enable shellcheck on windows by @zeitlinger in
[#9487](#9487)
- add google-java-format by @zeitlinger in
[#9488](#9488)
- add expert
([aqua:expert-lsp/expert](https://github.com/expert-lsp/expert)) by
@AlternateRT in [#9498](#9498)
- update entry for checkmake by @eread in
[#9504](#9504)
- add systemctl-tui
([aqua:rgwood/systemctl-tui](https://github.com/rgwood/systemctl-tui))
by @2xdevv in [#9521](#9521)
- add codon by @3w36zj6 in
[#9538](#9538)
- add tool yr (backend:github:VirusTotal/yara-x) by @adam-moss in
[#9542](#9542)
- add tool betterleaks (backend:aqua/betterleaks/betterleaks) by
@adam-moss in [#9541](#9541)
- add `git-filter-repo` by @garysassano in
[#9550](#9550)
- add umoci
([aqua:opencontainers/umoci](https://github.com/opencontainers/umoci))
by @2xdevv in [#9555](#9555)
- add aqua backend for elixir-ls by @AlternateRT in
[#9557](#9557)
- deny inline backend options by @risu729 in
[#9565](#9565)

### Chore

- **(ci)** fail registry tests without summary by @jdx in
[#9559](#9559)
- **(ci)** use !cancelled() instead of always() for test-ci aggregator
by @jdx in [#9569](#9569)
- **(ci)** use namespace runners for ci jobs by @jdx in
[#9561](#9561)
- **(config)** deprecate shorthands_file setting by @risu729 in
[#9534](#9534)
- **(docs)** remove shrill.en.dev analytics script by @jdx in
[#9539](#9539)
- **(release)** replace bc with awk in release-plz star formatting by
@jdx in
[d7f177f](d7f177f)
- bump hk to 1.44.3 by @jdx in
[#9493](#9493)
- invert CLAUDE.md/AGENTS.md so AGENTS.md is canonical by @jdx in
[#9560](#9560)
- set dev profile debug to 1 by @jdx in
[#9572](#9572)

### New Contributors

- @kuboon made their first contribution in
[#9567](#9567)
- @AlternateRT made their first contribution in
[#9557](#9557)
- @2xdevv made their first contribution in
[#9555](#9555)
- @adam-moss made their first contribution in
[#9541](#9541)
- @jlarmstrongiv made their first contribution in
[#9496](#9496)
- @tjarvstrand made their first contribution in
[#9505](#9505)
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.

1 participant