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 182d0f1ae811..7de27dfe567d 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 @@ -611,28 +611,59 @@ public void mergeRepositories(Model model, boolean replace) { // Infer inner reactor dependencies version // Model transformFileToRaw(Model model) { - if (model.getDependencies().isEmpty()) { + List newDeps = null; + boolean depsChanged = false; + if (!model.getDependencies().isEmpty()) { + newDeps = new ArrayList<>(model.getDependencies().size()); + depsChanged = inferDependencies(model, model.getDependencies(), newDeps); + } + + DependencyManagement depMgmt = model.getDependencyManagement(); + List newManagedDeps = null; + boolean managedDepsChanged = false; + if (depMgmt != null && !depMgmt.getDependencies().isEmpty()) { + newManagedDeps = new ArrayList<>(depMgmt.getDependencies().size()); + managedDepsChanged = inferDependencies(model, depMgmt.getDependencies(), newManagedDeps); + } + + if (!depsChanged && !managedDepsChanged) { return model; } - List newDeps = new ArrayList<>(model.getDependencies().size()); + Model.Builder builder = Model.newBuilder(model); + if (depsChanged) { + builder.dependencies(newDeps); + } + if (managedDepsChanged) { + builder.dependencyManagement(depMgmt.withDependencies(newManagedDeps)); + } + return builder.build(); + } + + /** + * Infers the missing version or groupId of the given dependencies by looking them up in the reactor. + * Each dependency, either the original one or the inferred one, is added to {@code result}. + * + * @param model the model declaring the dependencies + * @param dependencies the dependencies to process + * @param result the list collecting the resulting dependencies + * @return whether at least one dependency has been inferred + */ + private boolean inferDependencies(Model model, List dependencies, List result) { boolean changed = false; - for (Dependency dep : model.getDependencies()) { + for (Dependency dep : dependencies) { Dependency newDep = null; if (dep.getVersion() == null) { newDep = inferDependencyVersion(model, dep); - if (newDep != null) { - changed = true; - } } else if (dep.getGroupId() == null) { // Handle missing groupId when version is present newDep = inferDependencyGroupId(model, dep); - if (newDep != null) { - changed = true; - } } - newDeps.add(newDep == null ? dep : newDep); + if (newDep != null) { + changed = true; + } + result.add(newDep == null ? dep : newDep); } - return changed ? model.withDependencies(newDeps) : model; + return changed; } private Dependency inferDependencyVersion(Model model, Dependency dep) { diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java index 0789ca89fa90..f013d4c22429 100644 --- a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java +++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java @@ -28,6 +28,7 @@ import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; import org.apache.maven.api.model.Dependency; +import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.ModelBuilder; @@ -444,6 +445,53 @@ public void testBuildConsumerResolvesParentProfileProperties() { "Managed dependency version should be interpolated, not ${managed.version}"); } + /** + * Verifies that the versions of sibling reactor modules declared in {@code } + * are inferred, just like they already are for regular dependencies (GH-11147). + * This is the typical BOM use case where a subproject lists its siblings without their versions. + */ + @Test + public void testBomDependencyManagementVersionInference() { + // Build the lib POM first: this creates the main session and registers the sibling module + ModelBuilder.ModelBuilderSession mbs = builder.newSession(); + mbs.build(ModelBuilderRequest.builder() + .session(session) + .requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT) + .source(Sources.buildSource(getPom("bom-dep-mgmt-lib"))) + .build()); + + // Access the main session (package-private) to invoke the file to raw model transformation + DefaultModelBuilder.ModelBuilderSessionState mainState = + ((DefaultModelBuilder.ModelBuilderSessionImpl) mbs).mainSession; + + // A BOM declaring a sibling module in dependencyManagement, without a version + Model bomModel = Model.newBuilder() + .modelVersion("4.1.0") + .groupId("org.apache.maven.tests") + .artifactId("bom-dep-mgmt-bom") + .version("1.0-SNAPSHOT") + .packaging("pom") + .pomFile(getPom("bom-dep-mgmt-bom")) + .dependencyManagement(DependencyManagement.newBuilder() + .dependencies(List.of(Dependency.newBuilder() + .groupId("org.apache.maven.tests") + .artifactId("bom-dep-mgmt-lib") + .build())) + .build()) + .build(); + + Model transformed = mainState.transformFileToRaw(bomModel); + + assertNotNull(transformed.getDependencyManagement()); + Dependency managedDep = transformed.getDependencyManagement().getDependencies().stream() + .filter(d -> "bom-dep-mgmt-lib".equals(d.getArtifactId())) + .findFirst() + .orElse(null); + assertNotNull(managedDep, "Managed dependency for the sibling module should be kept"); + assertEquals( + "1.0-SNAPSHOT", managedDep.getVersion(), "Version should be inferred from the reactor sibling module"); + } + private Path getPom(String name) { return Paths.get("src/test/resources/poms/factory/" + name + ".xml").toAbsolutePath(); } diff --git a/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-bom.xml b/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-bom.xml new file mode 100644 index 000000000000..8d90fef50283 --- /dev/null +++ b/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-bom.xml @@ -0,0 +1,36 @@ + + + + + org.apache.maven.tests + bom-dep-mgmt-parent + bom-dep-mgmt-parent.xml + + bom-dep-mgmt-bom + pom + + + + + org.apache.maven.tests + bom-dep-mgmt-lib + + + + + diff --git a/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-lib.xml b/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-lib.xml new file mode 100644 index 000000000000..6034f67bd422 --- /dev/null +++ b/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-lib.xml @@ -0,0 +1,25 @@ + + + + + org.apache.maven.tests + bom-dep-mgmt-parent + bom-dep-mgmt-parent.xml + + bom-dep-mgmt-lib + diff --git a/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-parent.xml b/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-parent.xml new file mode 100644 index 000000000000..2fb8117371a7 --- /dev/null +++ b/impl/maven-impl/src/test/resources/poms/factory/bom-dep-mgmt-parent.xml @@ -0,0 +1,23 @@ + + + + org.apache.maven.tests + bom-dep-mgmt-parent + 1.0-SNAPSHOT + pom +