This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch backport/maven-4.0.x/pr-12105 in repository https://gitbox.apache.org/repos/asf/maven.git
commit b57809c1f84e6eedee0b17eeb43da11a0ed3cb92 Merge: dc30cbfef5 0a792e8a8a Author: Guillaume Nodet <[email protected]> AuthorDate: Tue May 19 17:10:09 2026 +0200 Merge remote-tracking branch 'origin/maven-4.0.x' into backport/maven-4.0.x/pr-12105 # Conflicts: # impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java .../main/appended-resources/META-INF/LICENSE.vm | 3 +- .../model/validation/DefaultModelValidator.java | 73 ++- .../validation/DefaultModelValidatorTest.java | 4 + .../java/org/apache/maven/model/ModelTest.java | 13 + .../plugin/descriptor/PluginDescriptorBuilder.java | 38 +- impl/maven-cli/pom.xml | 9 +- .../maven/cling/invoker/mvnup/UpgradeContext.java | 2 +- .../invoker/mvnup/goals/AbstractUpgradeGoal.java | 45 +- .../mvnup/goals/AbstractUpgradeStrategy.java | 94 ++- .../mvnup/goals/CompatibilityFixStrategy.java | 490 ++++++-------- .../maven/cling/invoker/mvnup/goals/DomUtils.java | 211 ++++++ .../maven/cling/invoker/mvnup/goals/GAV.java | 49 -- .../maven/cling/invoker/mvnup/goals/GAVUtils.java | 132 ---- .../invoker/mvnup/goals/InferenceStrategy.java | 389 +++++------ .../maven/cling/invoker/mvnup/goals/JDomUtils.java | 544 ---------------- .../invoker/mvnup/goals/ModelUpgradeStrategy.java | 209 +++--- .../invoker/mvnup/goals/ModelVersionUtils.java | 85 ++- .../invoker/mvnup/goals/PluginUpgradeStrategy.java | 209 +++--- .../cling/invoker/mvnup/goals/PomDiscovery.java | 273 ++------ .../invoker/mvnup/goals/StrategyOrchestrator.java | 193 +++--- .../invoker/mvnup/goals/UpgradeConstants.java | 236 ------- .../cling/invoker/mvnup/goals/UpgradeStrategy.java | 12 +- .../cling/invoker/mvnup/goals/package-info.java | 2 +- .../mvnup/goals/AbstractUpgradeGoalTest.java | 5 +- .../mvnup/goals/CompatibilityFixStrategyTest.java | 124 ++-- .../cling/invoker/mvnup/goals/DomUtilsTest.java | 725 +++++++++++++++++++++ .../maven/cling/invoker/mvnup/goals/GAVTest.java | 149 ----- .../cling/invoker/mvnup/goals/GAVUtilsTest.java | 102 ++- .../invoker/mvnup/goals/InferenceStrategyTest.java | 257 ++++---- .../cling/invoker/mvnup/goals/JDomUtilsTest.java | 453 ------------- .../mvnup/goals/ModelUpgradeStrategyTest.java | 312 ++++----- .../invoker/mvnup/goals/ModelVersionUtilsTest.java | 80 ++- .../mvnup/goals/PluginUpgradeStrategyTest.java | 207 +++--- .../cling/invoker/mvnup/goals/PomBuilder.java | 10 +- .../mvnup/goals/StrategyOrchestratorTest.java | 2 +- .../maven/cling/invoker/mvnup/goals/TestUtils.java | 11 + .../maven/project/DefaultProjectBuilder.java | 17 +- .../org/apache/maven/project/MavenProject.java | 20 +- .../maven/project/ProjectBuildingException.java | 84 ++- .../project/DefaultMavenProjectBuilderTest.java | 39 ++ .../project/ProjectBuildingExceptionTest.java | 163 +++++ .../apache/maven/project/ResourceIncludeTest.java | 58 ++ .../org/test/parent-pom/1.0/parent-pom-1.0.pom | 31 + .../child/pom.xml | 12 + .../pom.xml | 10 + .../parent-version-inherited-from-remote/pom.xml | 12 + .../maven/impl/model/DefaultModelBuilder.java | 26 +- .../maven/impl/model/DefaultModelValidator.java | 101 ++- .../impl/model/DefaultModelValidatorTest.java | 40 +- .../maven/impl/model/ParentCycleDetectionTest.java | 63 ++ .../raw-model/dm-with-chained-property-in-id.xml | 46 ++ pom.xml | 17 +- src/graph/ReactorGraph.java | 2 +- src/mdo/java/WrapperProperties.java | 6 + src/mdo/model-v3.vm | 6 +- 55 files changed, 3236 insertions(+), 3269 deletions(-) diff --cc impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java index ff572d49b4,266af03dff..fc76df6354 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategy.java @@@ -490,21 -459,19 +459,21 @@@ public class CompatibilityFixStrategy e } boolean fixed = false; - String elementType = repositoriesElement.getName().equals(REPOSITORIES) ? REPOSITORY : PLUGIN_REPOSITORY; - List<Element> repositories = repositoriesElement.getChildren(elementType, namespace); + String elementType = repositoriesElement.name().equals(REPOSITORIES) ? REPOSITORY : PLUGIN_REPOSITORY; + List<Element> repositories = repositoriesElement.children(elementType).toList(); for (Element repository : repositories) { - Element urlElement = repository.getChild("url", namespace); + Element urlElement = repository.child("url").orElse(null); if (urlElement != null) { - String url = urlElement.getTextTrim(); + String url = urlElement.textContent().trim(); - if (url.contains("${")) { - // Allow repository URL interpolation; do not disable. - // Keep a gentle warning to help users notice unresolved placeholders at build time. + String fixedUrl = + url.replace("${basedir}", "${project.basedir}").replace("${pom.basedir}", "${project.basedir}"); + if (!fixedUrl.equals(url)) { - urlElement.setText(fixedUrl); - String repositoryId = getChildText(repository, "id", namespace); ++ urlElement.textContent(fixedUrl); + String repositoryId = repository.childText("id"); - context.info("Detected interpolated expression in " + elementType + " URL (id: " + repositoryId - + "): " + url); + context.detail("Fixed: replaced deprecated expression in " + elementType + " URL (id: " + + repositoryId + "): " + url + " → " + fixedUrl); + fixed = true; } } } diff --cc impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategyTest.java index 12bbf60f89,af8b0774c7..bfe296769b --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategyTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/CompatibilityFixStrategyTest.java @@@ -287,203 -281,6 +281,203 @@@ class CompatibilityFixStrategyTest } } + @Nested + @DisplayName("Repository Expression Fixes") + class RepositoryExpressionFixesTests { + + @Test + @DisplayName("should replace ${basedir} with ${project.basedir} in repository URLs") + void shouldReplaceBasedirInRepositoryUrls() 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> + <repositories> + <repository> + <id>local-repo</id> + <url>file://${basedir}/internal-repository</url> + </repository> + </repositories> + </project> + """; + - Document document = saxBuilder.build(new StringReader(pomXml)); ++ Document document = Document.of(pomXml); + Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); - UpgradeResult result = strategy.apply(context, pomMap); ++ UpgradeResult result = strategy.doApply(context, pomMap); + + assertTrue(result.success(), "Compatibility fix should succeed"); + assertTrue(result.modifiedCount() > 0, "Should have fixed basedir expression"); + - Element root = document.getRootElement(); - Element repositories = root.getChild("repositories", root.getNamespace()); - Element repository = repositories.getChild("repository", root.getNamespace()); - Element url = repository.getChild("url", root.getNamespace()); ++ Element root = document.root(); ++ Element repositories = DomUtils.findChildElement(root, "repositories"); ++ Element repository = DomUtils.findChildElement(repositories, "repository"); ++ Element url = DomUtils.findChildElement(repository, "url"); + assertEquals( + "file://${project.basedir}/internal-repository", - url.getTextTrim(), ++ url.textContent().trim(), + "Should have replaced ${basedir} with ${project.basedir}"); + } + + @Test + @DisplayName("should replace ${pom.basedir} with ${project.basedir} in repository URLs") + void shouldReplacePomBasedirInRepositoryUrls() 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> + <repositories> + <repository> + <id>local-repo</id> + <url>file://${pom.basedir}/lib</url> + </repository> + </repositories> + </project> + """; + - Document document = saxBuilder.build(new StringReader(pomXml)); ++ Document document = Document.of(pomXml); + Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); - UpgradeResult result = strategy.apply(context, pomMap); ++ UpgradeResult result = strategy.doApply(context, pomMap); + + assertTrue(result.success(), "Compatibility fix should succeed"); + assertTrue(result.modifiedCount() > 0, "Should have fixed pom.basedir expression"); + - Element root = document.getRootElement(); - Element repositories = root.getChild("repositories", root.getNamespace()); - Element repository = repositories.getChild("repository", root.getNamespace()); - Element url = repository.getChild("url", root.getNamespace()); ++ Element root = document.root(); ++ Element repositories = DomUtils.findChildElement(root, "repositories"); ++ Element repository = DomUtils.findChildElement(repositories, "repository"); ++ Element url = DomUtils.findChildElement(repository, "url"); + assertEquals( + "file://${project.basedir}/lib", - url.getTextTrim(), ++ url.textContent().trim(), + "Should have replaced ${pom.basedir} with ${project.basedir}"); + } + + @Test + @DisplayName("should replace ${basedir} in pluginRepository URLs") + void shouldReplaceBasedirInPluginRepositoryUrls() 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> + <pluginRepositories> + <pluginRepository> + <id>local-plugins</id> + <url>file://${basedir}/plugin-repo</url> + </pluginRepository> + </pluginRepositories> + </project> + """; + - Document document = saxBuilder.build(new StringReader(pomXml)); ++ Document document = Document.of(pomXml); + Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); - UpgradeResult result = strategy.apply(context, pomMap); ++ UpgradeResult result = strategy.doApply(context, pomMap); + + assertTrue(result.success(), "Compatibility fix should succeed"); + assertTrue(result.modifiedCount() > 0, "Should have fixed basedir in pluginRepository"); + - Element root = document.getRootElement(); - Element pluginRepositories = root.getChild("pluginRepositories", root.getNamespace()); - Element pluginRepository = pluginRepositories.getChild("pluginRepository", root.getNamespace()); - Element url = pluginRepository.getChild("url", root.getNamespace()); ++ Element root = document.root(); ++ Element pluginRepositories = DomUtils.findChildElement(root, "pluginRepositories"); ++ Element pluginRepository = DomUtils.findChildElement(pluginRepositories, "pluginRepository"); ++ Element url = DomUtils.findChildElement(pluginRepository, "url"); + assertEquals( + "file://${project.basedir}/plugin-repo", - url.getTextTrim(), ++ url.textContent().trim(), + "Should have replaced ${basedir} with ${project.basedir}"); + } + + @Test + @DisplayName("should replace ${basedir} in profile repository URLs") + void shouldReplaceBasedirInProfileRepositoryUrls() 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> + <profiles> + <profile> + <id>local</id> + <repositories> + <repository> + <id>local-repo</id> + <url>file://${basedir}/repo</url> + </repository> + </repositories> + </profile> + </profiles> + </project> + """; + - Document document = saxBuilder.build(new StringReader(pomXml)); ++ Document document = Document.of(pomXml); + Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); - UpgradeResult result = strategy.apply(context, pomMap); ++ UpgradeResult result = strategy.doApply(context, pomMap); + + assertTrue(result.success(), "Compatibility fix should succeed"); + assertTrue(result.modifiedCount() > 0, "Should have fixed basedir in profile repository"); + - Element root = document.getRootElement(); - Element profiles = root.getChild("profiles", root.getNamespace()); - Element profile = profiles.getChild("profile", root.getNamespace()); - Element repositories = profile.getChild("repositories", root.getNamespace()); - Element repository = repositories.getChild("repository", root.getNamespace()); - Element url = repository.getChild("url", root.getNamespace()); ++ Element root = document.root(); ++ Element profiles = DomUtils.findChildElement(root, "profiles"); ++ Element profile = DomUtils.findChildElement(profiles, "profile"); ++ Element repositories = DomUtils.findChildElement(profile, "repositories"); ++ Element repository = DomUtils.findChildElement(repositories, "repository"); ++ Element url = DomUtils.findChildElement(repository, "url"); + assertEquals( + "file://${project.basedir}/repo", - url.getTextTrim(), ++ url.textContent().trim(), + "Should have replaced ${basedir} with ${project.basedir}"); + } + + @Test + @DisplayName("should not modify repository URLs without deprecated expressions") + void shouldNotModifyUrlsWithoutDeprecatedExpressions() 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> + <repositories> + <repository> + <id>central</id> + <url>https://repo.maven.apache.org/maven2</url> + </repository> + <repository> + <id>local-repo</id> + <url>file://${project.basedir}/repo</url> + </repository> + </repositories> + </project> + """; + - Document document = saxBuilder.build(new StringReader(pomXml)); ++ Document document = Document.of(pomXml); + Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); - UpgradeResult result = strategy.apply(context, pomMap); ++ UpgradeResult result = strategy.doApply(context, pomMap); + + assertTrue(result.success(), "Compatibility fix should succeed"); + assertEquals(0, result.modifiedCount(), "Should not have modified any POMs"); + } + } + @Nested @DisplayName("Strategy Description") class StrategyDescriptionTests { diff --cc impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvnup/goals/PluginUpgradeStrategyTest.java index ada85cdf0e,2ba4de0c2b..18ee2cdc76 --- 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 -187,46 +187,47 @@@ class PluginUpgradeStrategyTest // 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)); ++ Document document = Document.of(pomXml); + Map<Path, Document> pomMap = Map.of(Paths.get("pom.xml"), document); + + UpgradeContext context = createMockContext(); - UpgradeResult result = strategy.apply(context, pomMap); ++ UpgradeResult result = strategy.doApply(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); ++ Element root = document.root(); ++ Element build = DomUtils.findChildElement(root, "build"); ++ Element plugins = DomUtils.findChildElement(build, "plugins"); ++ Element plugin = DomUtils.findChildElement(plugins, "plugin"); ++ Element versionElement = DomUtils.findChildElement(plugin, "version"); ++ String version = ++ versionElement != null ? versionElement.textContent().trim() : null; + 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 {
