From 00e7a36fc1f980b82a978348d6eceb2e65d7d83a Mon Sep 17 00:00:00 2001 From: Jonathan Schneider Date: Mon, 24 Aug 2026 09:18:08 -0400 Subject: [PATCH] Match a distribution whose candidate carries a vendor build SDKMAN candidates now read `17.0.20+1.1-zulu`, and the build lands in the qualifier that the distribution is matched against, so no candidate for the requested distribution survives the filter and the recipe stops upgrading. Only a build is tolerated ahead of the distribution rather than anything at all: a variant such as `.crac-zulu` is a distinct distribution, and a plain request should keep on not selecting it. --- .../openrewrite/java/migrate/UpdateSdkMan.java | 12 ++++++++++-- .../java/migrate/UpdateSdkManTest.java | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/openrewrite/java/migrate/UpdateSdkMan.java b/src/main/java/org/openrewrite/java/migrate/UpdateSdkMan.java index f33983050b..9f30faacc7 100644 --- a/src/main/java/org/openrewrite/java/migrate/UpdateSdkMan.java +++ b/src/main/java/org/openrewrite/java/migrate/UpdateSdkMan.java @@ -42,6 +42,13 @@ @Value public class UpdateSdkMan extends Recipe { + /** + * Candidates carry the vendor build between the version and the distribution, as in `17.0.20+1.1-zulu`, and that + * lands in the qualifier the distribution is matched against. Only a build is tolerated ahead of the distribution, + * so a variant such as `.crac-zulu` is still a distinct distribution rather than a match for plain `-zulu`. + */ + private static final String BUILD_METADATA = "(\\+[^-]*)?"; + @Option(displayName = "Java version", description = "The Java version to update to. Use `latest.patch` to upgrade to the latest version within the current major version.", required = false, @@ -96,13 +103,14 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { String dist = newDistribution == null ? matcher.group(2) : "-" + newDistribution; String newBasis = ver + dist; Pattern majorPattern = Pattern.compile("^" + ver + "[.-].*"); - LatestRelease releaseComparator = new LatestRelease(dist); + String distPattern = BUILD_METADATA + dist; + LatestRelease releaseComparator = new LatestRelease(distPattern); String idealCandidate = readSdkmanJavaCandidates().stream() .filter(candidate -> majorPattern.matcher(candidate).matches()) .filter(candidate -> releaseComparator.isValid(newBasis, candidate)) .max(releaseComparator) .orElse(null); - if (idealCandidate != null && !isRequestedDowngrade(matcher.group(1) + dist, idealCandidate, dist)) { + if (idealCandidate != null && !isRequestedDowngrade(matcher.group(1) + dist, idealCandidate, distPattern)) { return plainText.withText(matcher.replaceFirst("java=" + idealCandidate)); } } diff --git a/src/test/java/org/openrewrite/java/migrate/UpdateSdkManTest.java b/src/test/java/org/openrewrite/java/migrate/UpdateSdkManTest.java index 3207b0ab5b..ac599a3533 100644 --- a/src/test/java/org/openrewrite/java/migrate/UpdateSdkManTest.java +++ b/src/test/java/org/openrewrite/java/migrate/UpdateSdkManTest.java @@ -176,6 +176,24 @@ void zuluNonCrac() { """ java=11.0.28-zulu """, + spec -> spec.path(".sdkmanrc") + .after(str -> assertThat(str) + .startsWith("java=17.0.") + .endsWith("-zulu") + .doesNotContain(".crac") + .actual()) + ) + ); + } + + @Test + void distributionIsStillMatchedWhenTheCandidateCarriesAVendorBuild() { + rewriteRun( + spec -> spec.recipe(new UpdateSdkMan("17", null)), + text( + """ + java=11.0.28+1.1-zulu + """, spec -> spec.path(".sdkmanrc") .after(str -> assertThat(str) .startsWith("java=17.0.")