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

slawekjaranowski 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 09b2dfc915 [MNG-5913] Allow defining aliases for existing server 
configurations in settings.xml (#2333)
09b2dfc915 is described below

commit 09b2dfc9151030e026a993f234c8e9c507c2d198
Author: Slawomir Jaranowski <[email protected]>
AuthorDate: Sun Jul 12 15:17:45 2026 +0200

    [MNG-5913] Allow defining aliases for existing server configurations in 
settings.xml (#2333)
    
    * [MNG-5913] Allow defining aliases for existing server configurations in 
settings.xml
    
    Add the next tag aliases to the server in settings.xml
    
    Additional server will be created in memory by SettingsBuilder,
    so the generated configuration should be transparent to other
    as Settings#getServers() will return complete list.
---
 api/maven-api-settings/pom.xml                     |   3 +
 api/maven-api-settings/src/main/mdo/settings.mdo   |  12 +++
 .../settings/building/DefaultSettingsBuilder.java  |  18 ++++
 .../validation/DefaultSettingsValidator.java       |  17 ++++
 .../DefaultSettingsBuilderFactoryTest.java         | 100 +++++++++++++++++++-
 .../validation/DefaultSettingsValidatorTest.java   |  52 +++++++++++
 .../settings/factory/settings-servers-1.xml        |  15 ++-
 .../settings/factory/settings-servers-2.xml        |  27 +++++-
 .../settings/factory/settings-servers-3.xml        |  18 +++-
 compat/maven-settings/pom.xml                      |   5 +-
 .../apache/maven/impl/DefaultSettingsBuilder.java  |  19 +++-
 .../maven/impl/DefaultSettingsValidator.java       |  20 ++++
 .../impl/DefaultSettingsBuilderFactoryTest.java    | 101 ++++++++++++++++++++-
 .../maven/impl/DefaultSettingsValidatorTest.java   |  47 ++++++++++
 .../settings-servers-1.xml}                        |  15 ++-
 .../settings-servers-2.xml}                        |  27 +++++-
 .../settings-servers-3.xml}                        |  18 +++-
 .../resources/{ => settings}/settings-simple.xml   |   0
 impl/maven-support/pom.xml                         |   5 +-
 pom.xml                                            |   5 +
 20 files changed, 503 insertions(+), 21 deletions(-)

diff --git a/api/maven-api-settings/pom.xml b/api/maven-api-settings/pom.xml
index a73c2ce1de..8262c2efde 100644
--- a/api/maven-api-settings/pom.xml
+++ b/api/maven-api-settings/pom.xml
@@ -54,6 +54,9 @@ under the License.
         <groupId>org.codehaus.modello</groupId>
         <artifactId>modello-maven-plugin</artifactId>
         <configuration>
+          <pluralExceptions>
+            <aliases>alias</aliases>
+          </pluralExceptions>
           <version>2.0.0</version>
           <velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
           <models>
diff --git a/api/maven-api-settings/src/main/mdo/settings.mdo 
b/api/maven-api-settings/src/main/mdo/settings.mdo
index fe69efeeff..0e8803b2d4 100644
--- a/api/maven-api-settings/src/main/mdo/settings.mdo
+++ b/api/maven-api-settings/src/main/mdo/settings.mdo
@@ -529,6 +529,18 @@
             Extra configuration for the transport layer.
           </description>
         </field>
+        <field>
+          <name>aliases</name>
+          <version>1.3.0+</version>
+          <description>List of additional server aliases. For each alias, an 
additional server entry will be generated
+            with the same configuration as the original one, but with the ID 
replaced by the alias
+            and with an empty aliases list.
+            This is useful when the same credentials should be used for 
multiple servers.</description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
       </fields>
     </class>
     <class>
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 140393bf06..48bb04bb4f 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
@@ -26,12 +26,15 @@
 import java.io.IOException;
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.util.ArrayList;
 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;
@@ -182,6 +185,7 @@ private Settings readSettings(
         }
 
         settingsValidator.validate(settings, problems);
+        settings.setServers(new 
ArrayList<>(serversByIds(settings.getServers())));
 
         return settings;
     }
@@ -251,4 +255,18 @@ public Object execute(String expression, Object value) {
 
         return result;
     }
+
+    private List<Server> serversByIds(List<Server> 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/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
 
b/compat/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
index f1913e00de..8e497d6b40 100644
--- 
a/compat/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
+++ 
b/compat/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
@@ -93,6 +93,23 @@ public void validate(Settings settings, 
SettingsProblemCollector problems) {
                             "must be unique but found duplicate server with id 
" + server.getId());
                 }
             }
