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 {

Reply via email to