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 5d449f9a24 [MNG-8244] Using before:all / all / after:all is not 
triggered (#1973)
5d449f9a24 is described below

commit 5d449f9a247742dc0bdf89cab0fbe6d8623881ee
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Sat Dec 14 00:04:37 2024 +0100

    [MNG-8244] Using before:all / all / after:all is not triggered (#1973)
---
 .../main/java/org/apache/maven/api/Lifecycle.java  |  21 ++--
 .../internal/impl/DefaultLifecycleRegistry.java    | 107 ++++++++----------
 .../java/org/apache/maven/lifecycle/Lifecycle.java |   8 +-
 .../DefaultLifecycleExecutionPlanCalculator.java   |   8 +-
 .../internal/DefaultLifecycleMappingDelegate.java  |  23 ++--
 .../maven/lifecycle/internal/PhaseComparator.java  |  11 +-
 .../internal/concurrent/BuildPlanExecutor.java     |  11 +-
 .../maven/lifecycle/LifecycleExecutorTest.java     | 124 +++++++++------------
 .../maven/it/MavenITmng8244PhaseAllTest.java       |  65 +++++++++++
 .../org/apache/maven/it/TestSuiteOrdering.java     |   1 +
 .../src/test/resources/mng-8244-phase-all/pom.xml  | 117 +++++++++++++++++++
 11 files changed, 326 insertions(+), 170 deletions(-)

diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/Lifecycle.java 
b/api/maven-api-core/src/main/java/org/apache/maven/api/Lifecycle.java
index 9fdabb2854..de7fe1ff90 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/Lifecycle.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Lifecycle.java
@@ -20,7 +20,6 @@ package org.apache.maven.api;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Optional;
 import java.util.stream.Stream;
 
 import org.apache.maven.api.annotations.Experimental;
@@ -66,10 +65,19 @@ public interface Lifecycle extends ExtensibleEnum {
     String id();
 
     /**
-     * Collection of phases for this lifecycle
+     * Collection of main phases for this lifecycle
      */
     Collection<Phase> phases();
 
+    /**
+     * Collection of main phases for this lifecycle used with the Maven 3 
builders.
+     * Those builders does not operate on a graph, but on the list and expect 
a slightly
+     * different ordering (mainly unit test being executed before packaging).
+     */
+    default Collection<Phase> v3phases() {
+        return phases();
+    }
+
     /**
      * Stream of phases containing all child phases recursively.
      */
@@ -82,14 +90,6 @@ public interface Lifecycle extends ExtensibleEnum {
      */
     Collection<Alias> aliases();
 
-    /**
-     * Pre-ordered list of phases.
-     * If not provided, a default order will be computed.
-     */
-    default Optional<List<String>> orderedPhases() {
-        return Optional.empty();
-    }
-
     /**
      * A phase in the lifecycle.
      *
@@ -101,6 +101,7 @@ public interface Lifecycle extends ExtensibleEnum {
         // ======================
         // Maven defined phases
         // ======================
+        String ALL = "all";
         String BUILD = "build";
         String INITIALIZE = "initialize";
         String VALIDATE = "validate";
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java
 
b/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java
index d5d474611e..d72ee709e1 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java
@@ -24,7 +24,6 @@ import javax.inject.Provider;
 import javax.inject.Singleton;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -50,6 +49,9 @@ import org.apache.maven.lifecycle.mapping.LifecyclePhase;
 import org.codehaus.plexus.PlexusContainer;
 import 
org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 
+import static org.apache.maven.api.Lifecycle.AFTER;
+import static org.apache.maven.api.Lifecycle.BEFORE;
+import static org.apache.maven.api.Lifecycle.Phase.ALL;
 import static org.apache.maven.api.Lifecycle.Phase.BUILD;
 import static org.apache.maven.api.Lifecycle.Phase.COMPILE;
 import static org.apache.maven.api.Lifecycle.Phase.DEPLOY;
@@ -129,34 +131,20 @@ public class DefaultLifecycleRegistry implements 
LifecycleRegistry {
 
     public List<String> computePhases(Lifecycle lifecycle) {
         Graph graph = new Graph();
-        lifecycle.phases().forEach(phase -> addPhase(graph, null, null, 
phase));
+        addPhases(graph, null, null, lifecycle.v3phases());
         List<String> allPhases = graph.visitAll();
         Collections.reverse(allPhases);
         List<String> computed =
                 allPhases.stream().filter(s -> 
!s.startsWith("$")).collect(Collectors.toList());
-        List<String> given = lifecycle.orderedPhases().orElse(null);
-        if (given != null) {
-            if (given.size() != computed.size()) {
-                Set<String> s1 =
-                        given.stream().filter(s -> 
!computed.contains(s)).collect(Collectors.toSet());
-                Set<String> s2 =
-                        computed.stream().filter(s -> 
!given.contains(s)).collect(Collectors.toSet());
-                throw new IllegalStateException(
-                        "List of phases differ in size: expected " + 
computed.size() + ", but received " + given.size()
-                                + (s1.isEmpty() ? "" : ", missing " + s1)
-                                + (s2.isEmpty() ? "" : ", unexpected " + s2));
-            }
-            return given;
-        }
         return computed;
     }
 
     private static void addPhase(
             Graph graph, Graph.Vertex before, Graph.Vertex after, 
org.apache.maven.api.Lifecycle.Phase phase) {
-        Graph.Vertex ep0 = graph.addVertex("$" + phase.name());
+        Graph.Vertex ep0 = graph.addVertex(BEFORE + phase.name());
         Graph.Vertex ep1 = graph.addVertex("$$" + phase.name());
         Graph.Vertex ep2 = graph.addVertex(phase.name());
-        Graph.Vertex ep3 = graph.addVertex("$$$" + phase.name());
+        Graph.Vertex ep3 = graph.addVertex(AFTER + phase.name());
         graph.addEdge(ep0, ep1);
         graph.addEdge(ep1, ep2);
         graph.addEdge(ep2, ep3);
@@ -171,11 +159,28 @@ public class DefaultLifecycleRegistry implements 
LifecycleRegistry {
                 if (link.kind() == Lifecycle.Link.Kind.AFTER) {
                     graph.addEdge(graph.addVertex(link.pointer().phase()), 
ep0);
                 } else {
-                    graph.addEdge(ep3, graph.addVertex("$" + 
link.pointer().phase()));
+                    graph.addEdge(ep3, graph.addVertex(BEFORE + 
link.pointer().phase()));
                 }
             }
         });
-        phase.phases().forEach(child -> addPhase(graph, ep1, ep2, child));
+        addPhases(graph, ep1, ep2, phase.phases());
+    }
+
+    private static void addPhases(
+            Graph graph, Graph.Vertex before, Graph.Vertex after, 
Collection<Lifecycle.Phase> phases) {
+        // We add ordering between internal phases.
+        // This would be wrong at execution time, but we are here computing a 
list and not a graph,
+        // so in order to obtain the expected order, we add these links 
between phases.
+        Lifecycle.Phase prev = null;
+        for (Lifecycle.Phase child : phases) {
+            // add phase
+            addPhase(graph, before, after, child);
+            if (prev != null) {
+                // add link between end of previous phase and beginning of 
this one
+                graph.addEdge(graph.addVertex(AFTER + prev.name()), 
graph.addVertex(BEFORE + child.name()));
+            }
+            prev = child;
+        }
     }
 
     @Named
@@ -375,8 +380,8 @@ public class DefaultLifecycleRegistry implements 
LifecycleRegistry {
         @Override
         public Collection<Phase> phases() {
             return List.of(phase(
-                    "all",
-                    phase(INITIALIZE, phase(VALIDATE)),
+                    ALL,
+                    phase(VALIDATE, phase(INITIALIZE)),
                     phase(
                             BUILD,
                             after(VALIDATE),
@@ -407,6 +412,28 @@ public class DefaultLifecycleRegistry implements 
LifecycleRegistry {
                     phase(DEPLOY, after(PACKAGE))));
         }
 
+        @Override
+        public Collection<Phase> v3phases() {
+            return List.of(phase(
+                    ALL,
+                    phase(INITIALIZE, phase(VALIDATE)),
+                    phase(
+                            BUILD,
+                            phase(SOURCES),
+                            phase(RESOURCES),
+                            phase(COMPILE),
+                            phase(READY),
+                            phase(TEST_SOURCES),
+                            phase(TEST_RESOURCES),
+                            phase(TEST_COMPILE),
+                            phase(TEST),
+                            phase(UNIT_TEST),
+                            phase(PACKAGE)),
+                    phase(VERIFY, phase(INTEGRATION_TEST)),
+                    phase(INSTALL),
+                    phase(DEPLOY)));
+        }
+
         @Override
         public Collection<Alias> aliases() {
             return List.of(
@@ -424,42 +451,6 @@ public class DefaultLifecycleRegistry implements 
LifecycleRegistry {
                     alias("pre-integration-test", BEFORE + INTEGRATION_TEST),
                     alias("post-integration-test", AFTER + INTEGRATION_TEST));
         }
-
-        @Override
-        public Optional<List<String>> orderedPhases() {
-            return Optional.of(Arrays.asList(
-                    VALIDATE,
-                    INITIALIZE,
-                    // "generate-sources",
-                    SOURCES,
-                    // "process-sources",
-                    // "generate-resources",
-                    RESOURCES,
-                    // "process-resources",
-                    COMPILE,
-                    // "process-classes",
-                    READY,
-                    // "generate-test-sources",
-                    TEST_SOURCES,
-                    // "process-test-sources",
-                    // "generate-test-resources",
-                    TEST_RESOURCES,
-                    // "process-test-resources",
-                    TEST_COMPILE,
-                    // "process-test-classes",
-                    TEST,
-                    UNIT_TEST,
-                    // "prepare-package",
-                    PACKAGE,
-                    BUILD,
-                    // "pre-integration-test",
-                    INTEGRATION_TEST,
-                    // "post-integration-test",
-                    VERIFY,
-                    INSTALL,
-                    DEPLOY,
-                    "all"));
-        }
     }
 
     static class SiteLifecycle implements Lifecycle {
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
index cc05a32ca6..91d392e280 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
@@ -23,13 +23,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 import org.apache.maven.lifecycle.mapping.LifecyclePhase;
 
-import static org.apache.maven.api.Lifecycle.AFTER;
-import static org.apache.maven.api.Lifecycle.BEFORE;
-
 /**
  * Lifecycle definition, with eventual plugin bindings (when they are not 
packaging-specific).
  */
@@ -46,9 +42,7 @@ public class Lifecycle {
             org.apache.maven.api.services.LifecycleRegistry registry, 
org.apache.maven.api.Lifecycle lifecycle) {
         this.lifecycle = lifecycle;
         this.id = lifecycle.id();
-        this.phases = registry.computePhases(lifecycle).stream()
-                .flatMap(p -> Stream.of(BEFORE + p, p, AFTER + p))
-                .toList();
+        this.phases = registry.computePhases(lifecycle);
         this.defaultPhases = getDefaultPhases(lifecycle);
     }
 
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java
 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java
index 35eadd54c3..bdd6e8e5be 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java
@@ -25,7 +25,6 @@ import javax.xml.stream.XMLStreamException;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -264,13 +263,10 @@ public class DefaultLifecycleExecutionPlanCalculator 
implements LifecycleExecuti
         }
 
         LifecycleMappingDelegate delegate;
-        if (Arrays.binarySearch(DefaultLifecycles.STANDARD_LIFECYCLES, 
lifecycle.getId()) >= 0) {
+        if 
(List.of(DefaultLifecycles.STANDARD_LIFECYCLES).contains(lifecycle.getId())) {
             delegate = standardDelegate;
         } else {
-            delegate = delegates.get(lifecycle.getId());
-            if (delegate == null) {
-                delegate = standardDelegate;
-            }
+            delegate = delegates.getOrDefault(lifecycle.getId(), 
standardDelegate);
         }
 
         return delegate.calculateLifecycleMappings(session, project, 
lifecycle, lifecyclePhase);
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java
 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java
index 43598103f1..82407e1948 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java
@@ -82,14 +82,23 @@ public class DefaultLifecycleMappingDelegate implements 
LifecycleMappingDelegate
             lifecyclePhase = PhaseId.of(aliases.get(lifecyclePhase)).phase();
         }
 
+        boolean passed = false;
         for (String phase : lifecycle.getPhases()) {
-            Map<PhaseId, List<MojoExecution>> phaseBindings =
-                    new TreeMap<>(Comparator.comparing(PhaseId::toString, new 
PhaseComparator(lifecycle.getPhases())));
-
-            mappings.put(phase, phaseBindings);
-
+            boolean include = true;
             if (phase.equals(lifecyclePhase)) {
-                break;
+                passed = true;
+            } else if (passed) {
+                if (phase.startsWith(org.apache.maven.api.Lifecycle.AFTER)) {
+                    String realPhase = 
phase.substring(org.apache.maven.api.Lifecycle.AFTER.length());
+                    include = 
mappings.containsKey(org.apache.maven.api.Lifecycle.BEFORE + realPhase);
+                } else {
+                    include = false;
+                }
+            }
+            if (include) {
+                Map<PhaseId, List<MojoExecution>> phaseBindings = new 
TreeMap<>(
+                        Comparator.comparing(PhaseId::toString, new 
PhaseComparator(lifecycle.getPhases())));
+                mappings.put(phase, phaseBindings);
             }
         }
 
@@ -163,7 +172,7 @@ public class DefaultLifecycleMappingDelegate implements 
LifecycleMappingDelegate
             Map<String, Map<PhaseId, List<MojoExecution>>> mappings, String 
phase) {
         if (phase != null) {
             PhaseId id = PhaseId.of(phase);
-            return mappings.get(id.phase());
+            return mappings.get(id.executionPoint().prefix() + id.phase());
         }
         return null;
     }
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java
 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java
index 7c8004b8c3..2a1efccfbf 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseComparator.java
@@ -43,8 +43,8 @@ public class PhaseComparator implements Comparator<String> {
     public int compare(String o1, String o2) {
         PhaseId p1 = PhaseId.of(o1);
         PhaseId p2 = PhaseId.of(o2);
-        int i1 = lifecyclePhases.indexOf(p1.phase());
-        int i2 = lifecyclePhases.indexOf(p2.phase());
+        int i1 = lifecyclePhases.indexOf(p1.executionPoint().prefix() + 
p1.phase());
+        int i2 = lifecyclePhases.indexOf(p2.executionPoint().prefix() + 
p2.phase());
         if (i1 == -1 && i2 == -1) {
             // unknown phases, leave in existing order
             return 0;
@@ -61,13 +61,6 @@ public class PhaseComparator implements Comparator<String> {
         if (rv != 0) {
             return rv;
         }
-        // same phase, now compare execution points
-        i1 = p1.executionPoint().ordinal();
-        i2 = p2.executionPoint().ordinal();
-        rv = Integer.compare(i1, i2);
-        if (rv != 0) {
-            return rv;
-        }
         // same execution point, now compare priorities
         return Integer.compare(p1.priority(), p2.priority());
     }
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java
 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java
index 57fdc9dabb..5dfa27cb9b 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java
@@ -410,6 +410,9 @@ public class BuildPlanExecutor {
                                 MojoDescriptor mojoDescriptor = 
getMojoDescriptor(project, plugin, goal);
                                 String phase =
                                         execution.getPhase() != null ? 
execution.getPhase() : mojoDescriptor.getPhase();
+                                if (phase == null) {
+                                    continue;
+                                }
                                 String tmpResolvedPhase = 
plan.aliases().getOrDefault(phase, phase);
                                 String resolvedPhase = 
tmpResolvedPhase.startsWith(AT)
                                         ? 
tmpResolvedPhase.substring(AT.length())
@@ -680,9 +683,7 @@ public class BuildPlanExecutor {
                                 + " or a goal in the format 
<plugin-prefix>:<goal> or"
                                 + " 
<plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available 
lifecycle phases are: "
                                 + lifecycles.stream()
-                                        .flatMap(l -> l.orderedPhases()
-                                                .map(List::stream)
-                                                .orElseGet(() -> 
l.allPhases().map(Lifecycle.Phase::name)))
+                                        .flatMap(l -> 
l.allPhases().map(Lifecycle.Phase::name))
                                         .collect(Collectors.joining(", "))
                                 + ".",
                         lifecyclePhase));
@@ -735,6 +736,10 @@ public class BuildPlanExecutor {
                                 ? lifecyclePhase.substring(AT.length())
                                 : AFTER + lifecyclePhase;
                 Set<BuildStep> toKeep = 
steps.get(endPhase).allPredecessors().collect(Collectors.toSet());
+                toKeep.addAll(toKeep.stream()
+                        .filter(s -> s.name.startsWith(BEFORE))
+                        .map(s -> steps.get(AFTER + 
s.name.substring(BEFORE.length())))
+                        .toList());
                 steps.values().stream().filter(n -> 
!toKeep.contains(n)).forEach(BuildStep::skip);
 
                 plan.addProject(project, steps);
diff --git 
a/impl/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
 
b/impl/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
index 46f3553c9e..ca7a81f0bf 100644
--- 
a/impl/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
+++ 
b/impl/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
@@ -173,26 +173,21 @@ class LifecycleExecutorTest extends 
AbstractCoreMavenComponentTestCase {
         // [09] jar:jar
         // [10] install:install
         //
-        assertEquals(10, executionPlan.size());
-
-        assertEquals("clean:clean", 
executionPlan.get(0).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "resources:resources", 
executionPlan.get(1).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "compiler:compile", 
executionPlan.get(2).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "it:generate-metadata", 
executionPlan.get(3).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "resources:testResources",
-                executionPlan.get(4).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "compiler:testCompile", 
executionPlan.get(5).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "it:generate-test-metadata",
-                executionPlan.get(6).getMojoDescriptor().getFullGoalName());
-        assertEquals("surefire:test", 
executionPlan.get(7).getMojoDescriptor().getFullGoalName());
-        assertEquals("jar:jar", 
executionPlan.get(8).getMojoDescriptor().getFullGoalName());
-        assertEquals("install:install", 
executionPlan.get(9).getMojoDescriptor().getFullGoalName());
+        assertListEquals(
+                List.of(
+                        "clean:clean",
+                        "resources:resources",
+                        "compiler:compile",
+                        "it:generate-metadata",
+                        "resources:testResources",
+                        "compiler:testCompile",
+                        "it:generate-test-metadata",
+                        "surefire:test",
+                        "jar:jar",
+                        "install:install"),
+                executionPlan.stream()
+                        .map(plan -> 
plan.getMojoDescriptor().getFullGoalName())
+                        .toList());
     }
 
     // We need to take in multiple lifecycles
@@ -226,31 +221,29 @@ class LifecycleExecutorTest extends 
AbstractCoreMavenComponentTestCase {
         // [16] install:install
         //
 
-        assertEquals(16, executions.size());
-
-        assertEquals("clean:clean", 
executions.get(0).getMojoDescriptor().getFullGoalName());
-        assertEquals("it:xpp3-writer", 
executions.get(1).getMojoDescriptor().getFullGoalName());
-        assertEquals("it:java", 
executions.get(2).getMojoDescriptor().getFullGoalName());
-        assertEquals("it:xpp3-reader", 
executions.get(3).getMojoDescriptor().getFullGoalName());
-        assertEquals("it:xpp3-writer", 
executions.get(4).getMojoDescriptor().getFullGoalName());
-        assertEquals("it:java", 
executions.get(5).getMojoDescriptor().getFullGoalName());
-        assertEquals("it:xpp3-reader", 
executions.get(6).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "resources:resources", 
executions.get(7).getMojoDescriptor().getFullGoalName());
-        assertEquals("compiler:compile", 
executions.get(8).getMojoDescriptor().getFullGoalName());
-        assertEquals("plugin:descriptor", 
executions.get(9).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "resources:testResources",
-                executions.get(10).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "compiler:testCompile", 
executions.get(11).getMojoDescriptor().getFullGoalName());
-        assertEquals("surefire:test", 
executions.get(12).getMojoDescriptor().getFullGoalName());
-        assertEquals("jar:jar", 
executions.get(13).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "plugin:addPluginArtifactMetadata",
-                executions.get(14).getMojoDescriptor().getFullGoalName());
-        assertEquals("install:install", 
executions.get(15).getMojoDescriptor().getFullGoalName());
-
+        assertListEquals(
+                List.of(
+                        "clean:clean",
+                        "it:xpp3-writer",
+                        "it:java",
+                        "it:xpp3-reader",
+                        "it:xpp3-writer",
+                        "it:java",
+                        "it:xpp3-reader",
+                        "resources:resources",
+                        "compiler:compile",
+                        "plugin:descriptor",
+                        "resources:testResources",
+                        "compiler:testCompile",
+                        "surefire:test",
+                        "jar:jar",
+                        "plugin:addPluginArtifactMetadata",
+                        "install:install"),
+                executions.stream()
+                        .map(execution -> 
execution.getMojoDescriptor().getFullGoalName())
+                        .toList());
+
+        // Keep the separate configuration checks
         assertEquals(
                 "src/main/mdo/remote-resources.mdo",
                 new 
MojoExecutionXPathContainer(executions.get(1)).getValue("configuration/models[1]/model"));
@@ -278,24 +271,19 @@ class LifecycleExecutorTest extends 
AbstractCoreMavenComponentTestCase {
         // [07] surefire:test
         // [08] jar:jar
         //
-        assertEquals(8, executionPlan.size());
-
-        assertEquals(
-                "resources:resources", 
executionPlan.get(0).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "compiler:compile", 
executionPlan.get(1).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "it:generate-metadata", 
executionPlan.get(2).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "resources:testResources",
-                executionPlan.get(3).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "compiler:testCompile", 
executionPlan.get(4).getMojoDescriptor().getFullGoalName());
-        assertEquals(
-                "it:generate-test-metadata",
-                executionPlan.get(5).getMojoDescriptor().getFullGoalName());
-        assertEquals("surefire:test", 
executionPlan.get(6).getMojoDescriptor().getFullGoalName());
-        assertEquals("jar:jar", 
executionPlan.get(7).getMojoDescriptor().getFullGoalName());
+        assertListEquals(
+                List.of(
+                        "resources:resources",
+                        "compiler:compile",
+                        "it:generate-metadata",
+                        "resources:testResources",
+                        "compiler:testCompile",
+                        "it:generate-test-metadata",
+                        "surefire:test",
+                        "jar:jar"),
+                executionPlan.stream()
+                        .map(plan -> 
plan.getMojoDescriptor().getFullGoalName())
+                        .toList());
     }
 
     @Test
@@ -516,18 +504,14 @@ class LifecycleExecutorTest extends 
AbstractCoreMavenComponentTestCase {
                 "afterProjectExecutionSuccess project-basic" //
                 );
 
-        assertEventLog(expectedLog, log);
+        assertListEquals(expectedLog, log);
     }
 
-    private static void assertEventLog(List<String> expectedList, List<String> 
actualList) {
+    private static void assertListEquals(List<String> expectedList, 
List<String> actualList) {
         assertEquals(toString(expectedList), toString(actualList));
     }
 
     private static String toString(List<String> lines) {
-        StringBuilder sb = new StringBuilder();
-        for (String line : lines) {
-            sb.append(line).append('\n');
-        }
-        return sb.toString();
+        return String.join("\n", lines);
     }
 }
diff --git 
a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8244PhaseAllTest.java
 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8244PhaseAllTest.java
new file mode 100644
index 0000000000..99e1980249
--- /dev/null
+++ 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8244PhaseAllTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.it;
+
+import java.io.File;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * This is a test set for <a 
href="https://issues.apache.org/jira/browse/MNG-8244";>MNG-8244</a>.
+ */
+class MavenITmng8244PhaseAllTest extends AbstractMavenIntegrationTestCase {
+
+    MavenITmng8244PhaseAllTest() {
+        super("[4.0.0-rc-2,)");
+    }
+
+    /**
+     *  Verify phase after:all phase is called
+     */
+    @Test
+    void testPhaseAllWihConcurrentBuilder() throws Exception {
+        File testDir = extractResources("/mng-8244-phase-all");
+
+        Verifier verifier = newVerifier(testDir.getAbsolutePath());
+        verifier.setLogFileName("build-concurrent.txt");
+        verifier.addCliArguments("-b", "concurrent", "build");
+        verifier.execute();
+
+        verifier.verifyTextInLog("Hallo 'before:all' phase.");
+        verifier.verifyTextInLog("Hallo 'after:all' phase.");
+    }
+
+    /**
+     *  Verify phase after:all phase is called
+     */
+    @Test
+    void testPhaseAllWithLegacyBuilder() throws Exception {
+        File testDir = extractResources("/mng-8244-phase-all");
+
+        Verifier verifier = newVerifier(testDir.getAbsolutePath());
+        verifier.setLogFileName("build-legacy.txt");
+        verifier.addCliArguments("build");
+        verifier.execute();
+
+        verifier.verifyTextInLog("Hallo 'before:all' phase.");
+        verifier.verifyTextInLog("Hallo 'after:all' phase.");
+    }
+}
diff --git 
a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java 
b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java
index ac5b592a86..5a5a4c149a 100644
--- a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java
@@ -100,6 +100,7 @@ public class TestSuiteOrdering implements ClassOrderer {
          * the tests are to finishing. Newer tests are also more likely to 
fail, so this is
          * a fail fast technique as well.
          */
+        suite.addTestSuite(MavenITmng8244PhaseAllTest.class);
         suite.addTestSuite(MavenITmng8421MavenEncryptionTest.class);
         suite.addTestSuite(MavenITmng8400CanonicalMavenHomeTest.class);
         suite.addTestSuite(MavenITmng8385PropertyContributoSPITest.class);
diff --git a/its/core-it-suite/src/test/resources/mng-8244-phase-all/pom.xml 
b/its/core-it-suite/src/test/resources/mng-8244-phase-all/pom.xml
new file mode 100644
index 0000000000..35250bb229
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8244-phase-all/pom.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.1.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; root="true" 
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 
https://maven.apache.org/xsd/maven-4.1.0.xsd";>
+
+  <groupId>org.apache.maven.its</groupId>
+  <artifactId>mng-8244</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>com.soebes.maven.plugins</groupId>
+        <artifactId>echo-maven-plugin</artifactId>
+        <version>0.5.0</version>
+        <executions>
+          <execution>
+            <id>before-clean</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>before:clean</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'before:clean' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+          <execution>
+            <id>after-clean</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>after:clean</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'after:clean' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+          <execution>
+            <id>before-build</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>before:build</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'before:build' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+          <execution>
+            <id>build</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>build</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'build' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+          <execution>
+            <id>after-build</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>after:build</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'after:build' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+          <execution>
+            <id>before-all</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>before:all</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'before:all' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+          <execution>
+            <id>all</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>all</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'all' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+          <execution>
+            <id>after-all</id>
+            <goals>
+              <goal>echo</goal>
+            </goals>
+            <phase>after:all</phase>
+            <configuration>
+              <echos>
+                <echo>Hallo 'after:all' phase.</echo>
+              </echos>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+
+  </build>
+
+</project>


Reply via email to