Skip to content

Commit 7be65f2

Browse files
committed
[MNG-8244] Fix wrong phase order
1 parent 874a0d5 commit 7be65f2

File tree

6 files changed

+74
-87
lines changed

6 files changed

+74
-87
lines changed

api/maven-api-core/src/main/java/org/apache/maven/api/Lifecycle.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import java.util.Collection;
2222
import java.util.List;
23-
import java.util.Optional;
2423
import java.util.stream.Stream;
2524

2625
import org.apache.maven.api.annotations.Experimental;
@@ -70,6 +69,15 @@ public interface Lifecycle extends ExtensibleEnum {
7069
*/
7170
Collection<Phase> phases();
7271

72+
/**
73+
* Collection of main phases for this lifecycle used with the Maven 3 builders.
74+
* Those builders does not operate on a graph, but on the list and expect a slightly
75+
* different ordering (mainly unit test being executed before packaging).
76+
*/
77+
default Collection<Phase> v3phases() {
78+
return phases();
79+
}
80+
7381
/**
7482
* Stream of phases containing all child phases recursively.
7583
*/
@@ -82,14 +90,6 @@ default Stream<Phase> allPhases() {
8290
*/
8391
Collection<Alias> aliases();
8492

85-
/**
86-
* Pre-ordered list of phases.
87-
* If not provided, a default order will be computed.
88-
*/
89-
default Optional<List<String>> orderedPhases() {
90-
return Optional.empty();
91-
}
92-
9393
/**
9494
* A phase in the lifecycle.
9595
*

impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLifecycleRegistry.java

Lines changed: 42 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import javax.inject.Singleton;
2525

2626
import java.util.ArrayList;
27-
import java.util.Arrays;
2827
import java.util.Collection;
2928
import java.util.Collections;
3029
import java.util.HashSet;
@@ -50,6 +49,8 @@
5049
import org.codehaus.plexus.PlexusContainer;
5150
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
5251

52+
import static org.apache.maven.api.Lifecycle.AFTER;
53+
import static org.apache.maven.api.Lifecycle.BEFORE;
5354
import static org.apache.maven.api.Lifecycle.Phase.ALL;
5455
import static org.apache.maven.api.Lifecycle.Phase.BUILD;
5556
import static org.apache.maven.api.Lifecycle.Phase.COMPILE;
@@ -130,34 +131,20 @@ public Optional<Lifecycle> lookup(String id) {
130131

131132
public List<String> computePhases(Lifecycle lifecycle) {
132133
Graph graph = new Graph();
133-
lifecycle.phases().forEach(phase -> addPhase(graph, null, null, phase));
134+
lifecycle.v3phases().forEach(phase -> addPhase(graph, null, null, phase));
134135
List<String> allPhases = graph.visitAll();
135136
Collections.reverse(allPhases);
136137
List<String> computed =
137138
allPhases.stream().filter(s -> !s.startsWith("$")).collect(Collectors.toList());
138-
List<String> given = lifecycle.orderedPhases().orElse(null);
139-
if (given != null) {
140-
if (given.size() != computed.size()) {
141-
Set<String> s1 =
142-
given.stream().filter(s -> !computed.contains(s)).collect(Collectors.toSet());
143-
Set<String> s2 =
144-
computed.stream().filter(s -> !given.contains(s)).collect(Collectors.toSet());
145-
throw new IllegalStateException(
146-
"List of phases differ in size: expected " + computed.size() + ", but received " + given.size()
147-
+ (s1.isEmpty() ? "" : ", missing " + s1)
148-
+ (s2.isEmpty() ? "" : ", unexpected " + s2));
149-
}
150-
return given;
151-
}
152139
return computed;
153140
}
154141

155142
private static void addPhase(
156143
Graph graph, Graph.Vertex before, Graph.Vertex after, org.apache.maven.api.Lifecycle.Phase phase) {
157-
Graph.Vertex ep0 = graph.addVertex("$" + phase.name());
144+
Graph.Vertex ep0 = graph.addVertex(BEFORE + phase.name());
158145
Graph.Vertex ep1 = graph.addVertex("$$" + phase.name());
159146
Graph.Vertex ep2 = graph.addVertex(phase.name());
160-
Graph.Vertex ep3 = graph.addVertex("$$$" + phase.name());
147+
Graph.Vertex ep3 = graph.addVertex(AFTER + phase.name());
161148
graph.addEdge(ep0, ep1);
162149
graph.addEdge(ep1, ep2);
163150
graph.addEdge(ep2, ep3);
@@ -172,11 +159,23 @@ private static void addPhase(
172159
if (link.kind() == Lifecycle.Link.Kind.AFTER) {
173160
graph.addEdge(graph.addVertex(link.pointer().phase()), ep0);
174161
} else {
175-
graph.addEdge(ep3, graph.addVertex("$" + link.pointer().phase()));
162+
graph.addEdge(ep3, graph.addVertex(BEFORE + link.pointer().phase()));
176163
}
177164
}
178165
});
179-
phase.phases().forEach(child -> addPhase(graph, ep1, ep2, child));
166+
// We add ordering between internal phases.
167+
// This would be wrong at execution time, but we are here computing a list and not a graph,
168+
// so in order to obtain the expected order, we add these links between phases.
169+
Lifecycle.Phase prev = null;
170+
for (Lifecycle.Phase child : phase.phases()) {
171+
// add phase
172+
addPhase(graph, ep1, ep2, child);
173+
if (prev != null) {
174+
// add link between end of previous phase and beginning of this one
175+
graph.addEdge(graph.addVertex(AFTER + prev.name()), graph.addVertex(BEFORE + child.name()));
176+
}
177+
prev = child;
178+
}
180179
}
181180

182181
@Named
@@ -408,6 +407,29 @@ public Collection<Phase> phases() {
408407
phase(DEPLOY, after(PACKAGE))));
409408
}
410409

410+
@Override
411+
public Collection<Phase> v3phases() {
412+
return List.of(phase(
413+
ALL,
414+
phase(VALIDATE),
415+
phase(INITIALIZE),
416+
phase(SOURCES),
417+
phase(RESOURCES),
418+
phase(COMPILE),
419+
phase(READY),
420+
phase(TEST_SOURCES),
421+
phase(TEST_RESOURCES),
422+
phase(TEST_COMPILE),
423+
phase(TEST),
424+
phase(UNIT_TEST),
425+
phase(PACKAGE),
426+
phase(BUILD),
427+
phase(INTEGRATION_TEST),
428+
phase(VERIFY),
429+
phase(INSTALL),
430+
phase(DEPLOY)));
431+
}
432+
411433
@Override
412434
public Collection<Alias> aliases() {
413435
return List.of(
@@ -425,42 +447,6 @@ public Collection<Alias> aliases() {
425447
alias("pre-integration-test", BEFORE + INTEGRATION_TEST),
426448
alias("post-integration-test", AFTER + INTEGRATION_TEST));
427449
}
428-
429-
@Override
430-
public Optional<List<String>> orderedPhases() {
431-
return Optional.of(Arrays.asList(
432-
VALIDATE,
433-
INITIALIZE,
434-
// "generate-sources",
435-
SOURCES,
436-
// "process-sources",
437-
// "generate-resources",
438-
RESOURCES,
439-
// "process-resources",
440-
COMPILE,
441-
// "process-classes",
442-
READY,
443-
// "generate-test-sources",
444-
TEST_SOURCES,
445-
// "process-test-sources",
446-
// "generate-test-resources",
447-
TEST_RESOURCES,
448-
// "process-test-resources",
449-
TEST_COMPILE,
450-
// "process-test-classes",
451-
TEST,
452-
UNIT_TEST,
453-
// "prepare-package",
454-
PACKAGE,
455-
BUILD,
456-
// "pre-integration-test",
457-
INTEGRATION_TEST,
458-
// "post-integration-test",
459-
VERIFY,
460-
INSTALL,
461-
DEPLOY,
462-
ALL));
463-
}
464450
}
465451

466452
static class SiteLifecycle implements Lifecycle {

impl/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,9 @@
2323
import java.util.List;
2424
import java.util.Map;
2525
import java.util.stream.Collectors;
26-
import java.util.stream.Stream;
2726

2827
import org.apache.maven.lifecycle.mapping.LifecyclePhase;
2928

30-
import static org.apache.maven.api.Lifecycle.AFTER;
31-
import static org.apache.maven.api.Lifecycle.BEFORE;
32-
3329
/**
3430
* Lifecycle definition, with eventual plugin bindings (when they are not packaging-specific).
3531
*/
@@ -46,9 +42,7 @@ public Lifecycle(
4642
org.apache.maven.api.services.LifecycleRegistry registry, org.apache.maven.api.Lifecycle lifecycle) {
4743
this.lifecycle = lifecycle;
4844
this.id = lifecycle.id();
49-
this.phases = registry.computePhases(lifecycle).stream()
50-
.flatMap(p -> Stream.of(BEFORE + p, p, AFTER + p))
51-
.toList();
45+
this.phases = registry.computePhases(lifecycle);
5246
this.defaultPhases = getDefaultPhases(lifecycle);
5347
}
5448

impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
import java.io.IOException;
2727
import java.util.ArrayList;
28-
import java.util.Arrays;
2928
import java.util.Collection;
3029
import java.util.Collections;
3130
import java.util.HashMap;
@@ -264,13 +263,10 @@ private Map<String, List<MojoExecution>> calculateLifecycleMappings(
264263
}
265264

266265
LifecycleMappingDelegate delegate;
267-
if (Arrays.binarySearch(DefaultLifecycles.STANDARD_LIFECYCLES, lifecycle.getId()) >= 0) {
266+
if (List.of(DefaultLifecycles.STANDARD_LIFECYCLES).contains(lifecycle.getId())) {
268267
delegate = standardDelegate;
269268
} else {
270-
delegate = delegates.get(lifecycle.getId());
271-
if (delegate == null) {
272-
delegate = standardDelegate;
273-
}
269+
delegate = delegates.getOrDefault(lifecycle.getId(), standardDelegate);
274270
}
275271

276272
return delegate.calculateLifecycleMappings(session, project, lifecycle, lifecyclePhase);

impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,23 @@ public Map<String, List<MojoExecution>> calculateLifecycleMappings(
8282
lifecyclePhase = PhaseId.of(aliases.get(lifecyclePhase)).phase();
8383
}
8484

85+
boolean passed = false;
8586
for (String phase : lifecycle.getPhases()) {
86-
Map<PhaseId, List<MojoExecution>> phaseBindings =
87-
new TreeMap<>(Comparator.comparing(PhaseId::toString, new PhaseComparator(lifecycle.getPhases())));
88-
89-
mappings.put(phase, phaseBindings);
90-
87+
boolean include = true;
9188
if (phase.equals(lifecyclePhase)) {
92-
break;
89+
passed = true;
90+
} else if (passed) {
91+
if (phase.startsWith(org.apache.maven.api.Lifecycle.AFTER)) {
92+
String realPhase = phase.substring(org.apache.maven.api.Lifecycle.AFTER.length());
93+
include = mappings.containsKey(org.apache.maven.api.Lifecycle.BEFORE + realPhase);
94+
} else {
95+
include = false;
96+
}
97+
}
98+
if (include) {
99+
Map<PhaseId, List<MojoExecution>> phaseBindings = new TreeMap<>(
100+
Comparator.comparing(PhaseId::toString, new PhaseComparator(lifecycle.getPhases())));
101+
mappings.put(phase, phaseBindings);
93102
}
94103
}
95104

impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -683,9 +683,7 @@ public BuildPlan calculateLifecycleMappings(
683683
+ " or a goal in the format <plugin-prefix>:<goal> or"
684684
+ " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: "
685685
+ lifecycles.stream()
686-
.flatMap(l -> l.orderedPhases()
687-
.map(List::stream)
688-
.orElseGet(() -> l.allPhases().map(Lifecycle.Phase::name)))
686+
.flatMap(l -> l.allPhases().map(Lifecycle.Phase::name))
689687
.collect(Collectors.joining(", "))
690688
+ ".",
691689
lifecyclePhase));
@@ -738,6 +736,10 @@ public BuildPlan calculateLifecycleMappings(
738736
? lifecyclePhase.substring(AT.length())
739737
: AFTER + lifecyclePhase;
740738
Set<BuildStep> toKeep = steps.get(endPhase).allPredecessors().collect(Collectors.toSet());
739+
toKeep.addAll(toKeep.stream()
740+
.filter(s -> s.name.startsWith(BEFORE))
741+
.map(s -> steps.get(AFTER + s.name.substring(BEFORE.length())))
742+
.toList());
741743
steps.values().stream().filter(n -> !toKeep.contains(n)).forEach(BuildStep::skip);
742744

743745
plan.addProject(project, steps);

0 commit comments

Comments
 (0)