+
+            for (int i = 0; i < servers.size(); i++) {
+                Server server = servers.get(i);
+                for (int a = 0; a < server.getAliases().size(); a++) {
+                    String alias = server.getAliases().get(a);
+                    validateStringNotEmpty(
+                            problems, "servers.server[" + i + "].aliases[" + a 
+ "]", alias, server.getId());
+                    if (!serverIds.add(alias)) {
+                        addViolation(
+                                problems,
+                                Severity.WARNING,
+                                "servers.server[" + i + "].aliases[" + a + "]",
+                                server.getId(),
+                                "must be unique across all server ids and 
aliases but found duplicate alias " + alias);
+                    }
+                }
+            }
         }
 
         List<Mirror> mirrors = settings.getMirrors();
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 2959e4f682..84c74feb0f 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<Server> 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<Server> 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(server12.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<Server> 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<SettingsProblem> problems = result.getProblems();
+        assertEquals(1, problems.size());
+        assertEquals(
+                "'servers.server[0].aliases[0]' for server-1 must be unique 
across all server ids and aliases but found duplicate alias server-2",
+                problems.get(0).getMessage());
     }
 }
diff --git 
a/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java
 
b/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java
index d2f95b21da..4bec76a359 100644
--- 
a/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java
+++ 
b/compat/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java
@@ -219,6 +219,58 @@ void testValidateProxy() throws Exception {
         assertContains(problems.messages.get(0), "'proxies.proxy.host' for 
default is missing");
     }
 
+    @Test
+    void testValidateServerIdAlias() {
+        Settings settings = new Settings();
+        Server server = new Server();
+        server.setId("server-1");
+        server.addAlias("server-1");
+        settings.addServer(server);
+
+        SimpleProblemCollector problems = new SimpleProblemCollector();
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(
+                problems.messages.get(0),
+                "'servers.server[0].aliases[0]' for server-1 must be unique 
across all server ids and aliases but found duplicate alias server-1");
+    }
+
+    @Test
+    void testMultipleUsageOfAliases() {
+        Settings settings = new Settings();
+
+        Server server1 = new Server();
+        server1.setId("server-1");
+        server1.addAlias("alias-1");
+        settings.addServer(server1);
+
+        Server server2 = new Server();
+        server2.setId("server-2");
+        server2.addAlias("alias-1");
+        settings.addServer(server2);
+
+        SimpleProblemCollector problems = new SimpleProblemCollector();
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(
+                problems.messages.get(0),
+                "'servers.server[1].aliases[0]' for server-2 must be unique 
across all server ids and aliases but found duplicate alias alias-1");
+    }
+
+    @Test
+    void testValidateServerIdAliasesWithEmptyValue() {
+        Settings settings = new Settings();
+        Server server = new Server();
+        server.setId("server-1");
+        server.addAlias("");
+        settings.addServer(server);
+
+        SimpleProblemCollector problems = new SimpleProblemCollector();
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(problems.messages.get(0), 
"'servers.server[0].aliases[0]' for server-1 is missing");
+    }
+
     private static class SimpleProblemCollector implements 
SettingsProblemCollector {
 
         List<String> messages = new ArrayList<>();
diff --git a/impl/maven-impl/src/test/resources/settings-simple.xml 
b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-1.xml
similarity index 75%
copy from impl/maven-impl/src/test/resources/settings-simple.xml
copy to 
compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-1.xml
index abcda726c7..7076749943 100644
--- a/impl/maven-impl/src/test/resources/settings-simple.xml
+++ 
b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-1.xml
@@ -19,6 +19,19 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<settings xmlns='http://maven.apache.org/SETTINGS/1.0.0'>
+<settings>
   <localRepository>${user.home}/.m2/repository</localRepository>
+  <servers>
+    <server>
+      <id>server-1</id>
+      <username>username1</username>
+      <password>password1</password>
+    </server>
+    <server>
+      <id>server-2</id>
+      <username>username2</username>
+      <password>password2</password>
+    </server>
+  </servers>
+
 </settings>
diff --git a/impl/maven-impl/src/test/resources/settings-simple.xml 
b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-2.xml
similarity index 60%
copy from impl/maven-impl/src/test/resources/settings-simple.xml
copy to 
compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-2.xml
index abcda726c7..a8464a49a3 100644
--- a/impl/maven-impl/src/test/resources/settings-simple.xml
+++ 
b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-2.xml
@@ -19,6 +19,31 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<settings xmlns='http://maven.apache.org/SETTINGS/1.0.0'>
+<settings>
   <localRepository>${user.home}/.m2/repository</localRepository>
+  <servers>
+    <server>
+      <id>server-1</id>
+      <aliases>
+        <alias>server-11</alias>
+        <alias>server-12</alias>
+      </aliases>
+      <username>username1</username>
+      <password>password1</password>
+    </server>
+    <server>
+      <id>server-2</id>
+      <aliases>
+        <alias>server-21</alias>
+      </aliases>
+      <username>username2</username>
+      <password>password2</password>
+    </server>
+    <server>
+      <id>server-3</id>
+      <username>username3</username>
+      <password>password3</password>
+    </server>
+  </servers>
+
 </settings>
diff --git a/impl/maven-impl/src/test/resources/settings-simple.xml 
b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-3.xml
similarity index 71%
copy from impl/maven-impl/src/test/resources/settings-simple.xml
copy to 
compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-3.xml
index abcda726c7..e0a13454e2 100644
--- a/impl/maven-impl/src/test/resources/settings-simple.xml
+++ 
b/compat/maven-settings-builder/src/test/resources/settings/factory/settings-servers-3.xml
@@ -19,6 +19,22 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<settings xmlns='http://maven.apache.org/SETTINGS/1.0.0'>
+<settings>
   <localRepository>${user.home}/.m2/repository</localRepository>
+  <servers>
+    <server>
+      <id>server-1</id>
+      <aliases>
+        <alias>server-2</alias>
+      </aliases>
+      <username>username1</username>
+      <password>password1</password>
+    </server>
+    <server>
+      <id>server-2</id>
+      <username>username2</username>
+      <password>password2</password>
+    </server>
+  </servers>
+
 </settings>
diff --git a/compat/maven-settings/pom.xml b/compat/maven-settings/pom.xml
index 6aaa0e4e42..b057a9d8f6 100644
--- a/compat/maven-settings/pom.xml
+++ b/compat/maven-settings/pom.xml
@@ -68,6 +68,9 @@ under the License.
         <groupId>org.codehaus.modello</groupId>
         <artifactId>modello-maven-plugin</artifactId>
         <configuration>
+          <pluralExceptions>
+            <aliases>alias</aliases>
+          </pluralExceptions>
           <version>2.0.0</version>
           <basedir>${project.basedir}/../../api/maven-api-settings</basedir>
           <velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
@@ -75,7 +78,7 @@ under the License.
             <model>src/main/mdo/settings.mdo</model>
           </models>
           <params>
-            <param>forcedIOModelVersion=1.2.0</param>
+            <param>forcedIOModelVersion=1.3.0</param>
             <param>packageModelV3=org.apache.maven.settings</param>
             <param>packageModelV4=org.apache.maven.api.settings</param>
             <param>packageToolV4=org.apache.maven.settings.v4</param>
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 be7dd9e863..b5014498bf 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 {
@@ -205,7 +205,9 @@ private Settings readSettings(
 
         settingsValidator.validate(settings, isProjectSettings, problems);
 
-        if (isProjectSettings) {
+        if (!isProjectSettings) {
+            settings = 
settings.withServers(serversByIds(settings.getServers()));
+        } else {
             settings = Settings.newBuilder(settings, true)
                     .localRepository(null)
                     .interactiveMode(false)
@@ -220,6 +222,7 @@ private Settings readSettings(
                                     .password(null)
                                     .filePermissions(null)
                                     .directoryPermissions(null)
+                                    .aliases(List.of())
                                     .build())
                             .toList())
                     .build();
@@ -228,6 +231,17 @@ private Settings readSettings(
         return settings;
     }
 
+    private List<Server> serversByIds(List<Server> 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<BuilderProblem> problems) {
         UnaryOperator<String> src;
@@ -348,7 +362,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/main/java/org/apache/maven/impl/DefaultSettingsValidator.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsValidator.java
index b2df07a6e2..5e960b1522 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsValidator.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsValidator.java
@@ -73,6 +73,9 @@ public void validate(Settings settings, boolean 
isProjectSettings, ProblemCollec
                 validateStringEmpty(problems, serverField + 
".filePermissions", server.getFilePermissions(), msgS);
                 validateStringEmpty(
                         problems, serverField + ".directoryPermissions", 
server.getDirectoryPermissions(), msgS);
+                if (!server.getAliases().isEmpty()) {
+                    addViolation(problems, BuilderProblem.Severity.WARNING, 
serverField + ".aliases", null, msgP);
+                }
             }
         }
 
@@ -123,6 +126,23 @@ public void validate(Settings settings, boolean 
isProjectSettings, ProblemCollec
                             "must be unique but found duplicate server with id 
" + server.getId());
                 }
             }
+
+            for (int i = 0; i < servers.size(); i++) {
+                Server server = servers.get(i);
+                for (int a = 0; a < server.getAliases().size(); a++) {
+                    String alias = server.getAliases().get(a);
+                    validateStringNotEmpty(
+                            problems, "servers.server[" + i + "].aliases[" + a 
+ "]", alias, server.getId());
+                    if (!serverIds.add(alias)) {
+                        addViolation(
+                                problems,
+                                BuilderProblem.Severity.WARNING,
+                                "servers.server[" + i + "].aliases[" + a + "]",
+                                server.getId(),
+                                "must be unique across all server ids and 
aliases but found duplicate alias " + alias);
+                    }
+                }
+            }
         }
 
         List<Mirror> mirrors = settings.getMirrors();
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 5419b27d62..f76b9067be 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<Server> 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<Server> 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(server12.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<Server> 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<BuilderProblem> problems = result.getProblems();
+        assertEquals(1, problems.problems().count());
+        assertEquals(
+                "'servers.server[0].aliases[0]' for server-1 must be unique 
across all server ids and aliases but found duplicate alias 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/java/org/apache/maven/impl/DefaultSettingsValidatorTest.java
 
b/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultSettingsValidatorTest.java
index f604fe6bb3..46ae074de0 100644
--- 
a/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultSettingsValidatorTest.java
+++ 
b/impl/maven-impl/src/test/java/org/apache/maven/impl/DefaultSettingsValidatorTest.java
@@ -26,6 +26,7 @@
 import org.apache.maven.api.services.SettingsBuilder;
 import org.apache.maven.api.settings.Profile;
 import org.apache.maven.api.settings.Repository;
+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;
@@ -70,4 +71,50 @@ void testValidate() {
         problems = validator.validate(model2);
         assertEquals(0, problems.totalProblemsReported());
     }
+
+    @Test
+    void testValidateServerIdAlias() {
+        Server server =
+                
Server.newBuilder().id("server-1").aliases(List.of("server-1")).build();
+
+        Settings settings = 
Settings.newBuilder().servers(List.of(server)).build();
+
+        ProblemCollector<BuilderProblem> problems = 
validator.validate(settings);
+        assertEquals(1, problems.totalProblemsReported());
+        assertEquals(
+                "'servers.server[0].aliases[0]' for server-1 must be unique 
across all server ids and aliases but found duplicate alias server-1",
+                problems.problems().findFirst().orElseThrow().getMessage());
+    }
+
+    @Test
+    void testMultipleUsageOfAliases() {
+
+        Server server1 =
+                
Server.newBuilder().id("server-1").aliases(List.of("alias-1")).build();
+
+        Server server2 =
+                
Server.newBuilder().id("server-2").aliases(List.of("alias-1")).build();
+
+        Settings settings =
+                Settings.newBuilder().servers(List.of(server1, 
server2)).build();
+
+        ProblemCollector<BuilderProblem> problems = 
validator.validate(settings);
+        assertEquals(1, problems.totalProblemsReported());
+        assertEquals(
+                "'servers.server[1].aliases[0]' for server-2 must be unique 
across all server ids and aliases but found duplicate alias alias-1",
+                problems.problems().findFirst().orElseThrow().getMessage());
+    }
+
+    @Test
+    void testValidateServerIdAliasesWithEmptyValue() {
+        Server server = 
Server.newBuilder().id("server-1").aliases(List.of("")).build();
+
+        Settings settings = 
Settings.newBuilder().servers(List.of(server)).build();
+
+        ProblemCollector<BuilderProblem> problems = 
validator.validate(settings);
+        assertEquals(1, problems.totalProblemsReported());
+        assertEquals(
+                "'servers.server[0].aliases[0]' for server-1 is missing",
+                problems.problems().findFirst().orElseThrow().getMessage());
+    }
 }
diff --git a/impl/maven-impl/src/test/resources/settings-simple.xml 
b/impl/maven-impl/src/test/resources/settings/settings-servers-1.xml
similarity index 75%
copy from impl/maven-impl/src/test/resources/settings-simple.xml
copy to impl/maven-impl/src/test/resources/settings/settings-servers-1.xml
index abcda726c7..7076749943 100644
--- a/impl/maven-impl/src/test/resources/settings-simple.xml
+++ b/impl/maven-impl/src/test/resources/settings/settings-servers-1.xml
@@ -19,6 +19,19 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<settings xmlns='http://maven.apache.org/SETTINGS/1.0.0'>
+<settings>
   <localRepository>${user.home}/.m2/repository</localRepository>
+  <servers>
+    <server>
+      <id>server-1</id>
+      <username>username1</username>
+      <password>password1</password>
+    </server>
+    <server>
+      <id>server-2</id>
+      <username>username2</username>
+      <password>password2</password>
+    </server>
+  </servers>
+
 </settings>
diff --git a/impl/maven-impl/src/test/resources/settings-simple.xml 
b/impl/maven-impl/src/test/resources/settings/settings-servers-2.xml
similarity index 60%
copy from impl/maven-impl/src/test/resources/settings-simple.xml
copy to impl/maven-impl/src/test/resources/settings/settings-servers-2.xml
index abcda726c7..a8464a49a3 100644
--- a/impl/maven-impl/src/test/resources/settings-simple.xml
+++ b/impl/maven-impl/src/test/resources/settings/settings-servers-2.xml
@@ -19,6 +19,31 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<settings xmlns='http://maven.apache.org/SETTINGS/1.0.0'>
+<settings>
   <localRepository>${user.home}/.m2/repository</localRepository>
+  <servers>
+    <server>
+      <id>server-1</id>
+      <aliases>
+        <alias>server-11</alias>
+        <alias>server-12</alias>
+      </aliases>
+      <username>username1</username>
+      <password>password1</password>
+    </server>
+    <server>
+      <id>server-2</id>
+      <aliases>
+        <alias>server-21</alias>
+      </aliases>
+      <username>username2</username>
+      <password>password2</password>
+    </server>
+    <server>
+      <id>server-3</id>
+      <username>username3</username>
+      <password>password3</password>
+    </server>
+  </servers>
+
 </settings>
diff --git a/impl/maven-impl/src/test/resources/settings-simple.xml 
b/impl/maven-impl/src/test/resources/settings/settings-servers-3.xml
similarity index 71%
copy from impl/maven-impl/src/test/resources/settings-simple.xml
copy to impl/maven-impl/src/test/resources/settings/settings-servers-3.xml
index abcda726c7..e0a13454e2 100644
--- a/impl/maven-impl/src/test/resources/settings-simple.xml
+++ b/impl/maven-impl/src/test/resources/settings/settings-servers-3.xml
@@ -19,6 +19,22 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<settings xmlns='http://maven.apache.org/SETTINGS/1.0.0'>
+<settings>
   <localRepository>${user.home}/.m2/repository</localRepository>
+  <servers>
+    <server>
+      <id>server-1</id>
+      <aliases>
+        <alias>server-2</alias>
+      </aliases>
+      <username>username1</username>
+      <password>password1</password>
+    </server>
+    <server>
+      <id>server-2</id>
+      <username>username2</username>
+      <password>password2</password>
+    </server>
+  </servers>
+
 </settings>
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 65f1eb0a7c..7171363b74 100644
--- a/impl/maven-support/pom.xml
+++ b/impl/maven-support/pom.xml
@@ -123,6 +123,9 @@ under the License.
             </goals>
             <phase>generate-sources</phase>
             <configuration>
+              <pluralExceptions>
+                <aliases>alias</aliases>
+              </pluralExceptions>
               <version>2.0.0</version>
               
<basedir>${project.basedir}/../../api/maven-api-settings</basedir>
               
<velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
@@ -136,7 +139,7 @@ under the License.
                 <template>writer-stax.vm</template>
               </templates>
               <params>
-                <param>forcedIOModelVersion=1.2.0</param>
+                <param>forcedIOModelVersion=1.3.0</param>
                 <param>packageModelV3=org.apache.maven.settings</param>
                 <param>packageModelV4=org.apache.maven.api.settings</param>
                 <param>packageToolV4=org.apache.maven.settings.v4</param>
diff --git a/pom.xml b/pom.xml
index 5063841c02..989e3606a7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -750,6 +750,11 @@ under the License.
           <artifactId>build-helper-maven-plugin</artifactId>
           <version>3.6.1</version>
         </plugin>
+        <plugin>
+          <groupId>org.codehaus.modello</groupId>
+          <artifactId>modello-maven-plugin</artifactId>
+          <version>2.7.0</version>
+        </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-deploy-plugin</artifactId>


Reply via email to