Skip to content

Commit 5dbe9b4

Browse files
committed
[MNG-8678] Address review: improve isFatal Javadoc and add soft-failure test
Follow-up to #13055. The isFatal Javadoc @return tag now explains why RuntimeException is treated as fatal on par with Error (both indicate an unexpected JVM or framework state). A new test pins the soft-failure path so a future change to isFatal cannot silently break --fail-at-end for ordinary plugin failures.
1 parent 40c5963 commit 5dbe9b4

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,9 @@ private void executeStep(BuildStep step) throws IOException, LifecycleExecutionE
599599
* them can only be seen by looking at the failures themselves.
600600
*
601601
* @param failures The failures collected for a single project
602-
* @return {@code true} if the build must be halted
602+
* @return {@code true} if the build must be halted; checked exceptions (ordinary plugin failures) are
603+
* soft and allow the reactor to continue with other projects, while {@link RuntimeException}s
604+
* and {@link Error}s indicate an unexpected JVM or framework state and halt the build
603605
*/
604606
private static boolean isFatal(List<Throwable> failures) {
605607
return failures.stream().anyMatch(t -> t instanceof RuntimeException || !(t instanceof Exception));

impl/maven-core/src/test/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutorTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,34 @@ void exceptionThrownByBuildStepIsRecordedAsBuildFailure() throws Exception {
9393
assertTrue(session.getResult().getBuildSummary(project) instanceof org.apache.maven.execution.BuildFailure);
9494
}
9595

96+
/**
97+
* A checked exception thrown by a build step is a soft failure: the reactor must not be halted, and
98+
* other projects must still be built when {@code REACTOR_FAIL_AT_END} is in effect. This pins the
99+
* soft-failure path of {@code isFatal} so a future change does not silently break {@code --fail-at-end}
100+
* for ordinary plugin failures.
101+
*/
102+
@Test
103+
void checkedExceptionThrownByBuildStepDoesNotHaltReactor() throws Exception {
104+
MavenProject project = newProject();
105+
MavenSession session = newSession(project);
106+
session.getRequest().setReactorFailureBehavior(MavenExecutionRequest.REACTOR_FAIL_AT_END);
107+
108+
ReactorContext reactorContext = execute(session, project, event -> {}, plan -> {
109+
BuildStep step = plan.step(project, "validate")
110+
.orElseThrow(() -> new IllegalStateException("no validate step in the plan"));
111+
// LifecycleExecutionException is a checked exception — the soft-failure case for isFatal.
112+
step.exception = new LifecycleExecutionException("plugin failure");
113+
step.status.set(BuildStep.FAILED);
114+
});
115+
116+
assertTrue(
117+
session.getResult().getBuildSummary(project) instanceof org.apache.maven.execution.BuildFailure,
118+
"the project must be recorded as a failure");
119+
assertTrue(
120+
!reactorContext.getReactorBuildStatus().isHalted(),
121+
"a checked exception must not halt the reactor when REACTOR_FAIL_AT_END is set");
122+
}
123+
96124
/**
97125
* A project can end up with more than one failure: when a build step fails, the matching after:* step is
98126
* still run for cleanup and may fail on its own. Those failures are reported through a wrapper exception,

0 commit comments

Comments
 (0)