diff --git a/api/maven-api-settings/pom.xml b/api/maven-api-settings/pom.xml index a73c2ce1de0d..8262c2efde5a 100644 --- a/api/maven-api-settings/pom.xml +++ b/api/maven-api-settings/pom.xml @@ -54,6 +54,9 @@ under the License. org.codehaus.modello modello-maven-plugin + + alias + 2.0.0 ${project.basedir}/../../src/mdo diff --git a/api/maven-api-settings/src/main/mdo/settings.mdo b/api/maven-api-settings/src/main/mdo/settings.mdo index fe69efeeff16..34b83cf86869 100644 --- a/api/maven-api-settings/src/main/mdo/settings.mdo +++ b/api/maven-api-settings/src/main/mdo/settings.mdo @@ -529,6 +529,16 @@ Extra configuration for the transport layer. + + aliases + 1.3.0+ + List of additional server aliases. For each alias, an additional server will be generated by copying the entire configuration, but using a different ID. + This is useful when the same credentials should be used for multiple servers. + + String + * + + diff --git a/compat/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java b/compat/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java index 140393bf0659..3e11798f06ae 100644 --- a/compat/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java +++ b/compat/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java @@ -29,9 +29,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Stream; import org.apache.maven.building.FileSource; import org.apache.maven.building.Source; +import org.apache.maven.settings.Server; import org.apache.maven.settings.Settings; import org.apache.maven.settings.TrackableBase; import org.apache.maven.settings.io.SettingsParseException; @@ -181,6 +183,7 @@ private Settings readSettings( return new Settings(); } + settings.setServers(serversByIds(settings.getServers())); settingsValidator.validate(settings, problems); return settings; @@ -251,4 +254,18 @@ public Object execute(String expression, Object value) { return result; } + + private List serversByIds(List servers) { + return servers.stream() + .flatMap(server -> Stream.concat( + Stream.of(server), server.getAliases().stream().map(id -> serverAlias(server, id)))) + .toList(); + } + + private Server serverAlias(Server server, String id) { + return new Server(org.apache.maven.api.settings.Server.newBuilder(server.getDelegate(), true) + .id(id) + .aliases(List.of()) + .build()); + } } diff --git a/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java b/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java index 2959e4f68243..cd5fc00516ef 100644 --- a/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java +++ b/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java @@ -19,10 +19,16 @@ package org.apache.maven.settings.building; import java.io.File; +import java.util.List; +import java.util.Properties; +import org.apache.maven.api.settings.Server; +import org.apache.maven.settings.Settings; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** */ @@ -32,17 +38,101 @@ private File getSettings(String name) { return new File("src/test/resources/settings/factory/" + name + ".xml").getAbsoluteFile(); } - @Test - void testCompleteWiring() throws Exception { + SettingsBuildingResult execute(String settingsName) throws Exception { + Properties properties = new Properties(); + properties.setProperty("user.home", "/home/user"); + SettingsBuilder builder = new DefaultSettingsBuilderFactory().newInstance(); assertNotNull(builder); DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); - request.setSystemProperties(System.getProperties()); - request.setUserSettingsFile(getSettings("simple")); + request.setSystemProperties(properties); + request.setUserSettingsFile(getSettings(settingsName)); SettingsBuildingResult result = builder.build(request); assertNotNull(result); - assertNotNull(result.getEffectiveSettings()); + return result; + } + + @Test + void testCompleteWiring() throws Exception { + Settings settings = execute("simple").getEffectiveSettings(); + + String localRepository = settings.getLocalRepository(); + assertTrue(localRepository.equals("/home/user/.m2/repository") + || localRepository.endsWith("\\home\\user\\.m2\\repository")); + } + + @Test + void testSettingsWithServers() throws Exception { + Settings settings = execute("settings-servers-1").getEffectiveSettings(); + + List servers = settings.getDelegate().getServers(); + assertEquals(2, servers.size()); + + Server server1 = getServerById(servers, "server-1"); + assertEquals("username1", server1.getUsername()); + assertEquals("password1", server1.getPassword()); + + Server server2 = getServerById(servers, "server-2"); + assertEquals("username2", server2.getUsername()); + assertEquals("password2", server2.getPassword()); + } + + @Test + void testSettingsWithServersAndAliases() throws Exception { + Settings settings = execute("settings-servers-2").getEffectiveSettings(); + + List servers = settings.getDelegate().getServers(); + assertEquals(6, servers.size()); + + Server server1 = getServerById(servers, "server-1"); + assertEquals("username1", server1.getUsername()); + assertEquals("password1", server1.getPassword()); + assertEquals(List.of("server-11", "server-12"), server1.getAliases()); + + Server server11 = getServerById(servers, "server-11"); + assertEquals("username1", server11.getUsername()); + assertEquals("password1", server11.getPassword()); + assertTrue(server11.getAliases().isEmpty()); + + Server server12 = getServerById(servers, "server-12"); + assertEquals("username1", server12.getUsername()); + assertEquals("password1", server12.getPassword()); + assertTrue(server11.getAliases().isEmpty()); + + Server server2 = getServerById(servers, "server-2"); + assertEquals("username2", server2.getUsername()); + assertEquals("password2", server2.getPassword()); + assertEquals(List.of("server-21"), server2.getAliases()); + + Server server21 = getServerById(servers, "server-21"); + assertEquals("username2", server21.getUsername()); + assertEquals("password2", server21.getPassword()); + assertTrue(server21.getAliases().isEmpty()); + + Server server3 = getServerById(servers, "server-3"); + assertEquals("username3", server3.getUsername()); + assertEquals("password3", server3.getPassword()); + assertTrue(server3.getAliases().isEmpty()); + } + + private Server getServerById(List servers, String id) { + return servers.stream() + .filter(s -> s.getId().equals(id)) + .findFirst() + .orElseThrow( + () -> new IllegalStateException("Server with id " + id + " not found on list: " + servers)); + } + + @Test + void testSettingsWithDuplicateServersIds() throws Exception { + SettingsBuildingResult result = execute("settings-servers-3"); + + List problems = result.getProblems(); + assertEquals(1, problems.size()); + assertEquals( + "'servers.server.id' must be unique but found duplicate server with id server-2", + problems.get(0).getMessage()); } } diff --git a/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-1.xml b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-1.xml new file mode 100644 index 000000000000..7076749943b2 --- /dev/null +++ b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-1.xml @@ -0,0 +1,37 @@ + + + + + + ${user.home}/.m2/repository + + + server-1 + username1 + password1 + + + server-2 + username2 + password2 + + + + diff --git a/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-2.xml b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-2.xml new file mode 100644 index 000000000000..a8464a49a302 --- /dev/null +++ b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-2.xml @@ -0,0 +1,49 @@ + + + + + + ${user.home}/.m2/repository + + + server-1 + + server-11 + server-12 + + username1 + password1 + + + server-2 + + server-21 + + username2 + password2 + + + server-3 + username3 + password3 + + + + diff --git a/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-3.xml b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-3.xml new file mode 100644 index 000000000000..e0a13454e2e8 --- /dev/null +++ b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-3.xml @@ -0,0 +1,40 @@ + + + + + + ${user.home}/.m2/repository + + + server-1 + + server-2 + + username1 + password1 + + + server-2 + username2 + password2 + + + + diff --git a/compat/maven-settings/pom.xml b/compat/maven-settings/pom.xml index 6aaa0e4e4246..78119cf62b32 100644 --- a/compat/maven-settings/pom.xml +++ b/compat/maven-settings/pom.xml @@ -75,7 +75,7 @@ under the License. src/main/mdo/settings.mdo - forcedIOModelVersion=1.2.0 + forcedIOModelVersion=1.3.0 packageModelV3=org.apache.maven.settings packageModelV4=org.apache.maven.api.settings packageToolV4=org.apache.maven.settings.v4 diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java index be7dd9e86312..ff4707b0bebe 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java @@ -31,6 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; import java.util.function.UnaryOperator; +import java.util.stream.Stream; import org.apache.maven.api.Constants; import org.apache.maven.api.ProtoSession; @@ -62,7 +63,6 @@ /** * Builds the effective settings from a user settings file and/or a global settings file. - * */ @Named public class DefaultSettingsBuilder implements SettingsBuilder { @@ -203,6 +203,10 @@ private Settings readSettings( settings = interpolate(settings, request, problems); settings = decrypt(settingsSource, settings, request, problems); + if (!isProjectSettings) { + settings = settings.withServers(serversByIds(settings.getServers())); + } + settingsValidator.validate(settings, isProjectSettings, problems); if (isProjectSettings) { @@ -228,6 +232,17 @@ private Settings readSettings( return settings; } + private List serversByIds(List servers) { + return servers.stream() + .flatMap(server -> Stream.concat( + Stream.of(server), server.getAliases().stream().map(id -> serverAlias(server, id)))) + .toList(); + } + + private Server serverAlias(Server server, String id) { + return Server.newBuilder(server, true).id(id).aliases(List.of()).build(); + } + private Settings interpolate( Settings settings, SettingsBuilderRequest request, ProblemCollector problems) { UnaryOperator src; @@ -348,7 +363,6 @@ public org.apache.maven.api.model.Profile convert(Profile profile) { /** * Collects the output of the settings builder. - * */ static class DefaultSettingsBuilderResult implements SettingsBuilderResult { diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultSettingsBuilderFactoryTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultSettingsBuilderFactoryTest.java index 5419b27d6287..a143d41ff9da 100644 --- a/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultSettingsBuilderFactoryTest.java +++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultSettingsBuilderFactoryTest.java @@ -20,14 +20,19 @@ import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import java.util.Map; import org.apache.maven.api.Session; +import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.services.ProblemCollector; import org.apache.maven.api.services.SettingsBuilder; import org.apache.maven.api.services.SettingsBuilderRequest; import org.apache.maven.api.services.SettingsBuilderResult; import org.apache.maven.api.services.Sources; import org.apache.maven.api.services.xml.SettingsXmlFactory; +import org.apache.maven.api.settings.Server; +import org.apache.maven.api.settings.Settings; import org.apache.maven.impl.model.DefaultInterpolator; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,9 +41,12 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** + * */ @ExtendWith(MockitoExtension.class) class DefaultSettingsBuilderFactoryTest { @@ -53,23 +61,106 @@ void setup() { .thenReturn(new DefaultSettingsXmlFactory()); } - @Test - void testCompleteWiring() { + SettingsBuilderResult execute(String settingsName) { SettingsBuilder builder = new DefaultSettingsBuilder(new DefaultSettingsXmlFactory(), new DefaultInterpolator(), Map.of()); assertNotNull(builder); SettingsBuilderRequest request = SettingsBuilderRequest.builder() .session(session) - .userSettingsSource(Sources.buildSource(getSettings("settings-simple"))) + .userSettingsSource(Sources.buildSource(getSettings(settingsName))) .build(); SettingsBuilderResult result = builder.build(request); assertNotNull(result); - assertNotNull(result.getEffectiveSettings()); + return result; + } + + @Test + void testCompleteWiring() { + Settings settings = execute("settings-simple").getEffectiveSettings(); + + String localRepository = settings.getLocalRepository(); + assertTrue(localRepository.equals("${user.home}/.m2/repository") + || localRepository.endsWith("\\${user.home}\\.m2\\repository")); + } + + @Test + void testSettingsWithServers() { + Settings settings = execute("settings-servers-1").getEffectiveSettings(); + + List servers = settings.getServers(); + assertEquals(2, servers.size()); + + Server server1 = getServerById(servers, "server-1"); + assertEquals("username1", server1.getUsername()); + assertEquals("password1", server1.getPassword()); + + Server server2 = getServerById(servers, "server-2"); + assertEquals("username2", server2.getUsername()); + assertEquals("password2", server2.getPassword()); + } + + @Test + void testSettingsWithServersAndAliases() { + Settings settings = execute("settings-servers-2").getEffectiveSettings(); + + assertEquals("${user.home}/.m2/repository", settings.getLocalRepository()); + + List servers = settings.getServers(); + assertEquals(6, servers.size()); + + Server server1 = getServerById(servers, "server-1"); + assertEquals("username1", server1.getUsername()); + assertEquals("password1", server1.getPassword()); + assertEquals(List.of("server-11", "server-12"), server1.getAliases()); + + Server server11 = getServerById(servers, "server-11"); + assertEquals("username1", server11.getUsername()); + assertEquals("password1", server11.getPassword()); + assertTrue(server11.getAliases().isEmpty()); + + Server server12 = getServerById(servers, "server-12"); + assertEquals("username1", server12.getUsername()); + assertEquals("password1", server12.getPassword()); + assertTrue(server11.getAliases().isEmpty()); + + Server server2 = getServerById(servers, "server-2"); + assertEquals("username2", server2.getUsername()); + assertEquals("password2", server2.getPassword()); + assertEquals(List.of("server-21"), server2.getAliases()); + + Server server21 = getServerById(servers, "server-21"); + assertEquals("username2", server21.getUsername()); + assertEquals("password2", server21.getPassword()); + assertTrue(server21.getAliases().isEmpty()); + + Server server3 = getServerById(servers, "server-3"); + assertEquals("username3", server3.getUsername()); + assertEquals("password3", server3.getPassword()); + assertTrue(server3.getAliases().isEmpty()); + } + + private Server getServerById(List servers, String id) { + return servers.stream() + .filter(s -> s.getId().equals(id)) + .findFirst() + .orElseThrow( + () -> new IllegalStateException("Server with id " + id + " not found on list: " + servers)); + } + + @Test + void testSettingsWithDuplicateServersIds() throws Exception { + SettingsBuilderResult result = execute("settings-servers-3"); + + ProblemCollector problems = result.getProblems(); + assertEquals(1, problems.problems().count()); + assertEquals( + "'servers.server.id' must be unique but found duplicate server with id server-2", + problems.problems().findFirst().orElseThrow().getMessage()); } private Path getSettings(String name) { - return Paths.get("src/test/resources/" + name + ".xml").toAbsolutePath(); + return Paths.get("src/test/resources/settings/" + name + ".xml").toAbsolutePath(); } } diff --git a/impl/maven-impl/src/test/resources/settings/settings-servers-1.xml b/impl/maven-impl/src/test/resources/settings/settings-servers-1.xml new file mode 100644 index 000000000000..7076749943b2 --- /dev/null +++ b/impl/maven-impl/src/test/resources/settings/settings-servers-1.xml @@ -0,0 +1,37 @@ + + + + + + ${user.home}/.m2/repository + + + server-1 + username1 + password1 + + + server-2 + username2 + password2 + + + + diff --git a/impl/maven-impl/src/test/resources/settings/settings-servers-2.xml b/impl/maven-impl/src/test/resources/settings/settings-servers-2.xml new file mode 100644 index 000000000000..a8464a49a302 --- /dev/null +++ b/impl/maven-impl/src/test/resources/settings/settings-servers-2.xml @@ -0,0 +1,49 @@ + + + + + + ${user.home}/.m2/repository + + + server-1 + + server-11 + server-12 + + username1 + password1 + + + server-2 + + server-21 + + username2 + password2 + + + server-3 + username3 + password3 + + + + diff --git a/impl/maven-impl/src/test/resources/settings/settings-servers-3.xml b/impl/maven-impl/src/test/resources/settings/settings-servers-3.xml new file mode 100644 index 000000000000..e0a13454e2e8 --- /dev/null +++ b/impl/maven-impl/src/test/resources/settings/settings-servers-3.xml @@ -0,0 +1,40 @@ + + + + + + ${user.home}/.m2/repository + + + server-1 + + server-2 + + username1 + password1 + + + server-2 + username2 + password2 + + + + diff --git a/impl/maven-impl/src/test/resources/settings-simple.xml b/impl/maven-impl/src/test/resources/settings/settings-simple.xml similarity index 100% rename from impl/maven-impl/src/test/resources/settings-simple.xml rename to impl/maven-impl/src/test/resources/settings/settings-simple.xml diff --git a/impl/maven-support/pom.xml b/impl/maven-support/pom.xml index 65f1eb0a7c5a..7171363b74fc 100644 --- a/impl/maven-support/pom.xml +++ b/impl/maven-support/pom.xml @@ -123,6 +123,9 @@ under the License. generate-sources + + alias + 2.0.0 ${project.basedir}/../../api/maven-api-settings ${project.basedir}/../../src/mdo @@ -136,7 +139,7 @@ under the License. - forcedIOModelVersion=1.2.0 + forcedIOModelVersion=1.3.0 packageModelV3=org.apache.maven.settings packageModelV4=org.apache.maven.api.settings packageToolV4=org.apache.maven.settings.v4 diff --git a/pom.xml b/pom.xml index 08260706e3ed..b109514105be 100644 --- a/pom.xml +++ b/pom.xml @@ -745,6 +745,11 @@ under the License. build-helper-maven-plugin 3.6.1 + + org.codehaus.modello + modello-maven-plugin + 2.7.0 + org.apache.maven.plugins maven-deploy-plugin