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 298dc260727d..e918edf2a49f 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 @@ -69,7 +69,6 @@ import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Parent; import org.apache.maven.api.model.Profile; -import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.BuilderProblem.Severity; import org.apache.maven.api.services.Interpolator; @@ -498,9 +497,21 @@ public ModelBuilderException newModelBuilderException() { return new ModelBuilderException(result); } - public void mergeRepositories(List toAdd, boolean replace) { - List repos = - toAdd.stream().map(session::createRemoteRepository).toList(); + public void mergeRepositories(Model model, boolean replace) { + if (model.getRepositories().isEmpty()) { + return; + } + // We need to interpolate the repositories before we can use them + Model interpolatedModel = interpolateModel( + Model.newBuilder() + .pomFile(model.getPomFile()) + .repositories(model.getRepositories()) + .build(), + request, + this); + List repos = interpolatedModel.getRepositories().stream() + .map(session::createRemoteRepository) + .toList(); if (replace) { Set ids = repos.stream().map(RemoteRepository::getId).collect(Collectors.toSet()); repositories = repositories.stream() @@ -1016,7 +1027,7 @@ Model resolveAndReadParentExternally(Model childModel, DefaultProfileActivationC // add repositories specified by the current model so that we can resolve the parent if (!childModel.getRepositories().isEmpty()) { var previousRepositories = repositories; - mergeRepositories(childModel.getRepositories(), false); + mergeRepositories(childModel, false); if (!Objects.equals(previousRepositories, repositories)) { if (logger.isDebugEnabled()) { logger.debug("Merging repositories from " + childModel.getId() + "\n" @@ -1196,7 +1207,7 @@ private Model readEffectiveModel() throws ModelBuilderException { if (!resultModel.getRepositories().isEmpty()) { List oldRepos = repositories.stream().map(Object::toString).toList(); - mergeRepositories(resultModel.getRepositories(), true); + mergeRepositories(resultModel, true); List newRepos = repositories.stream().map(Object::toString).toList(); if (!Objects.equals(oldRepos, newRepos)) { 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 c0a04a92dfc3..2b012185c4bf 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 @@ -18,10 +18,17 @@ */ package org.apache.maven.impl.model; +import java.lang.reflect.Field; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; +import org.apache.maven.api.model.Model; +import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.ModelBuilder; import org.apache.maven.api.services.ModelBuilderRequest; import org.apache.maven.api.services.ModelBuilderResult; @@ -60,6 +67,53 @@ public void testPropertiesAndProfiles() { assertEquals("21", result.getEffectiveModel().getProperties().get("maven.compiler.release")); } + @Test + public void testMergeRepositories() throws Exception { + // this is here only to trigger mainSession creation; unrelated + ModelBuilderRequest request = ModelBuilderRequest.builder() + .session(session) + .userProperties(Map.of("firstParentRepo", "https://some.repo")) + .requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT) + .source(Sources.buildSource(getPom("props-and-profiles"))) + .build(); + ModelBuilder.ModelBuilderSession session = builder.newSession(); + session.build(request); // ignored result value; just to trigger mainSession creation + + Field mainSessionField = DefaultModelBuilder.ModelBuilderSessionImpl.class.getDeclaredField("mainSession"); + mainSessionField.setAccessible(true); + DefaultModelBuilder.ModelBuilderSessionState state = + (DefaultModelBuilder.ModelBuilderSessionState) mainSessionField.get(session); + Field repositoriesField = DefaultModelBuilder.ModelBuilderSessionState.class.getDeclaredField("repositories"); + repositoriesField.setAccessible(true); + + List repositories; + // before merge + repositories = (List) repositoriesField.get(state); + assertEquals(1, repositories.size()); // central + + Model model = Model.newBuilder() + .repositories(Arrays.asList( + Repository.newBuilder() + .id("first") + .url("${firstParentRepo}") + .build(), + Repository.newBuilder() + .id("second") + .url("${secondParentRepo}") + .build())) + .build(); + state.mergeRepositories(model, false); + + // after merge + repositories = (List) repositoriesField.get(state); + assertEquals(3, repositories.size()); + assertEquals("first", repositories.get(0).getId()); + assertEquals("https://some.repo", repositories.get(0).getUrl()); // interpolated + assertEquals("second", repositories.get(1).getId()); + assertEquals("${secondParentRepo}", repositories.get(1).getUrl()); // un-interpolated (no source) + assertEquals("central", repositories.get(2).getId()); // default + } + private Path getPom(String name) { return Paths.get("src/test/resources/poms/factory/" + name + ".xml").toAbsolutePath(); }