This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch fix-milestone-version-comparison-4.0.x in repository https://gitbox.apache.org/repos/asf/maven.git
commit f7c482b5630d53bdf5003d41e67a9bcffd973f1e Author: Guillaume Nodet <[email protected]> AuthorDate: Mon May 18 08:45:28 2026 +0200 Use maven-api Version for mvnup plugin version comparison Replace hand-rolled version comparison with Session.parseVersion() which correctly handles milestone/pre-release qualifiers. The previous implementation stripped qualifiers (e.g., 3.0.0-M1 → 3.0.0) causing pre-release versions to be incorrectly considered sufficient. This fixes 19 projects (flink-connectors, sling) using enforcer 3.0.0-M1 that mvnup failed to upgrade to 3.0.0. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> --- .../invoker/mvnup/goals/PluginUpgradeStrategy.java | 28 +-------------- .../mvnup/goals/PluginUpgradeStrategyTest.java | 40 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java index 3b0dfa6538..21a9f16c1b 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategy.java @@ -381,33 +381,7 @@ private boolean isVersionBelow(String currentVersion, String minVersion) { if (currentVersion == null || minVersion == null) { return false; } - - // Remove any qualifiers like -SNAPSHOT, -alpha, etc. for comparison - String cleanCurrent = currentVersion.split("-")[0]; - String cleanMin = minVersion.split("-")[0]; - - try { - String[] currentParts = cleanCurrent.split("\\."); - String[] minParts = cleanMin.split("\\."); - - int maxLength = Math.max(currentParts.length, minParts.length); - - for (int i = 0; i < maxLength; i++) { - int currentPart = i < currentParts.length ? Integer.parseInt(currentParts[i]) : 0; - int minPart = i < minParts.length ? Integer.parseInt(minParts[i]) : 0; - - if (currentPart < minPart) { - return true; - } else if (currentPart > minPart) { - return false; - } - } - - return false; // Versions are equal - } catch (NumberFormatException e) { - // Fallback to string comparison if parsing fails - return currentVersion.compareTo(minVersion) < 0; - } + return getSession().parseVersion(currentVersion).compareTo(getSession().parseVersion(minVersion)) < 0; } /** diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java index ada85cdf0e..e59e2a072a 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java @@ -195,6 +195,46 @@ void shouldNotModifyPluginWhenVersionAlreadySufficient() throws Exception { // POM might still be marked as modified due to other plugin management additions } + @Test + @DisplayName("should upgrade milestone version below release minimum") + void shouldUpgradeMilestoneVersionBelowRelease() throws Exception { + String pomXml = """ + <?xml version="1.0" encoding="UTF-8"?> + <project xmlns="http://maven.apache.org/POM/4.0.0"> + <modelVersion>4.0.0</modelVersion> + <groupId>test</groupId> + <artifactId>test</artifactId> + <version>1.0.0</version> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <version>3.0.0-M1</version> + </plugin> + </plugins> + </build> + </project> + """; + + Document document = saxBuilder.build(new StringReader(pomXml)); + Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); + UpgradeResult result = strategy.apply(context, pomMap); + + assertTrue(result.success(), "Plugin upgrade should succeed"); + assertTrue(result.modifiedCount() > 0, "Should have upgraded 3.0.0-M1 to 3.0.0"); + + Element root = document.getRootElement(); + Namespace namespace = root.getNamespace(); + Element build = root.getChild("build", namespace); + Element plugins = build.getChild("plugins", namespace); + Element plugin = plugins.getChild("plugin", namespace); + String version = plugin.getChildText("version", namespace); + assertEquals("3.0.0", version, "3.0.0-M1 should be upgraded to 3.0.0"); + } + @Test @DisplayName("should upgrade plugin in pluginManagement") void shouldUpgradePluginInPluginManagement() throws Exception {
