You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2025/09/17 10:48:24 UTC

(maven) branch master updated: model-builder: simplify subproject auto-discovery decision (#11124)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new b2690b703d model-builder: simplify subproject auto-discovery decision (#11124)
b2690b703d is described below

commit b2690b703ded7f369bf493418dbb4a040300f3c4
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Wed Sep 17 12:48:19 2025 +0200

    model-builder: simplify subproject auto-discovery decision (#11124)
    
    - Treat explicit empty <subprojects/> as disabling discovery.
    - Base decision solely on explicit subprojects/modules in the main model; ignore profiles.
    - Inline the check using location tracking and remove profile scanning.
---
 .../project/DefaultMavenProjectBuilderTest.java    | 40 ++++++++++++++++++++++
 .../resources/projects/modules-empty/child/pom.xml |  8 +++++
 .../test/resources/projects/modules-empty/pom.xml  |  7 ++++
 .../projects/subprojects-empty/child/pom.xml       |  8 +++++
 .../resources/projects/subprojects-empty/pom.xml   |  7 ++++
 .../maven/impl/model/DefaultModelBuilder.java      | 16 ++++++++-
 6 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java
index b891b66d0a..27060c91dd 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java
@@ -547,4 +547,44 @@ public void testSubprojectDiscovery() throws Exception {
         MavenProject parent = p1.getArtifactId().equals("parent") ? p1 : p2;
         assertEquals(List.of("child"), parent.getModel().getDelegate().getSubprojects());
     }
+
+    @Test
+    public void testEmptySubprojectsElementPreventsDiscovery() throws Exception {
+        File pom = getTestFile("src/test/resources/projects/subprojects-empty/pom.xml");
+        ProjectBuildingRequest configuration = newBuildingRequest();
+        InternalSession internalSession = InternalSession.from(configuration.getRepositorySession());
+        InternalMavenSession mavenSession = InternalMavenSession.from(internalSession);
+        mavenSession
+                .getMavenSession()
+                .getRequest()
+                .setRootDirectory(pom.toPath().getParent());
+
+        List<ProjectBuildingResult> results = projectBuilder.build(List.of(pom), true, configuration);
+        // Should only build the parent project, not discover the child
+        assertEquals(1, results.size());
+        MavenProject parent = results.get(0).getProject();
+        assertEquals("parent", parent.getArtifactId());
+        // The subprojects list should be empty since we explicitly defined an empty <subprojects /> element
+        assertTrue(parent.getModel().getDelegate().getSubprojects().isEmpty());
+    }
+
+    @Test
+    public void testEmptyModulesElementPreventsDiscovery() throws Exception {
+        File pom = getTestFile("src/test/resources/projects/modules-empty/pom.xml");
+        ProjectBuildingRequest configuration = newBuildingRequest();
+        InternalSession internalSession = InternalSession.from(configuration.getRepositorySession());
+        InternalMavenSession mavenSession = InternalMavenSession.from(internalSession);
+        mavenSession
+                .getMavenSession()
+                .getRequest()
+                .setRootDirectory(pom.toPath().getParent());
+
+        List<ProjectBuildingResult> results = projectBuilder.build(List.of(pom), true, configuration);
+        // Should only build the parent project, not discover the child
+        assertEquals(1, results.size());
+        MavenProject parent = results.get(0).getProject();
+        assertEquals("parent", parent.getArtifactId());
+        // The modules list should be empty since we explicitly defined an empty <modules /> element
+        assertTrue(parent.getModel().getDelegate().getModules().isEmpty());
+    }
 }
diff --git a/impl/maven-core/src/test/resources/projects/modules-empty/child/pom.xml b/impl/maven-core/src/test/resources/projects/modules-empty/child/pom.xml
new file mode 100644
index 0000000000..022d865352
--- /dev/null
+++ b/impl/maven-core/src/test/resources/projects/modules-empty/child/pom.xml
@@ -0,0 +1,8 @@
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <parent>
+    <groupId>modules-empty</groupId>
+    <artifactId>parent</artifactId>
+  </parent>
+  <artifactId>child</artifactId>
+  <packaging>jar</packaging>
+</project>
diff --git a/impl/maven-core/src/test/resources/projects/modules-empty/pom.xml b/impl/maven-core/src/test/resources/projects/modules-empty/pom.xml
new file mode 100644
index 0000000000..b36128e6a5
--- /dev/null
+++ b/impl/maven-core/src/test/resources/projects/modules-empty/pom.xml
@@ -0,0 +1,7 @@
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <groupId>modules-empty</groupId>
+  <artifactId>parent</artifactId>
+  <version>1</version>
+  <packaging>pom</packaging>
+  <modules />
+</project>
diff --git a/impl/maven-core/src/test/resources/projects/subprojects-empty/child/pom.xml b/impl/maven-core/src/test/resources/projects/subprojects-empty/child/pom.xml
new file mode 100644
index 0000000000..1c4f2b7709
--- /dev/null
+++ b/impl/maven-core/src/test/resources/projects/subprojects-empty/child/pom.xml
@@ -0,0 +1,8 @@
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <parent>
+    <groupId>subprojects-empty</groupId>
+    <artifactId>parent</artifactId>
+  </parent>
+  <artifactId>child</artifactId>
+  <packaging>jar</packaging>
+</project>
diff --git a/impl/maven-core/src/test/resources/projects/subprojects-empty/pom.xml b/impl/maven-core/src/test/resources/projects/subprojects-empty/pom.xml
new file mode 100644
index 0000000000..840c572d1d
--- /dev/null
+++ b/impl/maven-core/src/test/resources/projects/subprojects-empty/pom.xml
@@ -0,0 +1,7 @@
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <groupId>subprojects-empty</groupId>
+  <artifactId>parent</artifactId>
+  <version>1</version>
+  <packaging>pom</packaging>
+  <subprojects />
+</project>
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
index 95b7fd842a..9b17dcb380 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
@@ -1393,7 +1393,7 @@ Model doReadFileModel() throws ModelBuilderException {
                 }
 
                 // subprojects discovery
-                if (getSubprojects(model).isEmpty()
+                if (!hasSubprojectsDefined(model)
                         // only discover subprojects if POM > 4.0.0
                         && !MODEL_VERSION_4_0_0.equals(model.getModelVersion())
                         // and if packaging is POM (we check type, but the session is not yet available,
@@ -1934,6 +1934,20 @@ private static List<String> getSubprojects(Model activated) {
         return subprojects;
     }
 
+    /**
+     * Checks if subprojects are explicitly defined in the main model.
+     * This method distinguishes between:
+     * 1. No subprojects/modules element present - returns false (should auto-discover)
+     * 2. Empty subprojects/modules element present - returns true (should NOT auto-discover)
+     * 3. Non-empty subprojects/modules - returns true (should NOT auto-discover)
+     */
+    @SuppressWarnings("deprecation")
+    private static boolean hasSubprojectsDefined(Model model) {
+        // Only consider the main model: profiles do not influence auto-discovery
+        // Inline the check for explicit elements using location tracking
+        return model.getLocation("subprojects") != null || model.getLocation("modules") != null;
+    }
+
     @Override
     public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException {
         RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(request.getSession(), request);