diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index c79dab47a5..b0d649081e 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -115,6 +115,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static java.util.Comparator.comparing; import static org.apache.maven.cli.ResolveFile.resolveFile; import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; @@ -986,7 +987,7 @@ private int execute( CliRequest cliRequest ) Map references = new LinkedHashMap<>(); - MavenProject project = null; + List failedProjects = new ArrayList<>(); for ( Throwable exception : result.getExceptions() ) { @@ -994,10 +995,9 @@ private int execute( CliRequest cliRequest ) logSummary( summary, references, "", cliRequest.showErrors ); - if ( project == null && exception instanceof LifecycleExecutionException ) + if ( exception instanceof LifecycleExecutionException ) { - LifecycleExecutionException lifecycleExecutionException = (LifecycleExecutionException) exception; - project = lifecycleExecutionException.getProject(); + failedProjects.add ( ( (LifecycleExecutionException) exception ).getProject() ); } } @@ -1026,15 +1026,23 @@ private int execute( CliRequest cliRequest ) } } - List sortedProjects = result.getTopologicallySortedProjects(); if ( result.canResume() ) { - logBuildResumeHint( "mvn -r " ); + logBuildResumeHint( "mvn -r" ); } - else if ( project != null && !project.equals( sortedProjects.get( 0 ) ) ) + else if ( !failedProjects.isEmpty() ) { - String resumeFromSelector = getResumeFromSelector( sortedProjects, project ); - logBuildResumeHint( "mvn -rf " + resumeFromSelector ); + List sortedProjects = result.getTopologicallySortedProjects(); + + // Sort the failedProjects list in the topologically sorted order. + failedProjects.sort( comparing( sortedProjects::indexOf ) ); + + MavenProject firstFailedProject = failedProjects.get( 0 ); + if ( !firstFailedProject.equals( sortedProjects.get( 0 ) ) ) + { + String resumeFromSelector = getResumeFromSelector( sortedProjects, firstFailedProject ); + logBuildResumeHint( "mvn -rf " + resumeFromSelector ); + } } if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) ) @@ -1074,22 +1082,22 @@ private void logBuildResumeHint( String resumeBuildHint ) * This method is made package-private for testing purposes. * * @param mavenProjects Maven projects which are part of build execution. - * @param failedProject Project which has failed. + * @param firstFailedProject The first project which has failed. * @return Value for -rf flag to resume build exactly from place where it failed ({@code :artifactId} in general * and {@code groupId:artifactId} when there is a name clash). */ - String getResumeFromSelector( List mavenProjects, MavenProject failedProject ) + String getResumeFromSelector( List mavenProjects, MavenProject firstFailedProject ) { boolean hasOverlappingArtifactId = mavenProjects.stream() - .filter( project -> failedProject.getArtifactId().equals( project.getArtifactId() ) ) + .filter( project -> firstFailedProject.getArtifactId().equals( project.getArtifactId() ) ) .count() > 1; if ( hasOverlappingArtifactId ) { - return failedProject.getGroupId() + ":" + failedProject.getArtifactId(); + return firstFailedProject.getGroupId() + ":" + firstFailedProject.getArtifactId(); } - return ":" + failedProject.getArtifactId(); + return ":" + firstFailedProject.getArtifactId(); } private void logSummary( ExceptionSummary summary, Map references, String indent,