fix(prerelease): detect Gradle-style -M\d+ milestone tags#143
fix(prerelease): detect Gradle-style -M\d+ milestone tags#143
Conversation
PRERELEASE_REGEX matches `-rc`, `-milestone`, `-alpha`, `-beta` etc. but missed Gradle's actual milestone tag style `-M\d+` (e.g. `9.6.0-M1`, `1.0.0-M1`, `1.0.0-M8a`). As a result, isPrerelease returns false for those, and `latest_stable_version` for `gradle` was computed as `9.6.0-M1` (a milestone preview) instead of `9.5.0` (the actual stable release shipped 2026-04-28). Adds `[-.]M\d+` as another alternation. Updated in both copies of the regex (scripts/sync-to-d1.js writer + web/src/lib/versions.ts filter) so the fix lands on both the data sync and the frontend. Verified against the relevant cases — matches Gradle/Spring-style milestones, doesn't false-match domain words like `Mar-2024` or `Maven`, and doesn't break existing matches: 9.6.0-M1 -> true ✓ (the bug case) 1.0.0-M1 -> true ✓ 1.0.0-M8a -> true ✓ 9.5.0 -> false ✓ 9.5.0-RC4 -> true ✓ 2.0.0-Mar-2024 -> false ✓ (no false positive) 3.0-Maven -> false ✓ (no false positive) 2.0.0.M1 -> true ✓ (dot-separated milestone) After the next scheduled `update` workflow run, the `gradle` metadata at mise-versions.jdx.dev/tools/gradle should report `latest_stable_version: "9.5.0"`. Refs jdx/mise#9499. Side-note: the same metadata also shows `last_updated: 2023-09-26T07:52:24.000Z` and frozen per-version `created_at` for gradle — that's a separate operational issue, the existing scripts/backfill-created-at.js can address it (running with --tool=gradle once mise ls-remote --json returns real timestamps for github_release backends).
There was a problem hiding this comment.
Code Review
This pull request updates the prerelease version regex and documentation in both scripts/sync-to-d1.js and web/src/lib/versions.ts to include support for Gradle-style milestone tags (e.g., -M1, .M1). The review feedback suggests consolidating the regex patterns to consistently handle both dash and dot separators for various prerelease tags like milestone, alpha, beta, and next, which would improve the robustness and readability of the detection logic.
| // Prerelease version regex - ported from mise | ||
| const PRERELEASE_REGEX = | ||
| /(-src|-dev|-latest|-stm|[-.](rc|pre)|-milestone|-alpha|-beta|-next|([abc])\d+$|snapshot|master)/i; | ||
| /(-src|-dev|-latest|-stm|[-.](rc|pre)|[-.]M\d+|-milestone|-alpha|-beta|-next|([abc])\d+$|snapshot|master)/i; |
There was a problem hiding this comment.
The regex can be simplified and made more consistent by consolidating the tags that support both dash and dot separators into a single group. This also provides an opportunity to add dot-separator support for milestone, alpha, beta, and next, which is common in many versioning schemes and improves the robustness of the prerelease detection.
| /(-src|-dev|-latest|-stm|[-.](rc|pre)|[-.]M\d+|-milestone|-alpha|-beta|-next|([abc])\d+$|snapshot|master)/i; | |
| /(-src|-dev|-latest|-stm|[-.](rc|pre|M\d+|milestone|alpha|beta|next)|([abc])\d+$|snapshot|master)/i; |
| * - -M1, -M2, .M1 etc. (Gradle-style milestone tags, e.g. 9.6.0-M1) | ||
| * - -milestone (milestone releases — long form) |
There was a problem hiding this comment.
Updating the documentation to reflect that the long-form milestone tag now also supports the dot separator (consistent with the short-form M\d+ and rc/pre tags).
| * - -M1, -M2, .M1 etc. (Gradle-style milestone tags, e.g. 9.6.0-M1) | |
| * - -milestone (milestone releases — long form) | |
| * - -M1, -M2, .M1 etc. (Gradle-style milestone tags, e.g. 9.6.0-M1) | |
| * - -milestone, .milestone (milestone releases — long form) |
| */ | ||
| const PRERELEASE_REGEX = | ||
| /(-src|-dev|-latest|-stm|[-.](rc|pre)|-milestone|-alpha|-beta|-next|([abc])\d+$|snapshot|master)/i; | ||
| /(-src|-dev|-latest|-stm|[-.](rc|pre)|[-.]M\d+|-milestone|-alpha|-beta|-next|([abc])\d+$|snapshot|master)/i; |
There was a problem hiding this comment.
Consolidating the prerelease tags into a single group that handles both dash and dot separators. This improves readability and ensures that all relevant tags (including alpha, beta, and next) are detected regardless of the separator used.
| /(-src|-dev|-latest|-stm|[-.](rc|pre)|[-.]M\d+|-milestone|-alpha|-beta|-next|([abc])\d+$|snapshot|master)/i; | |
| /(-src|-dev|-latest|-stm|[-.](rc|pre|M\d+|milestone|alpha|beta|next)|([abc])\d+$|snapshot|master)/i; |
Greptile SummaryThis PR adds Confidence Score: 5/5Safe to merge — the regex change is correct, well-reasoned, and applied consistently in both locations. No P0 or P1 issues found. The new No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Version string"] --> B{"PRERELEASE_REGEX.test"}
B -->|"matches -src/-dev/-latest/-stm"| C["prerelease = true"]
B -->|"matches dash/dot + rc/pre/M1/milestone/alpha/beta/next"| C
B -->|"matches a,b,c + digits at end"| C
B -->|"matches snapshot or master"| C
B -->|"no match"| D["prerelease = false"]
C --> E["Excluded from latest_stable_version"]
D --> F["Candidate for latest_stable_version"]
F --> G["sync-to-d1.js picks last stable"]
F --> H["VersionsTable.tsx frontend filter"]
Reviews (2): Last reviewed commit: "review: consolidate prerelease tags into..." | Re-trigger Greptile |
Per gemini-code-assist's PR review (jdx#143): collapse the scattered `-milestone`, `-alpha`, `-beta`, `-next` and the new `[-.]M\d+` into one alternation group `[-.](rc|pre|M\d+| milestone|alpha|beta|next)`. Same coverage as before, plus dot- separator support for `milestone` / `alpha` / `beta` / `next` (which already worked for `rc` / `pre`). Net: more uniform, more readable, and catches a few legitimate prerelease conventions that previously slipped through (e.g. `1.0.alpha`, `1.0.next`). Verified 20/20 cases including originals (9.6.0-M1, 1.0.0-M8a, 9.5.0-RC4), false-positive guards (-Mar-2024, -Maven), and the new dot-form additions (1.0.alpha, 1.0.beta, 1.0.next, 1.0.milestone). Docstring in web/src/lib/versions.ts updated to reflect the broadened separator coverage.
|
Thanks @gemini-code-assist — applied your suggestion in d6a86d1. Consolidated all four scattered tags ( Re-ran the test cases against the new regex (20 cases, all pass): Docstring in |
|
Thanks for the update, @ZoeyJones. Consolidating the regex into a single group is a cleaner approach and improves maintainability while ensuring consistent behavior across the board. The updated test cases look comprehensive and correctly validate the new logic, including the dot-separator support. This looks solid. |
|
it's not at all accurate, please stop |
I feel bad for having the AI spammed the PR. My main goal is that I do not want the Railway system consuming the Mise build system, which is using Gradle 9.6.0-M1 by default. The railway logs and the official doc screenshot posted in jdx/mise#9499 shows the inconsistency. I would be enormously grateful that there could be proper fix or clarification on the official doc link https://mise-versions.jdx.dev/tools/gradle. The stats is concerning as we have 631 downloads of 9.6.0-M1 yet only 112 of 9.5.0, as
|
|
probably just outdated clients |

Summary
PRERELEASE_REGEXmatches-rc,-milestone,-alpha,-betaetc. but missed Gradle's actual milestone tag style-M\d+(e.g.9.6.0-M1,1.0.0-M1,1.0.0-M8a). As a result,isPrerelease("9.6.0-M1")returnsfalse, and the loop inscripts/sync-to-d1.js:191-198happily picks the milestone aslatest_stable_version.Concretely today:
mise-versions.jdx.dev/tools/gradlereportslatest_stable_version: "9.6.0-M1"even thoughv9.5.0shipped on 2026-04-28 (and is correctly taggedprerelease=falseupstream atgradle/gradle-distributions).Fix
Add
[-.]M\d+as another alternation inPRERELEASE_REGEX. Updated in both copies (the writer inscripts/sync-to-d1.jsand the frontend filter inweb/src/lib/versions.ts) so the fix lands on the D1 sync AND the live frontend.Test cases
Reproducible with no project deps — just a one-liner against the new regex:
All 13 of my local cases pass (full set in the commit message).
Why
[-.]M\d+and not[-.]M\bor[-.]milestone-only[-.]M\d+— strict: requiresMfollowed by digits, scoped to dash/dot-separated suffixes. Matches Gradle/Spring (-M1) and dot-form (.M1). RejectsMar-2024,Maven,master-1(already filtered bymaster).[-.]M\bwould match a single-Mwith no digits, broader than necessary.-milestone(long form) is already in the regex but the actual tags Gradle publishes use the short form-M\d+. The asset filename uses-milestone-1, but the Git tag (and what mise's registry sees) is-M1.I considered consolidating the duplicated regex into a shared module, but the two consumers run in different environments (Node CommonJS-ish ESM vs Cloudflare Workers + TypeScript) and the file moves across deployment targets. Happy to do the consolidation in a follow-up if you'd prefer; kept this PR minimal and surgical.
Out of scope but related
The same gradle metadata also reports
last_updated: "2023-09-26T07:52:24.000Z"and every per-versioncreated_atis frozen at the registry-seed date. That's not a regex bug — it's thatmise ls-remote --json gradleoutput isn't refreshing per-version timestamps, soscripts/generate-toml.js'sv.created_at || existing.created_at || nowfallback keeps the stale existing date. The existingscripts/backfill-created-at.jsscript was built for exactly this — running it with--tool=gradleshould refresh the dates as long asmise ls-remote --json gradlereturns realcreated_atvalues. I can file a follow-up issue if useful, but the regex fix is independently valuable.Refs