You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2020/06/20 09:33:13 UTC

[maven] branch MNG-5760 created (now 8da7f1e)

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

rfscholte pushed a change to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git.


      at 8da7f1e  Removed unused import

This branch includes the following new commits:

     new 556bcca  When a build fails, write file with properties to resume the next build from.
     new 1d0c15f  Refactored the getResumeFromSelector logic to be compliant with checkstyle rules.
     new e4e89ff  Added JavaDoc to the method which determines whether a resume-from suggestion should be given or not.
     new 9d317a0  Added license to BuildResumptionManagerTest
     new 25e8d80  When -r is given, load resume.properties and apply it to the execution request.
     new 6841824  Created unit tests for the resumeFromSelector method.
     new 2d7de18  Removed dead code, as the `getResumeFrom` method has been moved to the BuildResumptionManager.
     new 915a3e5  Fix bug where the build resume hint log could be logged incorrectly.
     new ff350df  Fixed a bug where a failed project would be excluded in the next build when it failed after another failed build.
     new df60659  Refactored to call the resumption manager from the DefaultMaven instead of the CLI. As DefaultMaven has the right info to determine the execution root.
     new f994d90  Removing the resumption data when a build succeeded.
     new 504a0ef  Extract public interface
     new edbeb96  Store information about resumption storage in execution result
     new 473a35e  Replace Stream#filter#count with Stream#anyMatch
     new a5cbea9  Avoid stringly-typed method signatures
     new 0936fd3  Rename resumptionDataStored to canResume
     new cbc0ec9  Replace Plexus logger with SLF4J
     new 9b94112  Replace String#format with String concatenation
     new ba630fc  Renamed BuildResumptionManager to BuildResumer
     new 8232861  Removed an unused mock for the plexus Logger, which is a leftover after moving to slf4j.
     new 393ab2b  Resolving review comment; clearing up persistResumptionData method name.
     new 3551992  Review comment: Removed Guava's @VisibleForTesting
     new 306baa6  When something fails while persisting resumption data, throw an exception instead of returning false.
     new f2cacd4  Add a boolean to the setCanResume method, which denotes whether a build can be resumed or not.
     new 4c94e2c  Fixed checkstyle findings
     new e4ef15f  Moved the -rf helper method, including the tests, back to MavenCli. The BuildResumer is now only focused on the --resume feature.
     new 94b5469  Rename interface and implementation
     new 823d375  Refactored `#determineProjectsToSkip` to return a list instead of an optional with a comma separated list
     new 6faa4cd  Split off BuildResumptionAnalyzer from BuildResumptionDataRepository
     new c8e810f  Persist method either succeeds or throws Exception, so returns void
     new 8da7f1e  Removed unused import

The 31 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[maven] 14/31: Replace Stream#filter#count with Stream#anyMatch

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 473a35e1a43ec01637d345d5cfadbde5e16bca75
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Mon May 25 15:39:50 2020 +0200

    Replace Stream#filter#count with Stream#anyMatch
---
 maven-core/src/main/java/org/apache/maven/DefaultMaven.java | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index a5e84f3..9f6c56f 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -366,11 +366,10 @@ public class DefaultMaven
 
     private void saveResumptionDataWhenApplicable( MavenExecutionResult result, MavenSession session )
     {
-        long lifecycleExecutionExceptionCount = result.getExceptions().stream()
-                .filter( LifecycleExecutionException.class::isInstance )
-                .count();
+        boolean hasLifecycleExecutionExceptions = result.getExceptions().stream()
+                .anyMatch( LifecycleExecutionException.class::isInstance );
 
-        if ( lifecycleExecutionExceptionCount > 0 )
+        if ( hasLifecycleExecutionExceptions )
         {
             session.getAllProjects().stream()
                     .filter( MavenProject::isExecutionRoot )


[maven] 28/31: Refactored `#determineProjectsToSkip` to return a list instead of an optional with a comma separated list

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 823d375c15926e40a5b69a57223ce4d355a2a027
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Wed Jun 17 15:00:22 2020 +0200

    Refactored `#determineProjectsToSkip` to return a list instead of an optional with a comma separated list
---
 .../DefaultBuildResumptionDataRepository.java      | 25 +++++++++-------------
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
index e6815ce..7e647d7 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
@@ -103,10 +103,13 @@ public class DefaultBuildResumptionDataRepository implements BuildResumptionData
         {
             MavenProject resumeFromProject = failedProjects.get( 0 );
             Optional<String> resumeFrom = getResumeFrom( result, resumeFromProject );
-            Optional<String> projectsToSkip = determineProjectsToSkip( result, failedProjects, resumeFromProject );
+            List<String> projectsToSkip = determineProjectsToSkip( result, failedProjects, resumeFromProject );
 
             resumeFrom.ifPresent( value -> properties.setProperty( RESUME_FROM_PROPERTY, value ) );
-            projectsToSkip.ifPresent( value -> properties.setProperty( EXCLUDED_PROJECTS_PROPERTY, value ) );
+            if ( !projectsToSkip.isEmpty() ) {
+                String excludedProjects = String.join( PROPERTY_DELIMITER, projectsToSkip );
+                properties.setProperty( EXCLUDED_PROJECTS_PROPERTY, excludedProjects );
+            }
         }
         else
         {
@@ -154,11 +157,10 @@ public class DefaultBuildResumptionDataRepository implements BuildResumptionData
      * @param result The result of the Maven build.
      * @param failedProjects The list of failed projects in the build.
      * @param resumeFromProject The project where the build will be resumed with in the next run.
-     * @return An optional containing a comma separated list of projects which can be skipped,
-     *   or an empty optional if no projects can be skipped.
+     * @return A list of projects which can be skipped in a later build.
      */
-    private Optional<String> determineProjectsToSkip( MavenExecutionResult result, List<MavenProject> failedProjects,
-                                                      MavenProject resumeFromProject )
+    private List<String> determineProjectsToSkip( MavenExecutionResult result, List<MavenProject> failedProjects,
+                                                  MavenProject resumeFromProject )
     {
         List<MavenProject> allProjects = result.getTopologicallySortedProjects();
         int resumeFromProjectIndex = allProjects.indexOf( resumeFromProject );
@@ -168,18 +170,11 @@ public class DefaultBuildResumptionDataRepository implements BuildResumptionData
                 .map( GroupArtifactPair::new )
                 .collect( Collectors.toList() );
 
-        String projectsToSkip = remainingProjects.stream()
+        return remainingProjects.stream()
                 .filter( project -> result.getBuildSummary( project ) instanceof BuildSuccess )
                 .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
                 .map( project -> project.getGroupId() + ":" + project.getArtifactId() )
-                .collect( Collectors.joining( PROPERTY_DELIMITER ) );
-
-        if ( !StringUtils.isEmpty( projectsToSkip ) )
-        {
-            return Optional.of( projectsToSkip );
-        }
-
-        return Optional.empty();
+                .collect( Collectors.toList() );
     }
 
     private boolean hasNoDependencyOnProjects( MavenProject project, List<GroupArtifactPair> projectsGAs )


[maven] 06/31: Created unit tests for the resumeFromSelector method.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 68418243b1691b4e467795ed0d699aad8dd58e23
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri May 22 15:14:24 2020 +0200

    Created unit tests for the resumeFromSelector method.
---
 .../execution/BuildResumptionManagerTest.java      | 33 +++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java b/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
index 95a0375..96c0dee 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
@@ -159,10 +159,41 @@ public class BuildResumptionManagerTest
         assertThat( request.getExcludedProjects(), contains( ":module-a", ":module-b", ":module-c" ) );
     }
 
+    @Test
+    public void resumeFromSelectorIsSuggestedWithoutGroupId()
+    {
+        List<MavenProject> allProjects = asList(
+                createMavenProject( "group", "module-a" ),
+                createMavenProject( "group", "module-b" ) );
+        MavenProject failedProject = allProjects.get( 0 );
+
+        String selector = buildResumptionManager.getResumeFromSelector( allProjects, failedProject );
+
+        assertThat( selector, is( ":module-a" ) );
+    }
+
+    @Test
+    public void resumeFromSelectorContainsGroupIdWhenArtifactIdIsNotUnique()
+    {
+        List<MavenProject> allProjects = asList(
+                createMavenProject( "group-a", "module" ),
+                createMavenProject( "group-b", "module" ) );
+        MavenProject failedProject = allProjects.get( 0 );
+
+        String selector = buildResumptionManager.getResumeFromSelector( allProjects, failedProject );
+
+        assertThat( selector, is( "group-a:module" ) );
+    }
+
     private MavenProject createMavenProject( String artifactId )
     {
+        return createMavenProject( "test", artifactId );
+    }
+
+    private MavenProject createMavenProject( String groupId, String artifactId )
+    {
         MavenProject project = new MavenProject();
-        project.setGroupId( "test" );
+        project.setGroupId( groupId );
         project.setArtifactId( artifactId );
         return project;
     }


[maven] 21/31: Resolving review comment; clearing up persistResumptionData method name.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 393ab2b7a18692ee5de45f3120892e91d36fb573
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri Jun 5 20:47:31 2020 +0200

    Resolving review comment; clearing up persistResumptionData method name.
---
 maven-core/src/main/java/org/apache/maven/DefaultMaven.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 3eb7544..a78bf75 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -318,7 +318,7 @@ public class DefaultMaven
             if ( session.getResult().hasExceptions() )
             {
                 addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) );
-                saveResumptionDataWhenApplicable( result, session );
+                persistResumptionData( result, session );
                 return result;
             }
             else
@@ -363,7 +363,7 @@ public class DefaultMaven
         }
     }
 
-    private void saveResumptionDataWhenApplicable( MavenExecutionResult result, MavenSession session )
+    private void persistResumptionData( MavenExecutionResult result, MavenSession session )
     {
         boolean hasLifecycleExecutionExceptions = result.getExceptions().stream()
                 .anyMatch( LifecycleExecutionException.class::isInstance );


[maven] 16/31: Rename resumptionDataStored to canResume

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 0936fd36780a52bf48039aafeecae0c55cdc2bfa
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Mon May 25 16:05:00 2020 +0200

    Rename resumptionDataStored to canResume
---
 maven-core/src/main/java/org/apache/maven/DefaultMaven.java    |  3 +--
 .../apache/maven/execution/DefaultMavenExecutionResult.java    | 10 +++++-----
 .../java/org/apache/maven/execution/MavenExecutionResult.java  | 10 +++++-----
 .../src/main/java/org/apache/maven/cli/MavenCli.java           |  2 +-
 4 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 9f6c56f..ffda19d 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -30,7 +30,6 @@ import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -378,7 +377,7 @@ public class DefaultMaven
                     {
                         if ( buildResumptionManager.persistResumptionData( result, rootProject ) )
                         {
-                            result.setResumptionDataStored();
+                            result.setCanResume();
                         }
                     } );
         }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
index f346b7f..ae87d5c 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
@@ -43,7 +43,7 @@ public class DefaultMavenExecutionResult
     private final Map<MavenProject, BuildSummary> buildSummaries =
         Collections.synchronizedMap( new IdentityHashMap<>() );
 
-    private boolean resumptionDataStored = false;
+    private boolean canResume = false;
 
     public MavenExecutionResult setProject( MavenProject project )
     {
@@ -112,14 +112,14 @@ public class DefaultMavenExecutionResult
     }
 
     @Override
-    public boolean isResumptionDataStored()
+    public boolean canResume()
     {
-        return resumptionDataStored;
+        return canResume;
     }
 
     @Override
-    public void setResumptionDataStored()
+    public void setCanResume()
     {
-        this.resumptionDataStored = true;
+        this.canResume = true;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
index 301d459..07a1eb8 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
@@ -69,16 +69,16 @@ public interface MavenExecutionResult
     void addBuildSummary( BuildSummary summary );
 
     /**
-     * Indicates whether or not resumption data has been stored.
+     * Indicates whether or not the build could be resumed by a second invocation of Maven.
      * @see org.apache.maven.execution.BuildResumptionManager
      * @return <code>true</code> when it is possible to resume the build, <code>false</code> otherwise.
      */
-    boolean isResumptionDataStored();
+    boolean canResume();
 
     /**
-     * Indicate that resumption data has been stored.
+     * Indicate that the build could be resumed by a second invocation of Maven.
      * @see org.apache.maven.execution.BuildResumptionManager
-     * @see #isResumptionDataStored()
+     * @see #canResume()
      */
-    void setResumptionDataStored();
+    void setCanResume();
 }
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 66b1fc8..ec3d2ad 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
@@ -1032,7 +1032,7 @@ public class MavenCli
             }
 
             List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
-            if ( result.isResumptionDataStored() )
+            if ( result.canResume() )
             {
                 logBuildResumeHint( "mvn <args> -r " );
             }


[maven] 25/31: Fixed checkstyle findings

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 4c94e2c378087c6b080cda9be4698b1f88e38ca2
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri Jun 5 21:38:02 2020 +0200

    Fixed checkstyle findings
---
 .../apache/maven/execution/BuildResumptionPersistenceException.java   | 4 +---
 .../src/main/java/org/apache/maven/execution/DefaultBuildResumer.java | 2 +-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
index fb9281b..2d2852f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
@@ -19,11 +19,9 @@ package org.apache.maven.execution;
  * under the License.
  */
 
-import org.apache.maven.project.MavenProject;
-
 /**
  * This exception will be thrown when something fails while persisting build resumption data.
- * @see BuildResumer#persistResumptionData(MavenExecutionResult, MavenProject)
+ * @see BuildResumer#persistResumptionData
  */
 public class BuildResumptionPersistenceException extends Exception
 {
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
index 21d99de..b5fb1b6 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
@@ -219,7 +219,7 @@ public class DefaultBuildResumer implements BuildResumer
         catch ( IOException e )
         {
             String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
-            throw new BuildResumptionPersistenceException( message, e);
+            throw new BuildResumptionPersistenceException( message, e );
         }
 
         return true;


[maven] 11/31: Removing the resumption data when a build succeeded.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit f994d9076b91ea4af78ac408d39784b793a445a2
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Sat May 23 08:29:11 2020 +0200

    Removing the resumption data when a build succeeded.
---
 maven-core/src/main/java/org/apache/maven/DefaultMaven.java |  7 +++++++
 .../org/apache/maven/execution/BuildResumptionManager.java  | 13 +++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 026f729..4907ac9 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -322,6 +322,13 @@ public class DefaultMaven
                 saveResumptionDataWhenApplicable( result, session );
                 return result;
             }
+            else
+            {
+                session.getAllProjects().stream()
+                        .filter( MavenProject::isExecutionRoot )
+                        .findFirst()
+                        .ifPresent( buildResumptionManager::removeResumptionData );
+            }
         }
         finally
         {
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
index 2e7e775..e0ab008 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
@@ -80,6 +80,19 @@ public class BuildResumptionManager
         applyResumptionProperties( request, properties );
     }
 
+    public void removeResumptionData( MavenProject rootProject )
+    {
+        Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
+        try
+        {
+            Files.deleteIfExists( resumeProperties );
+        }
+        catch ( IOException e )
+        {
+            logger.warn( "Could not delete " + RESUME_PROPERTIES_FILENAME + " file. ", e );
+        }
+    }
+
     /**
      * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case
      *   where multiple modules in the reactor have the same artifactId.


[maven] 03/31: Added JavaDoc to the method which determines whether a resume-from suggestion should be given or not.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit e4e89ff133c19e3e5cf3972ef4132b1524203f04
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri May 22 09:06:26 2020 +0200

    Added JavaDoc to the method which determines whether a resume-from suggestion should be given or not.
---
 .../main/java/org/apache/maven/cli/BuildResumptionManager.java    | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
index ecabc81..900699f 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
@@ -100,6 +100,14 @@ class BuildResumptionManager
                 .collect( Collectors.toList() );
     }
 
+    /**
+     * Determine the project where the next build can be resumed from.
+     * If the failed project is the first project of the build,
+     * it does not make sense to use --resume-from, so the result will be empty.
+     * @param result The result of the Maven build.
+     * @param failedProject The first failed project of the build.
+     * @return An optional containing the resume-from suggestion.
+     */
     private Optional<String> getResumeFrom( MavenExecutionResult result, MavenProject failedProject )
     {
         List<MavenProject> allSortedProjects = result.getTopologicallySortedProjects();


[maven] 17/31: Replace Plexus logger with SLF4J

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit cbc0ec983cc3a27866fe9aad13859964661c907d
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Mon May 25 17:26:30 2020 +0200

    Replace Plexus logger with SLF4J
---
 .../execution/DefaultBuildResumptionManager.java   | 24 ++++++++++------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
index 4b7831b..4a3f819 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
@@ -24,9 +24,9 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.logging.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 import java.io.IOException;
@@ -56,9 +56,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
     private static final String RESUME_FROM_PROPERTY = "resumeFrom";
     private static final String EXCLUDED_PROJECTS_PROPERTY = "excludedProjects";
     private static final String PROPERTY_DELIMITER = ", ";
-
-    @Inject
-    private Logger logger;
+    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionManager.class );
 
     @Override
     public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
@@ -67,7 +65,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
 
         if ( properties.isEmpty() )
         {
-            logger.debug( "Will not create " + RESUME_PROPERTIES_FILENAME + " file: nothing to resume from" );
+            LOGGER.debug( "Will not create {} file: nothing to resume from", RESUME_PROPERTIES_FILENAME );
             return false;
         }
 
@@ -91,7 +89,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         }
         catch ( IOException e )
         {
-            logger.warn( "Could not delete " + RESUME_PROPERTIES_FILENAME + " file. ", e );
+            LOGGER.warn( "Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e );
         }
     }
 
@@ -127,7 +125,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         }
         else
         {
-            logger.warn( "Could not create " + RESUME_PROPERTIES_FILENAME + " file: no failed projects found" );
+            LOGGER.warn( "Could not create {} file: no failed projects found", RESUME_PROPERTIES_FILENAME );
         }
 
         return properties;
@@ -219,7 +217,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         }
         catch ( IOException e )
         {
-            logger.warn( "Could not create " + RESUME_PROPERTIES_FILENAME + " file. ", e );
+            LOGGER.warn( "Could not create {} file. ", RESUME_PROPERTIES_FILENAME, e );
             return false;
         }
 
@@ -232,7 +230,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         Path path = Paths.get( RESUME_PROPERTIES_FILENAME ).resolve( rootBuildDirectory );
         if ( !Files.exists( path ) )
         {
-            logger.warn( "The " + path + " file does not exist. The --resume / -r feature will not work." );
+            LOGGER.warn( "The {} file does not exist. The --resume / -r feature will not work.", path );
             return properties;
         }
 
@@ -242,7 +240,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         }
         catch ( IOException e )
         {
-            logger.warn( "Unable to read " + path + ". The --resume / -r feature will not work." );
+            LOGGER.warn( "Unable to read {}. The --resume / -r feature will not work.", path );
         }
 
         return properties;
@@ -255,7 +253,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         {
             String propertyValue = properties.getProperty( RESUME_FROM_PROPERTY );
             request.setResumeFrom( propertyValue );
-            logger.info( "Resuming from " + propertyValue + " due to the --resume / -r feature." );
+            LOGGER.info( "Resuming from {} due to the --resume / -r feature.", propertyValue );
         }
 
         if ( properties.containsKey( EXCLUDED_PROJECTS_PROPERTY ) )
@@ -263,7 +261,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
             String propertyValue = properties.getProperty( EXCLUDED_PROJECTS_PROPERTY );
             String[] excludedProjects = propertyValue.split( PROPERTY_DELIMITER );
             request.getExcludedProjects().addAll( Arrays.asList( excludedProjects ) );
-            logger.info( "Additionally excluding projects '" + propertyValue + "' due to the --resume / -r feature." );
+            LOGGER.info( "Additionally excluding projects '{}' due to the --resume / -r feature.", propertyValue );
         }
     }
 


[maven] 15/31: Avoid stringly-typed method signatures

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit a5cbea999e6ddc2f735fc3ee8202e72858f6fd8a
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Mon May 25 15:45:57 2020 +0200

    Avoid stringly-typed method signatures
---
 .../org/apache/maven/execution/DefaultBuildResumptionManager.java   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
index d08478f..4b7831b 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
@@ -77,7 +77,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
     @Override
     public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
     {
-        Properties properties = loadResumptionFile( rootProject.getBuild().getDirectory() );
+        Properties properties = loadResumptionFile( Paths.get( rootProject.getBuild().getDirectory() ) );
         applyResumptionProperties( request, properties );
     }
 
@@ -226,10 +226,10 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         return true;
     }
 
-    private Properties loadResumptionFile( String rootBuildDirectory )
+    private Properties loadResumptionFile( Path rootBuildDirectory )
     {
         Properties properties = new Properties();
-        Path path = Paths.get( rootBuildDirectory, RESUME_PROPERTIES_FILENAME );
+        Path path = Paths.get( RESUME_PROPERTIES_FILENAME ).resolve( rootBuildDirectory );
         if ( !Files.exists( path ) )
         {
             logger.warn( "The " + path + " file does not exist. The --resume / -r feature will not work." );


[maven] 19/31: Renamed BuildResumptionManager to BuildResumer

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit ba630fc8087b3dfe49a131f7a7c201bdec6c01d0
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri Jun 5 20:44:15 2020 +0200

    Renamed BuildResumptionManager to BuildResumer
---
 .../main/java/org/apache/maven/DefaultMaven.java   |  8 +++----
 ...ildResumptionManager.java => BuildResumer.java} |  2 +-
 ...mptionManager.java => DefaultBuildResumer.java} |  6 ++---
 .../maven/execution/MavenExecutionResult.java      |  4 ++--
 .../apache/maven/graph/DefaultGraphBuilder.java    |  6 ++---
 ...nagerTest.java => DefaultBuildResumerTest.java} | 26 +++++++++++-----------
 .../main/java/org/apache/maven/cli/MavenCli.java   |  8 +++----
 7 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index ffda19d..3eb7544 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -36,7 +36,7 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.execution.BuildResumptionManager;
+import org.apache.maven.execution.BuildResumer;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -102,7 +102,7 @@ public class DefaultMaven
     private GraphBuilder graphBuilder;
 
     @Inject
-    private BuildResumptionManager buildResumptionManager;
+    private BuildResumer buildResumer;
 
     @Override
     public MavenExecutionResult execute( MavenExecutionRequest request )
@@ -326,7 +326,7 @@ public class DefaultMaven
                 session.getAllProjects().stream()
                         .filter( MavenProject::isExecutionRoot )
                         .findFirst()
-                        .ifPresent( buildResumptionManager::removeResumptionData );
+                        .ifPresent( buildResumer::removeResumptionData );
             }
         }
         finally
@@ -375,7 +375,7 @@ public class DefaultMaven
                     .findFirst()
                     .ifPresent( rootProject ->
                     {
-                        if ( buildResumptionManager.persistResumptionData( result, rootProject ) )
+                        if ( buildResumer.persistResumptionData( result, rootProject ) )
                         {
                             result.setCanResume();
                         }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
similarity index 98%
rename from maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
rename to maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
index f3d41aa..be85371 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
@@ -28,7 +28,7 @@ import java.util.List;
  * builds of the same project that have the -r command-line flag skip successfully built projects during earlier
  * invocations of Maven.
  */
-public interface BuildResumptionManager
+public interface BuildResumer
 {
     /**
      * Persists any data needed to resume the build at a later point in time, using a new Maven invocation. This method
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
similarity index 98%
rename from maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
rename to maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
index 9f7c944..7232365 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
@@ -45,18 +45,18 @@ import java.util.stream.Collectors;
 import static java.util.Comparator.comparing;
 
 /**
- * This implementation of {@link BuildResumptionManager} persists information in a properties file. The file is stored
+ * This implementation of {@link BuildResumer} persists information in a properties file. The file is stored
  * in the build output directory under the Maven execution root.
  */
 @Named
 @Singleton
-public class DefaultBuildResumptionManager implements BuildResumptionManager
+public class DefaultBuildResumer implements BuildResumer
 {
     private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
     private static final String RESUME_FROM_PROPERTY = "resumeFrom";
     private static final String EXCLUDED_PROJECTS_PROPERTY = "excludedProjects";
     private static final String PROPERTY_DELIMITER = ", ";
-    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionManager.class );
+    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumer.class );
 
     @Override
     public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
index 07a1eb8..7a86afb 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
@@ -70,14 +70,14 @@ public interface MavenExecutionResult
 
     /**
      * Indicates whether or not the build could be resumed by a second invocation of Maven.
-     * @see org.apache.maven.execution.BuildResumptionManager
+     * @see org.apache.maven.execution.BuildResumer
      * @return <code>true</code> when it is possible to resume the build, <code>false</code> otherwise.
      */
     boolean canResume();
 
     /**
      * Indicate that the build could be resumed by a second invocation of Maven.
-     * @see org.apache.maven.execution.BuildResumptionManager
+     * @see org.apache.maven.execution.BuildResumer
      * @see #canResume()
      */
     void setCanResume();
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 091cbaf..1d19c03 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -38,7 +38,7 @@ import org.apache.maven.DefaultMaven;
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.ProjectCycleException;
 import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.execution.BuildResumptionManager;
+import org.apache.maven.execution.BuildResumer;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
@@ -75,7 +75,7 @@ public class DefaultGraphBuilder
     protected ProjectBuilder projectBuilder;
 
     @Inject
-    private BuildResumptionManager buildResumptionManager;
+    private BuildResumer buildResumer;
 
     @Override
     public Result<ProjectDependencyGraph> build( MavenSession session )
@@ -354,7 +354,7 @@ public class DefaultGraphBuilder
                     .filter( MavenProject::isExecutionRoot )
                     .findFirst()
                     .ifPresent( rootProject ->
-                            buildResumptionManager.applyResumptionData( request, rootProject ) );
+                            buildResumer.applyResumptionData( request, rootProject ) );
         }
     }
 
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionManagerTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
similarity index 87%
rename from maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionManagerTest.java
rename to maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
index a0c913b..fe1348e 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionManagerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
@@ -40,13 +40,13 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
 
 @RunWith( MockitoJUnitRunner.class )
-public class DefaultBuildResumptionManagerTest
+public class DefaultBuildResumerTest
 {
     @Mock
     private Logger logger;
 
     @InjectMocks
-    private DefaultBuildResumptionManager buildResumptionManager;
+    private DefaultBuildResumer buildResumer;
 
     private MavenExecutionResult result;
 
@@ -62,7 +62,7 @@ public class DefaultBuildResumptionManagerTest
         MavenProject projectB = createFailedMavenProject( "B" );
         result.setTopologicallySortedProjects( asList( projectA, projectB ) );
 
-        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+        Properties properties = buildResumer.determineResumptionProperties( result );
 
         assertThat( properties.get( "resumeFrom" ), is( "test:B" ) );
     }
@@ -74,7 +74,7 @@ public class DefaultBuildResumptionManagerTest
         MavenProject projectB = createMavenProject( "B" );
         result.setTopologicallySortedProjects( asList( projectA, projectB ) );
 
-        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+        Properties properties = buildResumer.determineResumptionProperties( result );
 
         assertThat( properties.containsKey( "resumeFrom" ), is(false) );
     }
@@ -87,7 +87,7 @@ public class DefaultBuildResumptionManagerTest
         MavenProject projectC = createSucceededMavenProject( "C" );
         result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
 
-        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+        Properties properties = buildResumer.determineResumptionProperties( result );
 
         assertThat( properties.get( "excludedProjects" ), is("test:C") );
     }
@@ -101,7 +101,7 @@ public class DefaultBuildResumptionManagerTest
         projectC.setDependencies( singletonList( toDependency( projectB ) ) );
         result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
 
-        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+        Properties properties = buildResumer.determineResumptionProperties( result );
 
         assertThat( properties.containsKey( "excludedProjects" ), is(false) );
     }
@@ -115,7 +115,7 @@ public class DefaultBuildResumptionManagerTest
         MavenProject projectD = createFailedMavenProject( "D" );
         result.setTopologicallySortedProjects( asList( projectA, projectB, projectC, projectD ) );
 
-        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+        Properties properties = buildResumer.determineResumptionProperties( result );
 
         assertThat( properties.get( "resumeFrom" ), is("test:B") );
         assertThat( properties.get( "excludedProjects" ), is("test:C") );
@@ -129,7 +129,7 @@ public class DefaultBuildResumptionManagerTest
         MavenProject projectC = createSucceededMavenProject( "C" );
         result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
 
-        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+        Properties properties = buildResumer.determineResumptionProperties( result );
 
         assertThat( properties.get( "excludedProjects" ), is( "test:B, test:C" ) );
     }
@@ -141,7 +141,7 @@ public class DefaultBuildResumptionManagerTest
         Properties properties = new Properties();
         properties.setProperty( "resumeFrom", ":module-a" );
 
-        buildResumptionManager.applyResumptionProperties( request, properties );
+        buildResumer.applyResumptionProperties( request, properties );
 
         assertThat( request.getResumeFrom(), is( ":module-a" ) );
     }
@@ -154,7 +154,7 @@ public class DefaultBuildResumptionManagerTest
         Properties properties = new Properties();
         properties.setProperty( "resumeFrom", ":module-a" );
 
-        buildResumptionManager.applyResumptionProperties( request, properties );
+        buildResumer.applyResumptionProperties( request, properties );
 
         assertThat( request.getResumeFrom(), is( ":module-b" ) );
     }
@@ -169,7 +169,7 @@ public class DefaultBuildResumptionManagerTest
         Properties properties = new Properties();
         properties.setProperty( "excludedProjects", ":module-b, :module-c" );
 
-        buildResumptionManager.applyResumptionProperties( request, properties );
+        buildResumer.applyResumptionProperties( request, properties );
 
         assertThat( request.getExcludedProjects(), contains( ":module-a", ":module-b", ":module-c" ) );
     }
@@ -182,7 +182,7 @@ public class DefaultBuildResumptionManagerTest
                 createMavenProject( "group", "module-b" ) );
         MavenProject failedProject = allProjects.get( 0 );
 
-        String selector = buildResumptionManager.getResumeFromSelector( allProjects, failedProject );
+        String selector = buildResumer.getResumeFromSelector( allProjects, failedProject );
 
         assertThat( selector, is( ":module-a" ) );
     }
@@ -195,7 +195,7 @@ public class DefaultBuildResumptionManagerTest
                 createMavenProject( "group-b", "module" ) );
         MavenProject failedProject = allProjects.get( 0 );
 
-        String selector = buildResumptionManager.getResumeFromSelector( allProjects, failedProject );
+        String selector = buildResumer.getResumeFromSelector( allProjects, failedProject );
 
         assertThat( selector, is( "group-a:module" ) );
     }
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 ec3d2ad..7778a06 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
@@ -48,7 +48,7 @@ import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.exception.DefaultExceptionHandler;
 import org.apache.maven.exception.ExceptionHandler;
 import org.apache.maven.exception.ExceptionSummary;
-import org.apache.maven.execution.BuildResumptionManager;
+import org.apache.maven.execution.BuildResumer;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.ExecutionListener;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -169,7 +169,7 @@ public class MavenCli
 
     private Map<String, ConfigurationProcessor> configurationProcessors;
 
-    private BuildResumptionManager buildResumptionManager;
+    private BuildResumer buildResumer;
 
     public MavenCli()
     {
@@ -708,7 +708,7 @@ public class MavenCli
 
         dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
 
-        buildResumptionManager = container.lookup( BuildResumptionManager.class );
+        buildResumer = container.lookup( BuildResumer.class );
 
         return container;
     }
@@ -1038,7 +1038,7 @@ public class MavenCli
             }
             else if ( project != null && !project.equals( sortedProjects.get( 0 ) ) )
             {
-                String resumeFromSelector = buildResumptionManager.getResumeFromSelector( sortedProjects, project );
+                String resumeFromSelector = buildResumer.getResumeFromSelector( sortedProjects, project );
                 logBuildResumeHint( "mvn <args> -rf " + resumeFromSelector );
             }
 


[maven] 20/31: Removed an unused mock for the plexus Logger, which is a leftover after moving to slf4j.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 823286173c6786be4604750d5e8ea75e8ee351a3
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri Jun 5 20:45:40 2020 +0200

    Removed an unused mock for the plexus Logger, which is a leftover after moving to slf4j.
---
 .../org/apache/maven/execution/DefaultBuildResumerTest.java  | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
index fe1348e..d2dd9ee 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
@@ -22,12 +22,9 @@ package org.apache.maven.execution;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.logging.Logger;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
@@ -37,16 +34,13 @@ import java.util.Properties;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.is;
 
 @RunWith( MockitoJUnitRunner.class )
 public class DefaultBuildResumerTest
 {
-    @Mock
-    private Logger logger;
-
-    @InjectMocks
-    private DefaultBuildResumer buildResumer;
+    private final DefaultBuildResumer buildResumer = new DefaultBuildResumer();
 
     private MavenExecutionResult result;
 


[maven] 05/31: When -r is given, load resume.properties and apply it to the execution request.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 25e8d807d33ab70373f9b76385cac6e544b21117
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri May 22 15:04:38 2020 +0200

    When -r is given, load resume.properties and apply it to the execution request.
---
 .../maven/execution}/BuildResumptionManager.java   | 128 +++++++++++++++------
 .../execution/DefaultMavenExecutionRequest.java    |  16 +++
 .../maven/execution/MavenExecutionRequest.java     |  11 ++
 .../apache/maven/graph/DefaultGraphBuilder.java    |  17 +++
 .../execution}/BuildResumptionManagerTest.java     |  60 +++++++++-
 .../main/java/org/apache/maven/cli/CLIManager.java |   3 +
 .../main/java/org/apache/maven/cli/MavenCli.java   |   8 +-
 7 files changed, 202 insertions(+), 41 deletions(-)

diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
similarity index 74%
rename from maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
rename to maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
index 900699f..0f6bf39 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
@@ -1,4 +1,4 @@
-package org.apache.maven.cli;
+package org.apache.maven.execution;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -21,7 +21,6 @@ package org.apache.maven.cli;
 
 import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
@@ -31,10 +30,12 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 import java.io.IOException;
+import java.io.Reader;
 import java.io.Writer;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -43,16 +44,24 @@ import java.util.stream.Collectors;
 
 import static java.util.Comparator.comparing;
 
+/**
+ * This class contains most of the logic needed for the --resume / -r feature.
+ * It persists information in a properties file to ensure newer builds, using the -r feature,
+ *   skip successfully built projects.
+ */
 @Named
 @Singleton
-class BuildResumptionManager
+public class BuildResumptionManager
 {
     private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
+    private static final String RESUME_FROM_PROPERTY = "resumeFrom";
+    private static final String EXCLUDED_PROJECTS_PROPERTY = "excludedProjects";
+    private static final String PROPERTY_DELIMITER = ", ";
 
     @Inject
     private Logger logger;
-
-    public boolean createResumptionFile( MavenExecutionResult result )
+    
+    public boolean persistResumptionData( MavenExecutionResult result )
     {
         Properties properties = determineResumptionProperties( result );
 
@@ -65,6 +74,42 @@ class BuildResumptionManager
         return writeResumptionFile( result, properties );
     }
 
+    public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
+    {
+        Properties properties = loadResumptionFile( rootProject.getBuild().getDirectory() );
+        applyResumptionProperties( request, properties );
+    }
+
+    /**
+     * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case
+     *   where multiple modules in the reactor have the same artifactId.
+     * <p>
+     * {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the reactor
+     *   have the same artifactId, effective failed module might be later in build reactor.
+     * This means that developer will either have to type groupId or wait for build execution of all modules which
+     *   were fine, but they are still before one which reported errors.
+     * <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
+     * {@code :artifactId} if there is no conflict.
+     *
+     * @param mavenProjects Maven projects which are part of build execution.
+     * @param failedProject 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).
+     */
+    public String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject failedProject )
+    {
+        boolean hasOverlappingArtifactId = mavenProjects.stream()
+                .filter( project -> failedProject.getArtifactId().equals( project.getArtifactId() ) )
+                .count() > 1;
+
+        if ( hasOverlappingArtifactId )
+        {
+            return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
+        }
+
+        return ":" + failedProject.getArtifactId();
+    }
+
     @VisibleForTesting
     Properties determineResumptionProperties( MavenExecutionResult result )
     {
@@ -77,8 +122,8 @@ class BuildResumptionManager
             Optional<String> resumeFrom = getResumeFrom( result, resumeFromProject );
             Optional<String> projectsToSkip = determineProjectsToSkip( result, failedProjects, resumeFromProject );
 
-            resumeFrom.ifPresent( value -> properties.setProperty( "resumeFrom", value ) );
-            projectsToSkip.ifPresent( value -> properties.setProperty( "excludedProjects", value ) );
+            resumeFrom.ifPresent( value -> properties.setProperty( RESUME_FROM_PROPERTY, value ) );
+            projectsToSkip.ifPresent( value -> properties.setProperty( EXCLUDED_PROJECTS_PROPERTY, value ) );
         }
         else
         {
@@ -144,7 +189,7 @@ class BuildResumptionManager
                 .filter( project -> result.getBuildSummary( project ) != null )
                 .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
                 .map( project -> String.format( "%s:%s", project.getGroupId(), project.getArtifactId() ) )
-                .collect( Collectors.joining( ", " ) );
+                .collect( Collectors.joining( PROPERTY_DELIMITER ) );
 
         if ( !StringUtils.isEmpty( projectsToSkip ) )
         {
@@ -161,32 +206,6 @@ class BuildResumptionManager
                 .noneMatch( projectsGAs::contains );
     }
 
-    /**
-     * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case where multiple modules in the reactor have the same artifactId.
-     * <p>
-     * {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the reactor have the same artifactId, effective failed module might be later in build reactor.
-     * This means that developer will either have to type groupId or wait for build execution of all modules which were fine, but they are still before one which reported errors.
-     * <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
-     * {@code :artifactId} if there is no conflict.
-     *
-     * @param mavenProjects Maven projects which are part of build execution.
-     * @param failedProject 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).
-     */
-    public String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject failedProject )
-    {
-        boolean hasOverlappingArtifactId = mavenProjects.stream()
-                .filter( project -> failedProject.getArtifactId().equals( project.getArtifactId() ) )
-                .count() > 1;
-
-        if ( hasOverlappingArtifactId )
-        {
-            return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
-        }
-
-        return ":" + failedProject.getArtifactId();
-    }
-
     private boolean writeResumptionFile( MavenExecutionResult result, Properties properties )
     {
         Path resumeProperties = Paths.get( result.getProject().getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
@@ -207,6 +226,47 @@ class BuildResumptionManager
         return true;
     }
 
+    private Properties loadResumptionFile( String rootBuildDirectory )
+    {
+        Properties properties = new Properties();
+        Path path = Paths.get( rootBuildDirectory, RESUME_PROPERTIES_FILENAME );
+        if ( !Files.exists( path ) )
+        {
+            logger.warn( "The " + path + " file does not exist. The --resume / -r feature will not work." );
+            return properties;
+        }
+
+        try ( Reader reader = Files.newBufferedReader( path ) )
+        {
+            properties.load( reader );
+        }
+        catch ( IOException e )
+        {
+            logger.warn( "Unable to read " + path + ". The --resume / -r feature will not work." );
+        }
+
+        return properties;
+    }
+
+    @VisibleForTesting
+    void applyResumptionProperties( MavenExecutionRequest request, Properties properties )
+    {
+        if ( properties.containsKey( RESUME_FROM_PROPERTY ) && StringUtils.isEmpty( request.getResumeFrom() ) )
+        {
+            String propertyValue = properties.getProperty( RESUME_FROM_PROPERTY );
+            request.setResumeFrom( propertyValue );
+            logger.info( "Resuming from " + propertyValue + " due to the --resume / -r feature." );
+        }
+
+        if ( properties.containsKey( EXCLUDED_PROJECTS_PROPERTY ) )
+        {
+            String propertyValue = properties.getProperty( EXCLUDED_PROJECTS_PROPERTY );
+            String[] excludedProjects = propertyValue.split( PROPERTY_DELIMITER );
+            request.getExcludedProjects().addAll( Arrays.asList( excludedProjects ) );
+            logger.info( "Additionally excluding projects '" + propertyValue + "' due to the --resume / -r feature." );
+        }
+    }
+
     private static class GroupArtifactPair
     {
         private final String groupId;
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
index 4a039eb..9cbdebe 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
@@ -116,6 +116,8 @@ public class DefaultMavenExecutionRequest
 
     private List<String> excludedProjects;
 
+    private boolean resume = false;
+
     private String resumeFrom;
 
     private String makeBehavior;
@@ -301,6 +303,12 @@ public class DefaultMavenExecutionRequest
     }
 
     @Override
+    public boolean isResume()
+    {
+        return resume;
+    }
+
+    @Override
     public String getResumeFrom()
     {
         return resumeFrom;
@@ -599,6 +607,14 @@ public class DefaultMavenExecutionRequest
     }
 
     @Override
+    public MavenExecutionRequest setResume()
+    {
+        resume = true;
+
+        return this;
+    }
+
+    @Override
     public MavenExecutionRequest setResumeFrom( String project )
     {
         this.resumeFrom = project;
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
index d006a43..542c34a 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
@@ -171,6 +171,17 @@ public interface MavenExecutionRequest
      */
     List<String> getExcludedProjects();
 
+    /**
+     * Sets whether the build should be resumed from the data in the resume.properties file.
+     * @return This request, never {@code null}.
+     */
+    MavenExecutionRequest setResume();
+
+    /**
+     * @return Whether the build should be resumed from the data in the resume.properties file.
+     */
+    boolean isResume();
+
     MavenExecutionRequest setResumeFrom( String project );
 
     String getResumeFrom();
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 99f0266..091cbaf 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -38,6 +38,7 @@ import org.apache.maven.DefaultMaven;
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.ProjectCycleException;
 import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.execution.BuildResumptionManager;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
@@ -73,6 +74,9 @@ public class DefaultGraphBuilder
     @Inject
     protected ProjectBuilder projectBuilder;
 
+    @Inject
+    private BuildResumptionManager buildResumptionManager;
+
     @Override
     public Result<ProjectDependencyGraph> build( MavenSession session )
     {
@@ -84,6 +88,7 @@ public class DefaultGraphBuilder
             {
                 final List<MavenProject> projects = getProjectsForMavenReactor( session );
                 validateProjects( projects );
+                enrichRequestFromResumptionData( projects, session.getRequest() );
                 result = reactorDependencyGraph( session, projects );
             }
 
@@ -341,6 +346,18 @@ public class DefaultGraphBuilder
         return result;
     }
 
+    private void enrichRequestFromResumptionData( List<MavenProject> projects, MavenExecutionRequest request )
+    {
+        if ( request.isResume() )
+        {
+            projects.stream()
+                    .filter( MavenProject::isExecutionRoot )
+                    .findFirst()
+                    .ifPresent( rootProject ->
+                            buildResumptionManager.applyResumptionData( request, rootProject ) );
+        }
+    }
+
     private String formatProjects( List<MavenProject> projects )
     {
         StringBuilder projectNames = new StringBuilder();
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java b/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
similarity index 72%
rename from maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java
rename to maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
index 5958c80..95a0375 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.cli;
+package org.apache.maven.execution;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,16 +19,19 @@ package org.apache.maven.cli;
  * under the License.
  */
 
-import org.apache.maven.execution.BuildFailure;
-import org.apache.maven.execution.BuildSuccess;
-import org.apache.maven.execution.DefaultMavenExecutionResult;
-import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.logging.Logger;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 
 import static java.util.Arrays.asList;
@@ -36,9 +39,14 @@ import static java.util.Collections.singletonList;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
 
+@RunWith( MockitoJUnitRunner.class )
 public class BuildResumptionManagerTest
 {
-    private final BuildResumptionManager buildResumptionManager = new BuildResumptionManager();
+    @Mock
+    private Logger logger;
+
+    @InjectMocks
+    private BuildResumptionManager buildResumptionManager;
 
     private MavenExecutionResult result;
 
@@ -111,6 +119,46 @@ public class BuildResumptionManagerTest
         assertThat( properties.get( "excludedProjects" ), is( "test:B, test:C" ) );
     }
 
+    @Test
+    public void resumeFromPropertyGetsApplied()
+    {
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        Properties properties = new Properties();
+        properties.setProperty( "resumeFrom", ":module-a" );
+
+        buildResumptionManager.applyResumptionProperties( request, properties );
+
+        assertThat( request.getResumeFrom(), is( ":module-a" ) );
+    }
+
+    @Test
+    public void resumeFromPropertyDoesNotOverrideExistingRequestParameters()
+    {
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setResumeFrom( ":module-b" );
+        Properties properties = new Properties();
+        properties.setProperty( "resumeFrom", ":module-a" );
+
+        buildResumptionManager.applyResumptionProperties( request, properties );
+
+        assertThat( request.getResumeFrom(), is( ":module-b" ) );
+    }
+
+    @Test
+    public void excludedProjectsFromPropertyGetsAddedToExistingRequestParameters()
+    {
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        List<String> excludedProjects = new ArrayList<>();
+        excludedProjects.add( ":module-a" );
+        request.setExcludedProjects( excludedProjects );
+        Properties properties = new Properties();
+        properties.setProperty( "excludedProjects", ":module-b, :module-c" );
+
+        buildResumptionManager.applyResumptionProperties( request, properties );
+
+        assertThat( request.getExcludedProjects(), contains( ":module-a", ":module-b", ":module-c" ) );
+    }
+
     private MavenProject createMavenProject( String artifactId )
     {
         MavenProject project = new MavenProject();
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
index c9e002a..873fc97 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
@@ -83,6 +83,8 @@ public class CLIManager
 
     public static final String FAIL_NEVER = "fn";
 
+    public static final String RESUME = "r";
+
     public static final String RESUME_FROM = "rf";
 
     public static final String PROJECT_LIST = "pl";
@@ -134,6 +136,7 @@ public class CLIManager
         options.addOption( Option.builder( FAIL_FAST ).longOpt( "fail-fast" ).desc( "Stop at first failure in reactorized builds" ).build() );
         options.addOption( Option.builder( FAIL_AT_END ).longOpt( "fail-at-end" ).desc( "Only fail the build afterwards; allow all non-impacted builds to continue" ).build() );
         options.addOption( Option.builder( FAIL_NEVER ).longOpt( "fail-never" ).desc( "NEVER fail the build, regardless of project result" ).build() );
+        options.addOption( Option.builder( RESUME ).longOpt( "resume" ).desc( "Resume reactor from the last failed project, using the resume.properties file in the build directory " ).build() );
         options.addOption( Option.builder( RESUME_FROM ).longOpt( "resume-from" ).hasArg().desc( "Resume reactor from specified project" ).build() );
         options.addOption( Option.builder( PROJECT_LIST ).longOpt( "projects" ).desc( "Comma-delimited list of specified reactor projects to build instead of all projects. A project can be specified by [groupId]:artifactId or by its relative path" ).hasArg().build() );
         options.addOption( Option.builder( ALSO_MAKE ).longOpt( "also-make" ).desc( "If project list is specified, also build projects required by the list" ).build() );
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 9dd127a..4ecd095 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
@@ -48,6 +48,7 @@ import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.exception.DefaultExceptionHandler;
 import org.apache.maven.exception.ExceptionHandler;
 import org.apache.maven.exception.ExceptionSummary;
+import org.apache.maven.execution.BuildResumptionManager;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.ExecutionListener;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -1029,7 +1030,7 @@ public class MavenCli
                 }
             }
 
-            boolean resumeFileCreated = buildResumptionManager.createResumptionFile( result );
+            boolean resumeFileCreated = buildResumptionManager.persistResumptionData( result );
 
             slf4jLogger.error( "" );
             slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
@@ -1528,6 +1529,11 @@ public class MavenCli
             request.setBaseDirectory( request.getPom().getParentFile() );
         }
 
+        if ( commandLine.hasOption( CLIManager.RESUME ) )
+        {
+            request.setResume();
+        }
+
         if ( commandLine.hasOption( CLIManager.RESUME_FROM ) )
         {
             request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );


[maven] 01/31: When a build fails, write file with properties to resume the next build from.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 556bcca55753159b6e54ae9b777d8d15d28de692
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Mon May 4 15:39:41 2020 +0200

    When a build fails, write file with properties to resume the next build from.
---
 .../apache/maven/cli/BuildResumptionManager.java   | 238 +++++++++++++++++++++
 .../main/java/org/apache/maven/cli/MavenCli.java   |  22 +-
 .../maven/cli/BuildResumptionManagerTest.java      | 126 +++++++++++
 3 files changed, 381 insertions(+), 5 deletions(-)

diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
new file mode 100644
index 0000000..7820c0a
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
@@ -0,0 +1,238 @@
+package org.apache.maven.cli;
+
+/*
+ * 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.
+ */
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.logging.Logger;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.comparing;
+
+@Named
+@Singleton
+class BuildResumptionManager
+{
+    private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
+
+    @Inject
+    private Logger logger;
+
+    public boolean createResumptionFile( MavenExecutionResult result )
+    {
+        Properties properties = determineResumptionProperties( result );
+
+        if ( properties.isEmpty() )
+        {
+            logger.debug( "Will not create " + RESUME_PROPERTIES_FILENAME + " file: nothing to resume from" );
+            return false;
+        }
+
+        return writeResumptionFile( result, properties );
+    }
+
+    @VisibleForTesting
+    Properties determineResumptionProperties( MavenExecutionResult result )
+    {
+        Properties properties = new Properties();
+
+        List<MavenProject> failedProjects = getFailedProjectsInOrder( result );
+        if ( !failedProjects.isEmpty() )
+        {
+            MavenProject resumeFromProject = failedProjects.get( 0 );
+            Optional<String> resumeFrom = getResumeFrom( result, resumeFromProject );
+            Optional<String> projectsToSkip = determineProjectsToSkip( result, failedProjects, resumeFromProject );
+
+            resumeFrom.ifPresent( value -> properties.setProperty( "resumeFrom", value ) );
+            projectsToSkip.ifPresent( value -> properties.setProperty( "excludedProjects", value ) );
+        }
+        else
+        {
+            logger.warn( "Could not create " + RESUME_PROPERTIES_FILENAME + " file: no failed projects found" );
+        }
+
+        return properties;
+    }
+
+    private List<MavenProject> getFailedProjectsInOrder( MavenExecutionResult result )
+    {
+        List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
+
+        return result.getExceptions().stream()
+                .filter( LifecycleExecutionException.class::isInstance )
+                .map( LifecycleExecutionException.class::cast )
+                .map( LifecycleExecutionException::getProject )
+                .sorted( comparing( sortedProjects::indexOf ) )
+                .collect( Collectors.toList() );
+    }
+
+    private Optional<String> getResumeFrom( MavenExecutionResult result, MavenProject failedProject )
+    {
+        List<MavenProject> allSortedProjects = result.getTopologicallySortedProjects();
+        if ( !allSortedProjects.get( 0 ).equals( failedProject ) )
+        {
+            return Optional.of( String.format( "%s:%s", failedProject.getGroupId(), failedProject.getArtifactId() ) );
+        }
+
+        return Optional.empty();
+    }
+
+    /**
+     * Projects after the first failed project could have succeeded by using -T or --fail-at-end.
+     * These projects can be skipped from later builds.
+     * This is not the case these projects are dependent on one of the failed projects.
+     * @param result The result of the Maven build.
+     * @param failedProjects The list of failed projects in the build.
+     * @param resumeFromProject The project where the build will be resumed with in the next run.
+     * @return An optional containing a comma separated list of projects which can be skipped,
+     *   or an empty optional if no projects can be skipped.
+     */
+    private Optional<String> determineProjectsToSkip( MavenExecutionResult result, List<MavenProject> failedProjects,
+                                                      MavenProject resumeFromProject )
+    {
+        List<MavenProject> allProjects = result.getTopologicallySortedProjects();
+        int resumeFromProjectIndex = allProjects.indexOf( resumeFromProject );
+        List<MavenProject> remainingProjects = allProjects.subList( resumeFromProjectIndex + 1, allProjects.size() );
+
+        List<GroupArtifactPair> failedProjectsGAList = failedProjects.stream()
+                .map( GroupArtifactPair::new )
+                .collect( Collectors.toList() );
+
+        String projectsToSkip = remainingProjects.stream()
+                .filter( project -> result.getBuildSummary( project ) != null )
+                .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
+                .map( project -> String.format( "%s:%s", project.getGroupId(), project.getArtifactId() ) )
+                .collect( Collectors.joining( ", " ) );
+
+        if ( !StringUtils.isEmpty( projectsToSkip ) )
+        {
+            return Optional.of( projectsToSkip );
+        }
+
+        return Optional.empty();
+    }
+
+    private boolean hasNoDependencyOnProjects( MavenProject project, List<GroupArtifactPair> projectsGAs )
+    {
+        return project.getDependencies().stream()
+                .map( GroupArtifactPair::new )
+                .noneMatch( projectsGAs::contains );
+    }
+
+    /**
+     * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case where multiple modules in the reactor have the same artifactId.
+     * <p>
+     * {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the reactor have the same artifactId, effective failed module might be later in build reactor.
+     * This means that developer will either have to type groupId or wait for build execution of all modules which were fine, but they are still before one which reported errors.
+     * <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
+     * {@code :artifactId} if there is no conflict.
+     *
+     * @param mavenProjects Maven projects which are part of build execution.
+     * @param failedProject 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).
+     */
+    public String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject failedProject )
+    {
+        for ( MavenProject buildProject : mavenProjects )
+        {
+            if ( failedProject.getArtifactId().equals( buildProject.getArtifactId() ) && !failedProject.equals( buildProject ) )
+            {
+                return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
+            }
+        }
+        return ":" + failedProject.getArtifactId();
+    }
+
+    private boolean writeResumptionFile( MavenExecutionResult result, Properties properties )
+    {
+        Path resumeProperties = Paths.get( result.getProject().getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
+        try
+        {
+            Files.createDirectories( resumeProperties.getParent() );
+            try ( Writer writer = Files.newBufferedWriter( resumeProperties ) )
+            {
+                properties.store( writer, null );
+            }
+        }
+        catch ( IOException e )
+        {
+            logger.warn( "Could not create " + RESUME_PROPERTIES_FILENAME + " file. ", e );
+            return false;
+        }
+
+        return true;
+    }
+
+    private static class GroupArtifactPair
+    {
+        private final String groupId;
+        private final String artifactId;
+
+        GroupArtifactPair( MavenProject project )
+        {
+            this.groupId = project.getGroupId();
+            this.artifactId = project.getArtifactId();
+        }
+
+        GroupArtifactPair( Dependency dependency )
+        {
+            this.groupId = dependency.getGroupId();
+            this.artifactId = dependency.getArtifactId();
+        }
+
+        @Override
+        public boolean equals( Object o )
+        {
+            if ( this == o )
+            {
+                return true;
+            }
+            if ( o == null || getClass() != o.getClass() )
+            {
+                return false;
+            }
+            GroupArtifactPair that = (GroupArtifactPair) o;
+            return Objects.equals( groupId, that.groupId ) && Objects.equals( artifactId, that.artifactId );
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return Objects.hash( groupId, artifactId );
+        }
+    }
+}
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 cbdf47f..9dd127a 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
@@ -168,6 +168,8 @@ public class MavenCli
 
     private Map<String, ConfigurationProcessor> configurationProcessors;
 
+    private BuildResumptionManager buildResumptionManager;
+
     public MavenCli()
     {
         this( null );
@@ -705,6 +707,8 @@ public class MavenCli
 
         dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
 
+        buildResumptionManager = container.lookup( BuildResumptionManager.class );
+
         return container;
     }
 
@@ -1025,12 +1029,20 @@ public class MavenCli
                 }
             }
 
-            if ( project != null && !project.equals( result.getTopologicallySortedProjects().get( 0 ) ) )
+            boolean resumeFileCreated = buildResumptionManager.createResumptionFile( result );
+
+            slf4jLogger.error( "" );
+            slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
+
+            List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
+            if ( resumeFileCreated )
             {
-                slf4jLogger.error( "" );
-                slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
-                slf4jLogger.error( buffer().a( "  " ).strong( "mvn <args> -rf "
-                    + getResumeFrom( result.getTopologicallySortedProjects(), project ) ).toString() );
+                slf4jLogger.error( buffer().a( "  " ).strong( "mvn <args> -r " ).toString() );
+            }
+            else if ( project != null && !project.equals( sortedProjects.get( 0 ) ) )
+            {
+                String resumeFromSelector = buildResumptionManager.getResumeFromSelector( sortedProjects, project );
+                slf4jLogger.error( buffer().a( "  " ).strong( "mvn <args> -rf " + resumeFromSelector ).toString() );
             }
 
             if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java
new file mode 100644
index 0000000..a70da32
--- /dev/null
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java
@@ -0,0 +1,126 @@
+package org.apache.maven.cli;
+
+import org.apache.maven.execution.BuildFailure;
+import org.apache.maven.execution.BuildSuccess;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+public class BuildResumptionManagerTest
+{
+    private final BuildResumptionManager buildResumptionManager = new BuildResumptionManager();
+
+    private MavenExecutionResult result;
+
+    @Before
+    public void before() {
+        result = new DefaultMavenExecutionResult();
+    }
+
+    @Test
+    public void resumeFromGetsDetermined()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        result.setTopologicallySortedProjects( asList( projectA, projectB ) );
+
+        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+
+        assertThat( properties.get( "resumeFrom" ), is( "test:B" ) );
+    }
+
+    @Test
+    public void resumeFromIsIgnoredWhenFirstProjectFails()
+    {
+        MavenProject projectA = createFailedMavenProject( "A" );
+        MavenProject projectB = createMavenProject( "B" );
+        result.setTopologicallySortedProjects( asList( projectA, projectB ) );
+
+        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+
+        assertThat( properties.containsKey( "resumeFrom" ), is(false) );
+    }
+
+    @Test
+    public void projectsSucceedingAfterFailedProjectsAreExcluded()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        MavenProject projectC = createSucceededMavenProject( "C" );
+        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
+
+        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+
+        assertThat( properties.get( "excludedProjects" ), is("test:C") );
+    }
+
+    @Test
+    public void projectsDependingOnFailedProjectsAreNotExcluded()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        MavenProject projectC = createSucceededMavenProject( "C" );
+        projectC.setDependencies( singletonList( toDependency( projectB ) ) );
+        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
+
+        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+
+        assertThat( properties.containsKey( "excludedProjects" ), is(false) );
+    }
+
+    @Test
+    public void multipleExcludedProjectsAreCommaSeparated()
+    {
+        MavenProject projectA = createFailedMavenProject( "A" );
+        MavenProject projectB = createSucceededMavenProject( "B" );
+        MavenProject projectC = createSucceededMavenProject( "C" );
+        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
+
+        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+
+        assertThat( properties.get( "excludedProjects" ), is( "test:B, test:C" ) );
+    }
+
+    private MavenProject createMavenProject( String artifactId )
+    {
+        MavenProject project = new MavenProject();
+        project.setGroupId( "test" );
+        project.setArtifactId( artifactId );
+        return project;
+    }
+
+    private Dependency toDependency( MavenProject mavenProject )
+    {
+        Dependency dependency = new Dependency();
+        dependency.setGroupId( mavenProject.getGroupId() );
+        dependency.setArtifactId( mavenProject.getArtifactId() );
+        dependency.setVersion( mavenProject.getVersion() );
+        return dependency;
+    }
+
+    private MavenProject createSucceededMavenProject( String artifactId )
+    {
+        MavenProject project = createMavenProject( artifactId );
+        result.addBuildSummary( new BuildSuccess( project, 0 ) );
+        return project;
+    }
+
+    private MavenProject createFailedMavenProject( String artifactId )
+    {
+        MavenProject project = createMavenProject( artifactId );
+        result.addBuildSummary( new BuildFailure( project, 0, new Exception() ) );
+        result.addException( new LifecycleExecutionException( "", project ) );
+        return project;
+    }
+}


[maven] 10/31: Refactored to call the resumption manager from the DefaultMaven instead of the CLI. As DefaultMaven has the right info to determine the execution root.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit df606590141756018ebca1e4000207e986d705ce
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Sat May 23 08:27:50 2020 +0200

    Refactored to call the resumption manager from the DefaultMaven instead of the CLI. As DefaultMaven has the right info to determine the execution root.
---
 .../main/java/org/apache/maven/DefaultMaven.java   | 30 +++++++++++++++++++++-
 .../maven/execution/BuildResumptionManager.java    |  8 +++---
 .../lifecycle/LifecycleExecutionException.java     | 12 +++++++++
 .../main/java/org/apache/maven/cli/MavenCli.java   |  9 ++++---
 4 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index fc26290..026f729 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -30,12 +30,14 @@ import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.execution.BuildResumptionManager;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -44,6 +46,7 @@ import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.graph.GraphBuilder;
 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
 import org.apache.maven.lifecycle.internal.LifecycleStarter;
 import org.apache.maven.model.Prerequisites;
@@ -99,6 +102,9 @@ public class DefaultMaven
     @Named( GraphBuilder.HINT )
     private GraphBuilder graphBuilder;
 
+    @Inject
+    private BuildResumptionManager buildResumptionManager;
+
     @Override
     public MavenExecutionResult execute( MavenExecutionRequest request )
     {
@@ -312,7 +318,9 @@ public class DefaultMaven
 
             if ( session.getResult().hasExceptions() )
             {
-                return addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) );
+                addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) );
+                saveResumptionDataWhenApplicable( result, session );
+                return result;
             }
         }
         finally
@@ -349,6 +357,26 @@ public class DefaultMaven
         }
     }
 
+    private void saveResumptionDataWhenApplicable( MavenExecutionResult result, MavenSession session )
+    {
+        List<LifecycleExecutionException> lifecycleExecutionExceptions = result.getExceptions().stream()
+                .filter( LifecycleExecutionException.class::isInstance )
+                .map( LifecycleExecutionException.class::cast )
+                .collect( Collectors.toList() );
+
+        if ( !lifecycleExecutionExceptions.isEmpty() )
+        {
+            session.getAllProjects().stream()
+                    .filter( MavenProject::isExecutionRoot )
+                    .findFirst()
+                    .ifPresent( rootProject ->
+                    {
+                        boolean persisted = buildResumptionManager.persistResumptionData( result, rootProject );
+                        lifecycleExecutionExceptions.forEach( e -> e.setBuildResumptionDataSaved( persisted ) );
+                    } );
+        }
+    }
+
     public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
     {
         return repositorySessionFactory.newRepositorySession( request );
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
index 0fb22e4..2e7e775 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
@@ -61,7 +61,7 @@ public class BuildResumptionManager
     @Inject
     private Logger logger;
     
-    public boolean persistResumptionData( MavenExecutionResult result )
+    public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
     {
         Properties properties = determineResumptionProperties( result );
 
@@ -71,7 +71,7 @@ public class BuildResumptionManager
             return false;
         }
 
-        return writeResumptionFile( result, properties );
+        return writeResumptionFile( rootProject, properties );
     }
 
     public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
@@ -206,9 +206,9 @@ public class BuildResumptionManager
                 .noneMatch( projectsGAs::contains );
     }
 
-    private boolean writeResumptionFile( MavenExecutionResult result, Properties properties )
+    private boolean writeResumptionFile( MavenProject rootProject, Properties properties )
     {
-        Path resumeProperties = Paths.get( result.getProject().getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
+        Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
         try
         {
             Files.createDirectories( resumeProperties.getParent() );
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
index 0831a4f..af9821a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
@@ -33,6 +33,8 @@ public class LifecycleExecutionException
 {
     private MavenProject project;
 
+    private boolean buildResumptionDataSaved = false;
+
     public LifecycleExecutionException( String message )
     {
         super( message );
@@ -76,6 +78,16 @@ public class LifecycleExecutionException
         return project;
     }
 
+    public boolean isBuildResumptionDataSaved()
+    {
+        return buildResumptionDataSaved;
+    }
+
+    public void setBuildResumptionDataSaved( boolean isBuildResumptionDataSaved )
+    {
+        this.buildResumptionDataSaved = isBuildResumptionDataSaved;
+    }
+
     private static String createMessage( MojoExecution execution, MavenProject project, Throwable cause )
     {
         MessageBuilder buffer = buffer( 256 );
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 113af25..657dfe0 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
@@ -992,6 +992,7 @@ public class MavenCli
             Map<String, String> references = new LinkedHashMap<>();
 
             MavenProject project = null;
+            boolean isResumptionDataSaved = false;
 
             for ( Throwable exception : result.getExceptions() )
             {
@@ -1001,7 +1002,9 @@ public class MavenCli
 
                 if ( project == null && exception instanceof LifecycleExecutionException )
                 {
-                    project = ( (LifecycleExecutionException) exception ).getProject();
+                    LifecycleExecutionException lifecycleExecutionException = (LifecycleExecutionException) exception;
+                    project = lifecycleExecutionException.getProject();
+                    isResumptionDataSaved = lifecycleExecutionException.isBuildResumptionDataSaved();
                 }
             }
 
@@ -1030,10 +1033,8 @@ public class MavenCli
                 }
             }
 
-            boolean resumeFileCreated = buildResumptionManager.persistResumptionData( result );
-
             List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
-            if ( resumeFileCreated )
+            if ( isResumptionDataSaved )
             {
                 logBuildResumeHint( "mvn <args> -r " );
             }


[maven] 23/31: When something fails while persisting resumption data, throw an exception instead of returning false.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 306baa643cfeb6325fb019b3afbd5635a638a842
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri Jun 5 21:21:14 2020 +0200

    When something fails while persisting resumption data, throw an exception instead of returning false.
---
 .../main/java/org/apache/maven/DefaultMaven.java   | 12 ++++++--
 .../org/apache/maven/execution/BuildResumer.java   |  4 ++-
 .../BuildResumptionPersistenceException.java       | 34 ++++++++++++++++++++++
 .../maven/execution/DefaultBuildResumer.java       |  6 ++--
 4 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index a78bf75..1543591 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -37,6 +37,7 @@ import javax.inject.Singleton;
 
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.execution.BuildResumer;
+import org.apache.maven.execution.BuildResumptionPersistenceException;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -375,9 +376,16 @@ public class DefaultMaven
                     .findFirst()
                     .ifPresent( rootProject ->
                     {
-                        if ( buildResumer.persistResumptionData( result, rootProject ) )
+                        try
                         {
-                            result.setCanResume();
+                            if ( buildResumer.persistResumptionData( result, rootProject ) )
+                            {
+                                result.setCanResume();
+                            }
+                        }
+                        catch ( BuildResumptionPersistenceException e )
+                        {
+                            logger.warn( "Could not persist build resumption data", e );
                         }
                     } );
         }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
index be85371..fd6840e 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
@@ -37,9 +37,11 @@ public interface BuildResumer
      *
      * @param result The result of the current Maven invocation.
      * @param rootProject The root project that is being built.
+     * @throws BuildResumptionPersistenceException When an error occurs while persisting data.
      * @return Whether any data was persisted.
      */
-    boolean persistResumptionData( final MavenExecutionResult result, final MavenProject rootProject );
+    boolean persistResumptionData( final MavenExecutionResult result, final MavenProject rootProject )
+            throws BuildResumptionPersistenceException;
 
     /**
      * Uses previously stored resumption data to enrich an existing execution request.
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
new file mode 100644
index 0000000..fb9281b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
@@ -0,0 +1,34 @@
+package org.apache.maven.execution;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.project.MavenProject;
+
+/**
+ * This exception will be thrown when something fails while persisting build resumption data.
+ * @see BuildResumer#persistResumptionData(MavenExecutionResult, MavenProject)
+ */
+public class BuildResumptionPersistenceException extends Exception
+{
+    public BuildResumptionPersistenceException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
index 0e0e165..21d99de 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
@@ -59,6 +59,7 @@ public class DefaultBuildResumer implements BuildResumer
 
     @Override
     public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
+            throws BuildResumptionPersistenceException
     {
         Properties properties = determineResumptionProperties( result );
 
@@ -204,6 +205,7 @@ public class DefaultBuildResumer implements BuildResumer
     }
 
     private boolean writeResumptionFile( MavenProject rootProject, Properties properties )
+            throws BuildResumptionPersistenceException
     {
         Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
         try
@@ -216,8 +218,8 @@ public class DefaultBuildResumer implements BuildResumer
         }
         catch ( IOException e )
         {
-            LOGGER.warn( "Could not create {} file. ", RESUME_PROPERTIES_FILENAME, e );
-            return false;
+            String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
+            throw new BuildResumptionPersistenceException( message, e);
         }
 
         return true;


[maven] 30/31: Persist method either succeeds or throws Exception, so returns void

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit c8e810f6afffc5ee84dcc89d6e56e39af3e4d968
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Thu Jun 18 09:27:45 2020 +0200

    Persist method either succeeds or throws Exception, so returns void
---
 maven-core/src/main/java/org/apache/maven/DefaultMaven.java           | 4 ++--
 .../org/apache/maven/execution/BuildResumptionDataRepository.java     | 3 +--
 .../apache/maven/execution/DefaultBuildResumptionDataRepository.java  | 4 +---
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 167cb7b..51d7752 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -384,8 +384,8 @@ public class DefaultMaven
             {
                 try
                 {
-                    boolean canResume = buildResumptionDataRepository.persistResumptionData( rootProject, resumption );
-                    result.setCanResume( canResume );
+                    buildResumptionDataRepository.persistResumptionData( rootProject, resumption );
+                    result.setCanResume( true );
                 }
                 catch ( BuildResumptionPersistenceException e )
                 {
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
index b8a3b22..3d0be6f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
@@ -36,9 +36,8 @@ public interface BuildResumptionDataRepository
      * @param rootProject The root project that is being built.
      * @param buildResumptionData Information needed to resume the build.
      * @throws BuildResumptionPersistenceException When an error occurs while persisting data.
-     * @return Whether any data was persisted.
      */
-    boolean persistResumptionData( final MavenProject rootProject, final BuildResumptionData buildResumptionData )
+    void persistResumptionData( final MavenProject rootProject, final BuildResumptionData buildResumptionData )
             throws BuildResumptionPersistenceException;
 
     /**
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
index e7965b3..eea097f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
@@ -50,7 +50,7 @@ public class DefaultBuildResumptionDataRepository implements BuildResumptionData
     private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionDataRepository.class );
 
     @Override
-    public boolean persistResumptionData( MavenProject rootProject, BuildResumptionData buildResumptionData )
+    public void persistResumptionData( MavenProject rootProject, BuildResumptionData buildResumptionData )
             throws BuildResumptionPersistenceException
     {
         Properties properties = convertToProperties( buildResumptionData );
@@ -69,8 +69,6 @@ public class DefaultBuildResumptionDataRepository implements BuildResumptionData
             String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
             throw new BuildResumptionPersistenceException( message, e );
         }
-
-        return true;
     }
 
     private Properties convertToProperties( final BuildResumptionData buildResumptionData )


[maven] 12/31: Extract public interface

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 504a0efdb9906eae99cdc2b7e21bb1a7c24cbb8c
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Sat May 23 19:56:34 2020 +0200

    Extract public interface
---
 .../maven/execution/BuildResumptionManager.java    | 299 ++-------------------
 ...ger.java => DefaultBuildResumptionManager.java} |  29 +-
 ...java => DefaultBuildResumptionManagerTest.java} |   4 +-
 3 files changed, 36 insertions(+), 296 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
index e0ab008..f3d41aa 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
@@ -19,79 +19,40 @@ package org.apache.maven.execution;
  * under the License.
  */
 
-import com.google.common.annotations.VisibleForTesting;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.maven.lifecycle.LifecycleExecutionException;
-import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.logging.Logger;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.stream.Collectors;
-
-import static java.util.Comparator.comparing;
 
 /**
- * This class contains most of the logic needed for the --resume / -r feature.
- * It persists information in a properties file to ensure newer builds, using the -r feature,
- *   skip successfully built projects.
+ * This class describes most of the logic needed for the --resume / -r feature. Its goal is to ensure newer
+ * builds of the same project that have the -r command-line flag skip successfully built projects during earlier
+ * invocations of Maven.
  */
-@Named
-@Singleton
-public class BuildResumptionManager
+public interface BuildResumptionManager
 {
-    private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
-    private static final String RESUME_FROM_PROPERTY = "resumeFrom";
-    private static final String EXCLUDED_PROJECTS_PROPERTY = "excludedProjects";
-    private static final String PROPERTY_DELIMITER = ", ";
-
-    @Inject
-    private Logger logger;
-    
-    public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
-    {
-        Properties properties = determineResumptionProperties( result );
-
-        if ( properties.isEmpty() )
-        {
-            logger.debug( "Will not create " + RESUME_PROPERTIES_FILENAME + " file: nothing to resume from" );
-            return false;
-        }
-
-        return writeResumptionFile( rootProject, properties );
-    }
+    /**
+     * Persists any data needed to resume the build at a later point in time, using a new Maven invocation. This method
+     * may also decide it is not needed or meaningful to persist such data, and return <code>false</code> to indicate
+     * so.
+     *
+     * @param result The result of the current Maven invocation.
+     * @param rootProject The root project that is being built.
+     * @return Whether any data was persisted.
+     */
+    boolean persistResumptionData( final MavenExecutionResult result, final MavenProject rootProject );
 
-    public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
-    {
-        Properties properties = loadResumptionFile( rootProject.getBuild().getDirectory() );
-        applyResumptionProperties( request, properties );
-    }
+    /**
+     * Uses previously stored resumption data to enrich an existing execution request.
+     * @param request The execution request that will be enriched.
+     * @param rootProject The root project that is being built.
+     */
+    void applyResumptionData( final MavenExecutionRequest request, final MavenProject rootProject );
 
-    public void removeResumptionData( MavenProject rootProject )
-    {
-        Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
-        try
-        {
-            Files.deleteIfExists( resumeProperties );
-        }
-        catch ( IOException e )
-        {
-            logger.warn( "Could not delete " + RESUME_PROPERTIES_FILENAME + " file. ", e );
-        }
-    }
+    /**
+     * Removes previously stored resumption data.
+     * @param rootProject The root project that is being built.
+     */
+    void removeResumptionData( final MavenProject rootProject );
 
     /**
      * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case
@@ -109,213 +70,5 @@ public class BuildResumptionManager
      * @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).
      */
-    public String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject failedProject )
-    {
-        boolean hasOverlappingArtifactId = mavenProjects.stream()
-                .filter( project -> failedProject.getArtifactId().equals( project.getArtifactId() ) )
-                .count() > 1;
-
-        if ( hasOverlappingArtifactId )
-        {
-            return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
-        }
-
-        return ":" + failedProject.getArtifactId();
-    }
-
-    @VisibleForTesting
-    Properties determineResumptionProperties( MavenExecutionResult result )
-    {
-        Properties properties = new Properties();
-
-        List<MavenProject> failedProjects = getFailedProjectsInOrder( result );
-        if ( !failedProjects.isEmpty() )
-        {
-            MavenProject resumeFromProject = failedProjects.get( 0 );
-            Optional<String> resumeFrom = getResumeFrom( result, resumeFromProject );
-            Optional<String> projectsToSkip = determineProjectsToSkip( result, failedProjects, resumeFromProject );
-
-            resumeFrom.ifPresent( value -> properties.setProperty( RESUME_FROM_PROPERTY, value ) );
-            projectsToSkip.ifPresent( value -> properties.setProperty( EXCLUDED_PROJECTS_PROPERTY, value ) );
-        }
-        else
-        {
-            logger.warn( "Could not create " + RESUME_PROPERTIES_FILENAME + " file: no failed projects found" );
-        }
-
-        return properties;
-    }
-
-    private List<MavenProject> getFailedProjectsInOrder( MavenExecutionResult result )
-    {
-        List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
-
-        return result.getExceptions().stream()
-                .filter( LifecycleExecutionException.class::isInstance )
-                .map( LifecycleExecutionException.class::cast )
-                .map( LifecycleExecutionException::getProject )
-                .sorted( comparing( sortedProjects::indexOf ) )
-                .collect( Collectors.toList() );
-    }
-
-    /**
-     * Determine the project where the next build can be resumed from.
-     * If the failed project is the first project of the build,
-     * it does not make sense to use --resume-from, so the result will be empty.
-     * @param result The result of the Maven build.
-     * @param failedProject The first failed project of the build.
-     * @return An optional containing the resume-from suggestion.
-     */
-    private Optional<String> getResumeFrom( MavenExecutionResult result, MavenProject failedProject )
-    {
-        List<MavenProject> allSortedProjects = result.getTopologicallySortedProjects();
-        if ( !allSortedProjects.get( 0 ).equals( failedProject ) )
-        {
-            return Optional.of( String.format( "%s:%s", failedProject.getGroupId(), failedProject.getArtifactId() ) );
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Projects after the first failed project could have succeeded by using -T or --fail-at-end.
-     * These projects can be skipped from later builds.
-     * This is not the case these projects are dependent on one of the failed projects.
-     * @param result The result of the Maven build.
-     * @param failedProjects The list of failed projects in the build.
-     * @param resumeFromProject The project where the build will be resumed with in the next run.
-     * @return An optional containing a comma separated list of projects which can be skipped,
-     *   or an empty optional if no projects can be skipped.
-     */
-    private Optional<String> determineProjectsToSkip( MavenExecutionResult result, List<MavenProject> failedProjects,
-                                                      MavenProject resumeFromProject )
-    {
-        List<MavenProject> allProjects = result.getTopologicallySortedProjects();
-        int resumeFromProjectIndex = allProjects.indexOf( resumeFromProject );
-        List<MavenProject> remainingProjects = allProjects.subList( resumeFromProjectIndex + 1, allProjects.size() );
-
-        List<GroupArtifactPair> failedProjectsGAList = failedProjects.stream()
-                .map( GroupArtifactPair::new )
-                .collect( Collectors.toList() );
-
-        String projectsToSkip = remainingProjects.stream()
-                .filter( project -> result.getBuildSummary( project ) instanceof BuildSuccess )
-                .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
-                .map( project -> String.format( "%s:%s", project.getGroupId(), project.getArtifactId() ) )
-                .collect( Collectors.joining( PROPERTY_DELIMITER ) );
-
-        if ( !StringUtils.isEmpty( projectsToSkip ) )
-        {
-            return Optional.of( projectsToSkip );
-        }
-
-        return Optional.empty();
-    }
-
-    private boolean hasNoDependencyOnProjects( MavenProject project, List<GroupArtifactPair> projectsGAs )
-    {
-        return project.getDependencies().stream()
-                .map( GroupArtifactPair::new )
-                .noneMatch( projectsGAs::contains );
-    }
-
-    private boolean writeResumptionFile( MavenProject rootProject, Properties properties )
-    {
-        Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
-        try
-        {
-            Files.createDirectories( resumeProperties.getParent() );
-            try ( Writer writer = Files.newBufferedWriter( resumeProperties ) )
-            {
-                properties.store( writer, null );
-            }
-        }
-        catch ( IOException e )
-        {
-            logger.warn( "Could not create " + RESUME_PROPERTIES_FILENAME + " file. ", e );
-            return false;
-        }
-
-        return true;
-    }
-
-    private Properties loadResumptionFile( String rootBuildDirectory )
-    {
-        Properties properties = new Properties();
-        Path path = Paths.get( rootBuildDirectory, RESUME_PROPERTIES_FILENAME );
-        if ( !Files.exists( path ) )
-        {
-            logger.warn( "The " + path + " file does not exist. The --resume / -r feature will not work." );
-            return properties;
-        }
-
-        try ( Reader reader = Files.newBufferedReader( path ) )
-        {
-            properties.load( reader );
-        }
-        catch ( IOException e )
-        {
-            logger.warn( "Unable to read " + path + ". The --resume / -r feature will not work." );
-        }
-
-        return properties;
-    }
-
-    @VisibleForTesting
-    void applyResumptionProperties( MavenExecutionRequest request, Properties properties )
-    {
-        if ( properties.containsKey( RESUME_FROM_PROPERTY ) && StringUtils.isEmpty( request.getResumeFrom() ) )
-        {
-            String propertyValue = properties.getProperty( RESUME_FROM_PROPERTY );
-            request.setResumeFrom( propertyValue );
-            logger.info( "Resuming from " + propertyValue + " due to the --resume / -r feature." );
-        }
-
-        if ( properties.containsKey( EXCLUDED_PROJECTS_PROPERTY ) )
-        {
-            String propertyValue = properties.getProperty( EXCLUDED_PROJECTS_PROPERTY );
-            String[] excludedProjects = propertyValue.split( PROPERTY_DELIMITER );
-            request.getExcludedProjects().addAll( Arrays.asList( excludedProjects ) );
-            logger.info( "Additionally excluding projects '" + propertyValue + "' due to the --resume / -r feature." );
-        }
-    }
-
-    private static class GroupArtifactPair
-    {
-        private final String groupId;
-        private final String artifactId;
-
-        GroupArtifactPair( MavenProject project )
-        {
-            this.groupId = project.getGroupId();
-            this.artifactId = project.getArtifactId();
-        }
-
-        GroupArtifactPair( Dependency dependency )
-        {
-            this.groupId = dependency.getGroupId();
-            this.artifactId = dependency.getArtifactId();
-        }
-
-        @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
-                return true;
-            }
-            if ( o == null || getClass() != o.getClass() )
-            {
-                return false;
-            }
-            GroupArtifactPair that = (GroupArtifactPair) o;
-            return Objects.equals( groupId, that.groupId ) && Objects.equals( artifactId, that.artifactId );
-        }
-
-        @Override
-        public int hashCode()
-        {
-            return Objects.hash( groupId, artifactId );
-        }
-    }
+    String getResumeFromSelector( final List<MavenProject> mavenProjects, final MavenProject failedProject );
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
similarity index 89%
copy from maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
copy to maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
index e0ab008..d08478f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
@@ -45,13 +45,12 @@ import java.util.stream.Collectors;
 import static java.util.Comparator.comparing;
 
 /**
- * This class contains most of the logic needed for the --resume / -r feature.
- * It persists information in a properties file to ensure newer builds, using the -r feature,
- *   skip successfully built projects.
+ * This implementation of {@link BuildResumptionManager} persists information in a properties file. The file is stored
+ * in the build output directory under the Maven execution root.
  */
 @Named
 @Singleton
-public class BuildResumptionManager
+public class DefaultBuildResumptionManager implements BuildResumptionManager
 {
     private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
     private static final String RESUME_FROM_PROPERTY = "resumeFrom";
@@ -60,7 +59,8 @@ public class BuildResumptionManager
 
     @Inject
     private Logger logger;
-    
+
+    @Override
     public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
     {
         Properties properties = determineResumptionProperties( result );
@@ -74,12 +74,14 @@ public class BuildResumptionManager
         return writeResumptionFile( rootProject, properties );
     }
 
+    @Override
     public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
     {
         Properties properties = loadResumptionFile( rootProject.getBuild().getDirectory() );
         applyResumptionProperties( request, properties );
     }
 
+    @Override
     public void removeResumptionData( MavenProject rootProject )
     {
         Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
@@ -93,22 +95,7 @@ public class BuildResumptionManager
         }
     }
 
-    /**
-     * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case
-     *   where multiple modules in the reactor have the same artifactId.
-     * <p>
-     * {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the reactor
-     *   have the same artifactId, effective failed module might be later in build reactor.
-     * This means that developer will either have to type groupId or wait for build execution of all modules which
-     *   were fine, but they are still before one which reported errors.
-     * <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
-     * {@code :artifactId} if there is no conflict.
-     *
-     * @param mavenProjects Maven projects which are part of build execution.
-     * @param failedProject 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).
-     */
+    @Override
     public String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject failedProject )
     {
         boolean hasOverlappingArtifactId = mavenProjects.stream()
diff --git a/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionManagerTest.java
similarity index 98%
rename from maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
rename to maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionManagerTest.java
index 5c3129b..a0c913b 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionManagerTest.java
@@ -40,13 +40,13 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
 
 @RunWith( MockitoJUnitRunner.class )
-public class BuildResumptionManagerTest
+public class DefaultBuildResumptionManagerTest
 {
     @Mock
     private Logger logger;
 
     @InjectMocks
-    private BuildResumptionManager buildResumptionManager;
+    private DefaultBuildResumptionManager buildResumptionManager;
 
     private MavenExecutionResult result;
 


[maven] 22/31: Review comment: Removed Guava's @VisibleForTesting

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 35519929b77111a79e0735d60158562519d67ca3
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri Jun 5 20:59:56 2020 +0200

    Review comment: Removed Guava's @VisibleForTesting
---
 .../main/java/org/apache/maven/execution/DefaultBuildResumer.java    | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
index 7232365..0e0e165 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
@@ -19,7 +19,6 @@ package org.apache.maven.execution;
  * under the License.
  */
 
-import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.Dependency;
@@ -108,7 +107,7 @@ public class DefaultBuildResumer implements BuildResumer
         return ":" + failedProject.getArtifactId();
     }
 
-    @VisibleForTesting
+    // This method is made package-private for testing purposes
     Properties determineResumptionProperties( MavenExecutionResult result )
     {
         Properties properties = new Properties();
@@ -246,7 +245,7 @@ public class DefaultBuildResumer implements BuildResumer
         return properties;
     }
 
-    @VisibleForTesting
+    // This method is made package-private for testing purposes
     void applyResumptionProperties( MavenExecutionRequest request, Properties properties )
     {
         if ( properties.containsKey( RESUME_FROM_PROPERTY ) && StringUtils.isEmpty( request.getResumeFrom() ) )


[maven] 13/31: Store information about resumption storage in execution result

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit edbeb969eeb1e3f092db8557da20b0a009156a9a
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Sat May 23 20:30:46 2020 +0200

    Store information about resumption storage in execution result
---
 .../src/main/java/org/apache/maven/DefaultMaven.java       | 13 +++++++------
 .../maven/execution/DefaultMavenExecutionResult.java       | 14 ++++++++++++++
 .../org/apache/maven/execution/MavenExecutionResult.java   | 14 ++++++++++++++
 .../maven/lifecycle/LifecycleExecutionException.java       | 12 ------------
 .../src/main/java/org/apache/maven/cli/MavenCli.java       |  4 +---
 5 files changed, 36 insertions(+), 21 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 4907ac9..a5e84f3 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -366,20 +366,21 @@ public class DefaultMaven
 
     private void saveResumptionDataWhenApplicable( MavenExecutionResult result, MavenSession session )
     {
-        List<LifecycleExecutionException> lifecycleExecutionExceptions = result.getExceptions().stream()
+        long lifecycleExecutionExceptionCount = result.getExceptions().stream()
                 .filter( LifecycleExecutionException.class::isInstance )
-                .map( LifecycleExecutionException.class::cast )
-                .collect( Collectors.toList() );
+                .count();
 
-        if ( !lifecycleExecutionExceptions.isEmpty() )
+        if ( lifecycleExecutionExceptionCount > 0 )
         {
             session.getAllProjects().stream()
                     .filter( MavenProject::isExecutionRoot )
                     .findFirst()
                     .ifPresent( rootProject ->
                     {
-                        boolean persisted = buildResumptionManager.persistResumptionData( result, rootProject );
-                        lifecycleExecutionExceptions.forEach( e -> e.setBuildResumptionDataSaved( persisted ) );
+                        if ( buildResumptionManager.persistResumptionData( result, rootProject ) )
+                        {
+                            result.setResumptionDataStored();
+                        }
                     } );
         }
     }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
index 6ab1daa..f346b7f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
@@ -43,6 +43,8 @@ public class DefaultMavenExecutionResult
     private final Map<MavenProject, BuildSummary> buildSummaries =
         Collections.synchronizedMap( new IdentityHashMap<>() );
 
+    private boolean resumptionDataStored = false;
+
     public MavenExecutionResult setProject( MavenProject project )
     {
         this.project = project;
@@ -108,4 +110,16 @@ public class DefaultMavenExecutionResult
     {
         buildSummaries.put( summary.getProject(), summary );
     }
+
+    @Override
+    public boolean isResumptionDataStored()
+    {
+        return resumptionDataStored;
+    }
+
+    @Override
+    public void setResumptionDataStored()
+    {
+        this.resumptionDataStored = true;
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
index cb95fb1..301d459 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
@@ -67,4 +67,18 @@ public interface MavenExecutionResult
      * @param summary The build summary to add, must not be {@code null}.
      */
     void addBuildSummary( BuildSummary summary );
+
+    /**
+     * Indicates whether or not resumption data has been stored.
+     * @see org.apache.maven.execution.BuildResumptionManager
+     * @return <code>true</code> when it is possible to resume the build, <code>false</code> otherwise.
+     */
+    boolean isResumptionDataStored();
+
+    /**
+     * Indicate that resumption data has been stored.
+     * @see org.apache.maven.execution.BuildResumptionManager
+     * @see #isResumptionDataStored()
+     */
+    void setResumptionDataStored();
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
index af9821a..0831a4f 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
@@ -33,8 +33,6 @@ public class LifecycleExecutionException
 {
     private MavenProject project;
 
-    private boolean buildResumptionDataSaved = false;
-
     public LifecycleExecutionException( String message )
     {
         super( message );
@@ -78,16 +76,6 @@ public class LifecycleExecutionException
         return project;
     }
 
-    public boolean isBuildResumptionDataSaved()
-    {
-        return buildResumptionDataSaved;
-    }
-
-    public void setBuildResumptionDataSaved( boolean isBuildResumptionDataSaved )
-    {
-        this.buildResumptionDataSaved = isBuildResumptionDataSaved;
-    }
-
     private static String createMessage( MojoExecution execution, MavenProject project, Throwable cause )
     {
         MessageBuilder buffer = buffer( 256 );
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 657dfe0..66b1fc8 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
@@ -992,7 +992,6 @@ public class MavenCli
             Map<String, String> references = new LinkedHashMap<>();
 
             MavenProject project = null;
-            boolean isResumptionDataSaved = false;
 
             for ( Throwable exception : result.getExceptions() )
             {
@@ -1004,7 +1003,6 @@ public class MavenCli
                 {
                     LifecycleExecutionException lifecycleExecutionException = (LifecycleExecutionException) exception;
                     project = lifecycleExecutionException.getProject();
-                    isResumptionDataSaved = lifecycleExecutionException.isBuildResumptionDataSaved();
                 }
             }
 
@@ -1034,7 +1032,7 @@ public class MavenCli
             }
 
             List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
-            if ( isResumptionDataSaved )
+            if ( result.isResumptionDataStored() )
             {
                 logBuildResumeHint( "mvn <args> -r " );
             }


[maven] 09/31: Fixed a bug where a failed project would be excluded in the next build when it failed after another failed build.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit ff350dfd05dca376db697b66f70f4a220e336d48
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Sat May 23 07:59:01 2020 +0200

    Fixed a bug where a failed project would be excluded in the next build when it failed after another failed build.
---
 .../apache/maven/execution/BuildResumptionManager.java    |  2 +-
 .../maven/execution/BuildResumptionManagerTest.java       | 15 +++++++++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
index 0f6bf39..0fb22e4 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionManager.java
@@ -186,7 +186,7 @@ public class BuildResumptionManager
                 .collect( Collectors.toList() );
 
         String projectsToSkip = remainingProjects.stream()
-                .filter( project -> result.getBuildSummary( project ) != null )
+                .filter( project -> result.getBuildSummary( project ) instanceof BuildSuccess )
                 .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
                 .map( project -> String.format( "%s:%s", project.getGroupId(), project.getArtifactId() ) )
                 .collect( Collectors.joining( PROPERTY_DELIMITER ) );
diff --git a/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java b/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
index 96c0dee..5c3129b 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/BuildResumptionManagerTest.java
@@ -107,6 +107,21 @@ public class BuildResumptionManagerTest
     }
 
     @Test
+    public void projectsFailingAfterAnotherFailedProjectAreNotExcluded()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        MavenProject projectC = createSucceededMavenProject( "C" );
+        MavenProject projectD = createFailedMavenProject( "D" );
+        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC, projectD ) );
+
+        Properties properties = buildResumptionManager.determineResumptionProperties( result );
+
+        assertThat( properties.get( "resumeFrom" ), is("test:B") );
+        assertThat( properties.get( "excludedProjects" ), is("test:C") );
+    }
+
+    @Test
     public void multipleExcludedProjectsAreCommaSeparated()
     {
         MavenProject projectA = createFailedMavenProject( "A" );


[maven] 29/31: Split off BuildResumptionAnalyzer from BuildResumptionDataRepository

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 6faa4cd12a2b2478c63e88d34a62637c7f75e653
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Wed Jun 17 20:24:28 2020 +0200

    Split off BuildResumptionAnalyzer from BuildResumptionDataRepository
---
 .../main/java/org/apache/maven/DefaultMaven.java   |  32 ++--
 .../maven/execution/BuildResumptionAnalyzer.java   |  36 ++++
 .../maven/execution/BuildResumptionData.java       |  55 ++++++
 .../execution/BuildResumptionDataRepository.java   |   4 +-
 .../execution/DefaultBuildResumptionAnalyzer.java  | 162 ++++++++++++++++++
 .../DefaultBuildResumptionDataRepository.java      | 190 +++------------------
 .../DefaultBuildResumptionAnalyzerTest.java        | 150 ++++++++++++++++
 .../DefaultBuildResumptionDataRepositoryTest.java  | 132 +-------------
 8 files changed, 453 insertions(+), 308 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index ad5aad7..167cb7b 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -36,6 +36,7 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.execution.BuildResumptionAnalyzer;
 import org.apache.maven.execution.BuildResumptionDataRepository;
 import org.apache.maven.execution.BuildResumptionPersistenceException;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
@@ -103,6 +104,9 @@ public class DefaultMaven
     private GraphBuilder graphBuilder;
 
     @Inject
+    private BuildResumptionAnalyzer buildResumptionAnalyzer;
+
+    @Inject
     private BuildResumptionDataRepository buildResumptionDataRepository;
 
     @Override
@@ -371,21 +375,23 @@ public class DefaultMaven
 
         if ( hasLifecycleExecutionExceptions )
         {
-            session.getAllProjects().stream()
+            MavenProject rootProject = session.getAllProjects().stream()
                     .filter( MavenProject::isExecutionRoot )
                     .findFirst()
-                    .ifPresent( rootProject ->
-                    {
-                        try
-                        {
-                            boolean persistenceResult = buildResumptionDataRepository.persistResumptionData( result, rootProject );
-                            result.setCanResume( persistenceResult );
-                        }
-                        catch ( BuildResumptionPersistenceException e )
-                        {
-                            logger.warn( "Could not persist build resumption data", e );
-                        }
-                    } );
+                    .orElseThrow( () -> new IllegalStateException( "No project in the session is execution root" ) );
+
+            buildResumptionAnalyzer.determineBuildResumptionData( result ).ifPresent( resumption ->
+            {
+                try
+                {
+                    boolean canResume = buildResumptionDataRepository.persistResumptionData( rootProject, resumption );
+                    result.setCanResume( canResume );
+                }
+                catch ( BuildResumptionPersistenceException e )
+                {
+                    logger.warn( "Could not persist build resumption data", e );
+                }
+            } );
         }
     }
 
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionAnalyzer.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionAnalyzer.java
new file mode 100644
index 0000000..1778946
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionAnalyzer.java
@@ -0,0 +1,36 @@
+package org.apache.maven.execution;
+
+/*
+ * 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.
+ */
+
+import java.util.Optional;
+
+/**
+ * Instances of this class are responsible for determining whether it makes sense to "resume" a build (i.e., using
+ * the {@code --resume} flag.
+ */
+public interface BuildResumptionAnalyzer
+{
+    /**
+     * Construct an instance of {@link BuildResumptionData} based on the outcome of the current Maven build.
+     * @param result Outcome of the current Maven build.
+     * @return A {@link BuildResumptionData} instance or {@link Optional#empty()} if resuming the build is not possible.
+     */
+    Optional<BuildResumptionData> determineBuildResumptionData( final MavenExecutionResult result );
+}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
new file mode 100644
index 0000000..9330929
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
@@ -0,0 +1,55 @@
+package org.apache.maven.execution;
+
+/*
+ * 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.
+ */
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class holds the information required to enable resuming a Maven build with {@code --resume}.
+ */
+public class BuildResumptionData
+{
+    /**
+     * The project where the next build could resume from.
+     */
+    private final String resumeFrom;
+
+    /**
+     * List of projects to skip if the build would be resumed from {@link #resumeFrom}.
+     */
+    private final List<String> projectsToSkip;
+
+    public BuildResumptionData ( final String resumeFrom, final List<String> projectsToSkip )
+    {
+        this.resumeFrom = resumeFrom;
+        this.projectsToSkip = projectsToSkip;
+    }
+
+    public String getResumeFrom()
+    {
+        return this.resumeFrom;
+    }
+
+    public List<String> getProjectsToSkip()
+    {
+        return this.projectsToSkip;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
index 8733819..b8a3b22 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
@@ -33,12 +33,12 @@ public interface BuildResumptionDataRepository
      * may also decide it is not needed or meaningful to persist such data, and return <code>false</code> to indicate
      * so.
      *
-     * @param result The result of the current Maven invocation.
      * @param rootProject The root project that is being built.
+     * @param buildResumptionData Information needed to resume the build.
      * @throws BuildResumptionPersistenceException When an error occurs while persisting data.
      * @return Whether any data was persisted.
      */
-    boolean persistResumptionData( final MavenExecutionResult result, final MavenProject rootProject )
+    boolean persistResumptionData( final MavenProject rootProject, final BuildResumptionData buildResumptionData )
             throws BuildResumptionPersistenceException;
 
     /**
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzer.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzer.java
new file mode 100644
index 0000000..3d100dc
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzer.java
@@ -0,0 +1,162 @@
+package org.apache.maven.execution;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.comparing;
+
+/**
+ * Default implementation of {@link BuildResumptionAnalyzer}.
+ */
+@Named
+@Singleton
+public class DefaultBuildResumptionAnalyzer implements BuildResumptionAnalyzer
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionAnalyzer.class );
+
+    @Override
+    public Optional<BuildResumptionData> determineBuildResumptionData( final MavenExecutionResult result )
+    {
+        final List<MavenProject> failedProjects = getFailedProjectsInOrder( result );
+
+        if ( failedProjects.isEmpty() )
+        {
+            LOGGER.info( "No failed projects found, resuming the build would not make sense." );
+            return Optional.empty();
+        }
+
+        final MavenProject resumeFromProject = failedProjects.get( 0 );
+
+        if ( isFailedProjectFirstInBuild( result, resumeFromProject ) )
+        {
+            LOGGER.info( "The first module in the build failed, resuming the build would not make sense." );
+            return Optional.empty();
+        }
+
+        final String resumeFromSelector = resumeFromProject.getGroupId() + ":" + resumeFromProject.getArtifactId();
+        final List<String> projectsToSkip = determineProjectsToSkip( result, failedProjects, resumeFromProject );
+
+        return Optional.of( new BuildResumptionData( resumeFromSelector, projectsToSkip ) );
+    }
+
+    private boolean isFailedProjectFirstInBuild( final MavenExecutionResult result, final MavenProject failedProject )
+    {
+        final List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
+        return sortedProjects.indexOf( failedProject ) == 0;
+    }
+
+    private List<MavenProject> getFailedProjectsInOrder( MavenExecutionResult result )
+    {
+        List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
+
+        return result.getExceptions().stream()
+                .filter( LifecycleExecutionException.class::isInstance )
+                .map( LifecycleExecutionException.class::cast )
+                .map( LifecycleExecutionException::getProject )
+                .sorted( comparing( sortedProjects::indexOf ) )
+                .collect( Collectors.toList() );
+    }
+
+    /**
+     * Projects after the first failed project could have succeeded by using -T or --fail-at-end.
+     * These projects can be skipped from later builds.
+     * This is not the case these projects are dependent on one of the failed projects.
+     * @param result The result of the Maven build.
+     * @param failedProjects The list of failed projects in the build.
+     * @param resumeFromProject The project where the build will be resumed with in the next run.
+     * @return A list of projects which can be skipped in a later build.
+     */
+    private List<String> determineProjectsToSkip( MavenExecutionResult result,
+                                                  List<MavenProject> failedProjects,
+                                                  MavenProject resumeFromProject )
+    {
+        List<MavenProject> allProjects = result.getTopologicallySortedProjects();
+        int resumeFromProjectIndex = allProjects.indexOf( resumeFromProject );
+        List<MavenProject> remainingProjects = allProjects.subList( resumeFromProjectIndex + 1, allProjects.size() );
+
+        List<GroupArtifactPair> failedProjectsGAList = failedProjects.stream()
+                .map( GroupArtifactPair::new )
+                .collect( Collectors.toList() );
+
+        return remainingProjects.stream()
+                .filter( project -> result.getBuildSummary( project ) instanceof BuildSuccess )
+                .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
+                .map( project -> project.getGroupId() + ":" + project.getArtifactId() )
+                .collect( Collectors.toList() );
+    }
+
+    private boolean hasNoDependencyOnProjects( MavenProject project, List<GroupArtifactPair> projectsGAs )
+    {
+        return project.getDependencies().stream()
+                .map( GroupArtifactPair::new )
+                .noneMatch( projectsGAs::contains );
+    }
+
+    private static class GroupArtifactPair
+    {
+        private final String groupId;
+        private final String artifactId;
+
+        GroupArtifactPair( MavenProject project )
+        {
+            this.groupId = project.getGroupId();
+            this.artifactId = project.getArtifactId();
+        }
+
+        GroupArtifactPair( Dependency dependency )
+        {
+            this.groupId = dependency.getGroupId();
+            this.artifactId = dependency.getArtifactId();
+        }
+
+        @Override
+        public boolean equals( Object o )
+        {
+            if ( this == o )
+            {
+                return true;
+            }
+            if ( o == null || getClass() != o.getClass() )
+            {
+                return false;
+            }
+            GroupArtifactPair that = (GroupArtifactPair) o;
+            return Objects.equals( groupId, that.groupId ) && Objects.equals( artifactId, that.artifactId );
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return Objects.hash( groupId, artifactId );
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
index 7e647d7..e7965b3 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
@@ -20,8 +20,6 @@ package org.apache.maven.execution;
  */
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.maven.lifecycle.LifecycleExecutionException;
-import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,17 +33,11 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
 import java.util.Properties;
-import java.util.stream.Collectors;
-
-import static java.util.Comparator.comparing;
 
 /**
- * This implementation of {@link BuildResumptionDataRepository} persists information in a properties file. The file is stored
- * in the build output directory under the Maven execution root.
+ * This implementation of {@link BuildResumptionDataRepository} persists information in a properties file. The file is
+ * stored in the build output directory under the Maven execution root.
  */
 @Named
 @Singleton
@@ -58,151 +50,58 @@ public class DefaultBuildResumptionDataRepository implements BuildResumptionData
     private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionDataRepository.class );
 
     @Override
-    public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
+    public boolean persistResumptionData( MavenProject rootProject, BuildResumptionData buildResumptionData )
             throws BuildResumptionPersistenceException
     {
-        Properties properties = determineResumptionProperties( result );
-
-        if ( properties.isEmpty() )
-        {
-            LOGGER.debug( "Will not create {} file: nothing to resume from", RESUME_PROPERTIES_FILENAME );
-            return false;
-        }
-
-        return writeResumptionFile( rootProject, properties );
-    }
-
-    @Override
-    public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
-    {
-        Properties properties = loadResumptionFile( Paths.get( rootProject.getBuild().getDirectory() ) );
-        applyResumptionProperties( request, properties );
-    }
+        Properties properties = convertToProperties( buildResumptionData );
 
-    @Override
-    public void removeResumptionData( MavenProject rootProject )
-    {
         Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
         try
         {
-            Files.deleteIfExists( resumeProperties );
+            Files.createDirectories( resumeProperties.getParent() );
+            try ( Writer writer = Files.newBufferedWriter( resumeProperties ) )
+            {
+                properties.store( writer, null );
+            }
         }
         catch ( IOException e )
         {
-            LOGGER.warn( "Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e );
+            String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
+            throw new BuildResumptionPersistenceException( message, e );
         }
+
+        return true;
     }
 
-    // This method is made package-private for testing purposes
-    Properties determineResumptionProperties( MavenExecutionResult result )
+    private Properties convertToProperties( final BuildResumptionData buildResumptionData )
     {
         Properties properties = new Properties();
-
-        List<MavenProject> failedProjects = getFailedProjectsInOrder( result );
-        if ( !failedProjects.isEmpty() )
-        {
-            MavenProject resumeFromProject = failedProjects.get( 0 );
-            Optional<String> resumeFrom = getResumeFrom( result, resumeFromProject );
-            List<String> projectsToSkip = determineProjectsToSkip( result, failedProjects, resumeFromProject );
-
-            resumeFrom.ifPresent( value -> properties.setProperty( RESUME_FROM_PROPERTY, value ) );
-            if ( !projectsToSkip.isEmpty() ) {
-                String excludedProjects = String.join( PROPERTY_DELIMITER, projectsToSkip );
-                properties.setProperty( EXCLUDED_PROJECTS_PROPERTY, excludedProjects );
-            }
-        }
-        else
-        {
-            LOGGER.warn( "Could not create {} file: no failed projects found", RESUME_PROPERTIES_FILENAME );
-        }
+        properties.setProperty( RESUME_FROM_PROPERTY, buildResumptionData.getResumeFrom() );
+        String excludedProjects = String.join( PROPERTY_DELIMITER, buildResumptionData.getProjectsToSkip() );
+        properties.setProperty( EXCLUDED_PROJECTS_PROPERTY, excludedProjects );
 
         return properties;
     }
 
-    private List<MavenProject> getFailedProjectsInOrder( MavenExecutionResult result )
-    {
-        List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
-
-        return result.getExceptions().stream()
-                .filter( LifecycleExecutionException.class::isInstance )
-                .map( LifecycleExecutionException.class::cast )
-                .map( LifecycleExecutionException::getProject )
-                .sorted( comparing( sortedProjects::indexOf ) )
-                .collect( Collectors.toList() );
-    }
-
-    /**
-     * Determine the project where the next build can be resumed from.
-     * If the failed project is the first project of the build,
-     * it does not make sense to use --resume-from, so the result will be empty.
-     * @param result The result of the Maven build.
-     * @param failedProject The first failed project of the build.
-     * @return An optional containing the resume-from suggestion.
-     */
-    private Optional<String> getResumeFrom( MavenExecutionResult result, MavenProject failedProject )
-    {
-        List<MavenProject> allSortedProjects = result.getTopologicallySortedProjects();
-        if ( !allSortedProjects.get( 0 ).equals( failedProject ) )
-        {
-            return Optional.of( failedProject.getGroupId() + ":" + failedProject.getArtifactId() );
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Projects after the first failed project could have succeeded by using -T or --fail-at-end.
-     * These projects can be skipped from later builds.
-     * This is not the case these projects are dependent on one of the failed projects.
-     * @param result The result of the Maven build.
-     * @param failedProjects The list of failed projects in the build.
-     * @param resumeFromProject The project where the build will be resumed with in the next run.
-     * @return A list of projects which can be skipped in a later build.
-     */
-    private List<String> determineProjectsToSkip( MavenExecutionResult result, List<MavenProject> failedProjects,
-                                                  MavenProject resumeFromProject )
-    {
-        List<MavenProject> allProjects = result.getTopologicallySortedProjects();
-        int resumeFromProjectIndex = allProjects.indexOf( resumeFromProject );
-        List<MavenProject> remainingProjects = allProjects.subList( resumeFromProjectIndex + 1, allProjects.size() );
-
-        List<GroupArtifactPair> failedProjectsGAList = failedProjects.stream()
-                .map( GroupArtifactPair::new )
-                .collect( Collectors.toList() );
-
-        return remainingProjects.stream()
-                .filter( project -> result.getBuildSummary( project ) instanceof BuildSuccess )
-                .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
-                .map( project -> project.getGroupId() + ":" + project.getArtifactId() )
-                .collect( Collectors.toList() );
-    }
-
-    private boolean hasNoDependencyOnProjects( MavenProject project, List<GroupArtifactPair> projectsGAs )
+    @Override
+    public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
     {
-        return project.getDependencies().stream()
-                .map( GroupArtifactPair::new )
-                .noneMatch( projectsGAs::contains );
+        Properties properties = loadResumptionFile( Paths.get( rootProject.getBuild().getDirectory() ) );
+        applyResumptionProperties( request, properties );
     }
 
-    private boolean writeResumptionFile( MavenProject rootProject, Properties properties )
-            throws BuildResumptionPersistenceException
+    @Override
+    public void removeResumptionData( MavenProject rootProject )
     {
         Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
         try
         {
-            Files.createDirectories( resumeProperties.getParent() );
-            try ( Writer writer = Files.newBufferedWriter( resumeProperties ) )
-            {
-                properties.store( writer, null );
-            }
+            Files.deleteIfExists( resumeProperties );
         }
         catch ( IOException e )
         {
-            String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
-            throw new BuildResumptionPersistenceException( message, e );
+            LOGGER.warn( "Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e );
         }
-
-        return true;
     }
 
     private Properties loadResumptionFile( Path rootBuildDirectory )
@@ -245,43 +144,4 @@ public class DefaultBuildResumptionDataRepository implements BuildResumptionData
             LOGGER.info( "Additionally excluding projects '{}' due to the --resume / -r feature.", propertyValue );
         }
     }
-
-    private static class GroupArtifactPair
-    {
-        private final String groupId;
-        private final String artifactId;
-
-        GroupArtifactPair( MavenProject project )
-        {
-            this.groupId = project.getGroupId();
-            this.artifactId = project.getArtifactId();
-        }
-
-        GroupArtifactPair( Dependency dependency )
-        {
-            this.groupId = dependency.getGroupId();
-            this.artifactId = dependency.getArtifactId();
-        }
-
-        @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
-                return true;
-            }
-            if ( o == null || getClass() != o.getClass() )
-            {
-                return false;
-            }
-            GroupArtifactPair that = (GroupArtifactPair) o;
-            return Objects.equals( groupId, that.groupId ) && Objects.equals( artifactId, that.artifactId );
-        }
-
-        @Override
-        public int hashCode()
-        {
-            return Objects.hash( groupId, artifactId );
-        }
-    }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzerTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzerTest.java
new file mode 100644
index 0000000..59a8e63
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzerTest.java
@@ -0,0 +1,150 @@
+package org.apache.maven.execution;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Optional;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.is;
+
+public class DefaultBuildResumptionAnalyzerTest
+{
+    private final DefaultBuildResumptionAnalyzer analyzer = new DefaultBuildResumptionAnalyzer();
+
+    private MavenExecutionResult executionResult;
+
+    @Before
+    public void before() {
+        executionResult = new DefaultMavenExecutionResult();
+    }
+
+    @Test
+    public void resumeFromGetsDetermined()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        executionResult.setTopologicallySortedProjects( asList( projectA, projectB ) );
+
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+
+        assertThat( result.isPresent(), is( true ) );
+        assertThat( result.get().getResumeFrom(), is( "test:B" ) );
+    }
+
+    @Test
+    public void resumeFromIsIgnoredWhenFirstProjectFails()
+    {
+        MavenProject projectA = createFailedMavenProject( "A" );
+        MavenProject projectB = createMavenProject( "B" );
+        executionResult.setTopologicallySortedProjects( asList( projectA, projectB ) );
+
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+
+        assertThat( result.isPresent(), is( false ) );
+    }
+
+    @Test
+    public void projectsSucceedingAfterFailedProjectsAreExcluded()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        MavenProject projectC = createSucceededMavenProject( "C" );
+        executionResult.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
+
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+
+        assertThat( result.isPresent(), is( true ) );
+        assertThat( result.get().getProjectsToSkip(), contains( "test:C" ) );
+    }
+
+    @Test
+    public void projectsDependingOnFailedProjectsAreNotExcluded()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        MavenProject projectC = createSucceededMavenProject( "C" );
+        projectC.setDependencies( singletonList( toDependency( projectB ) ) );
+        executionResult.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
+
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+
+        assertThat( result.isPresent(), is( true ) );
+        assertThat( result.get().getProjectsToSkip().isEmpty(), is( true ) );
+    }
+
+    @Test
+    public void projectsFailingAfterAnotherFailedProjectAreNotExcluded()
+    {
+        MavenProject projectA = createSucceededMavenProject( "A" );
+        MavenProject projectB = createFailedMavenProject( "B" );
+        MavenProject projectC = createSucceededMavenProject( "C" );
+        MavenProject projectD = createFailedMavenProject( "D" );
+        executionResult.setTopologicallySortedProjects( asList( projectA, projectB, projectC, projectD ) );
+
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+
+        assertThat( result.isPresent(), is( true ) );
+        assertThat( result.get().getResumeFrom(), is( "test:B" ) );
+        assertThat( result.get().getProjectsToSkip(), contains( "test:C" ) );
+        assertThat( result.get().getProjectsToSkip(), not( contains( "test:D" ) ) );
+    }
+
+    private MavenProject createMavenProject( String artifactId )
+    {
+        MavenProject project = new MavenProject();
+        project.setGroupId( "test" );
+        project.setArtifactId( artifactId );
+        return project;
+    }
+
+    private Dependency toDependency(MavenProject mavenProject )
+    {
+        Dependency dependency = new Dependency();
+        dependency.setGroupId( mavenProject.getGroupId() );
+        dependency.setArtifactId( mavenProject.getArtifactId() );
+        dependency.setVersion( mavenProject.getVersion() );
+        return dependency;
+    }
+
+    private MavenProject createSucceededMavenProject( String artifactId )
+    {
+        MavenProject project = createMavenProject( artifactId );
+        executionResult.addBuildSummary( new BuildSuccess( project, 0 ) );
+        return project;
+    }
+
+    private MavenProject createFailedMavenProject( String artifactId )
+    {
+        MavenProject project = createMavenProject( artifactId );
+        executionResult.addBuildSummary( new BuildFailure( project, 0, new Exception() ) );
+        executionResult.addException( new LifecycleExecutionException( "", project ) );
+        return project;
+    }
+}
\ No newline at end of file
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
index 279fb11..415b946 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
@@ -19,10 +19,6 @@ package org.apache.maven.execution;
  * under the License.
  */
 
-import org.apache.maven.lifecycle.LifecycleExecutionException;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.project.MavenProject;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
@@ -31,8 +27,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
 
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.is;
@@ -40,93 +34,7 @@ import static org.hamcrest.Matchers.is;
 @RunWith( MockitoJUnitRunner.class )
 public class DefaultBuildResumptionDataRepositoryTest
 {
-    private final DefaultBuildResumptionDataRepository buildResumer = new DefaultBuildResumptionDataRepository();
-
-    private MavenExecutionResult result;
-
-    @Before
-    public void before() {
-        result = new DefaultMavenExecutionResult();
-    }
-
-    @Test
-    public void resumeFromGetsDetermined()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        result.setTopologicallySortedProjects( asList( projectA, projectB ) );
-
-        Properties properties = buildResumer.determineResumptionProperties( result );
-
-        assertThat( properties.get( "resumeFrom" ), is( "test:B" ) );
-    }
-
-    @Test
-    public void resumeFromIsIgnoredWhenFirstProjectFails()
-    {
-        MavenProject projectA = createFailedMavenProject( "A" );
-        MavenProject projectB = createMavenProject( "B" );
-        result.setTopologicallySortedProjects( asList( projectA, projectB ) );
-
-        Properties properties = buildResumer.determineResumptionProperties( result );
-
-        assertThat( properties.containsKey( "resumeFrom" ), is(false) );
-    }
-
-    @Test
-    public void projectsSucceedingAfterFailedProjectsAreExcluded()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        MavenProject projectC = createSucceededMavenProject( "C" );
-        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
-
-        Properties properties = buildResumer.determineResumptionProperties( result );
-
-        assertThat( properties.get( "excludedProjects" ), is("test:C") );
-    }
-
-    @Test
-    public void projectsDependingOnFailedProjectsAreNotExcluded()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        MavenProject projectC = createSucceededMavenProject( "C" );
-        projectC.setDependencies( singletonList( toDependency( projectB ) ) );
-        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
-
-        Properties properties = buildResumer.determineResumptionProperties( result );
-
-        assertThat( properties.containsKey( "excludedProjects" ), is(false) );
-    }
-
-    @Test
-    public void projectsFailingAfterAnotherFailedProjectAreNotExcluded()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        MavenProject projectC = createSucceededMavenProject( "C" );
-        MavenProject projectD = createFailedMavenProject( "D" );
-        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC, projectD ) );
-
-        Properties properties = buildResumer.determineResumptionProperties( result );
-
-        assertThat( properties.get( "resumeFrom" ), is("test:B") );
-        assertThat( properties.get( "excludedProjects" ), is("test:C") );
-    }
-
-    @Test
-    public void multipleExcludedProjectsAreCommaSeparated()
-    {
-        MavenProject projectA = createFailedMavenProject( "A" );
-        MavenProject projectB = createSucceededMavenProject( "B" );
-        MavenProject projectC = createSucceededMavenProject( "C" );
-        result.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
-
-        Properties properties = buildResumer.determineResumptionProperties( result );
-
-        assertThat( properties.get( "excludedProjects" ), is( "test:B, test:C" ) );
-    }
+    private final DefaultBuildResumptionDataRepository repository = new DefaultBuildResumptionDataRepository();
 
     @Test
     public void resumeFromPropertyGetsApplied()
@@ -135,7 +43,7 @@ public class DefaultBuildResumptionDataRepositoryTest
         Properties properties = new Properties();
         properties.setProperty( "resumeFrom", ":module-a" );
 
-        buildResumer.applyResumptionProperties( request, properties );
+        repository.applyResumptionProperties( request, properties );
 
         assertThat( request.getResumeFrom(), is( ":module-a" ) );
     }
@@ -148,7 +56,7 @@ public class DefaultBuildResumptionDataRepositoryTest
         Properties properties = new Properties();
         properties.setProperty( "resumeFrom", ":module-a" );
 
-        buildResumer.applyResumptionProperties( request, properties );
+        repository.applyResumptionProperties( request, properties );
 
         assertThat( request.getResumeFrom(), is( ":module-b" ) );
     }
@@ -163,40 +71,8 @@ public class DefaultBuildResumptionDataRepositoryTest
         Properties properties = new Properties();
         properties.setProperty( "excludedProjects", ":module-b, :module-c" );
 
-        buildResumer.applyResumptionProperties( request, properties );
+        repository.applyResumptionProperties( request, properties );
 
         assertThat( request.getExcludedProjects(), contains( ":module-a", ":module-b", ":module-c" ) );
     }
-
-    private MavenProject createMavenProject( String artifactId )
-    {
-        MavenProject project = new MavenProject();
-        project.setGroupId( "test" );
-        project.setArtifactId( artifactId );
-        return project;
-    }
-
-    private Dependency toDependency( MavenProject mavenProject )
-    {
-        Dependency dependency = new Dependency();
-        dependency.setGroupId( mavenProject.getGroupId() );
-        dependency.setArtifactId( mavenProject.getArtifactId() );
-        dependency.setVersion( mavenProject.getVersion() );
-        return dependency;
-    }
-
-    private MavenProject createSucceededMavenProject( String artifactId )
-    {
-        MavenProject project = createMavenProject( artifactId );
-        result.addBuildSummary( new BuildSuccess( project, 0 ) );
-        return project;
-    }
-
-    private MavenProject createFailedMavenProject( String artifactId )
-    {
-        MavenProject project = createMavenProject( artifactId );
-        result.addBuildSummary( new BuildFailure( project, 0, new Exception() ) );
-        result.addException( new LifecycleExecutionException( "", project ) );
-        return project;
-    }
 }


[maven] 18/31: Replace String#format with String concatenation

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 9b94112443b2b4f70f1305ef55f53f2c4b848705
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Mon May 25 17:29:50 2020 +0200

    Replace String#format with String concatenation
---
 .../org/apache/maven/execution/DefaultBuildResumptionManager.java     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
index 4a3f819..9f7c944 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionManager.java
@@ -156,7 +156,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         List<MavenProject> allSortedProjects = result.getTopologicallySortedProjects();
         if ( !allSortedProjects.get( 0 ).equals( failedProject ) )
         {
-            return Optional.of( String.format( "%s:%s", failedProject.getGroupId(), failedProject.getArtifactId() ) );
+            return Optional.of( failedProject.getGroupId() + ":" + failedProject.getArtifactId() );
         }
 
         return Optional.empty();
@@ -186,7 +186,7 @@ public class DefaultBuildResumptionManager implements BuildResumptionManager
         String projectsToSkip = remainingProjects.stream()
                 .filter( project -> result.getBuildSummary( project ) instanceof BuildSuccess )
                 .filter( project -> hasNoDependencyOnProjects( project, failedProjectsGAList ) )
-                .map( project -> String.format( "%s:%s", project.getGroupId(), project.getArtifactId() ) )
+                .map( project -> project.getGroupId() + ":" + project.getArtifactId() )
                 .collect( Collectors.joining( PROPERTY_DELIMITER ) );
 
         if ( !StringUtils.isEmpty( projectsToSkip ) )


[maven] 07/31: Removed dead code, as the `getResumeFrom` method has been moved to the BuildResumptionManager.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 2d7de183ecdd15b7268992f0be1482a81331d1dd
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri May 22 15:17:46 2020 +0200

    Removed dead code, as the `getResumeFrom` method has been moved to the BuildResumptionManager.
---
 .../main/java/org/apache/maven/cli/MavenCli.java   | 29 ----------------------
 1 file changed, 29 deletions(-)

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 4ecd095..4877ddd 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
@@ -1063,35 +1063,6 @@ public class MavenCli
         }
     }
 
-    /**
-     * A helper method to determine the value to resume the build with {@code -rf} taking into account the
-     * edge case where multiple modules in the reactor have the same artifactId.
-     * <p>
-     * {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the
-     * reactor have the same artifactId, effective failed module might be later in build reactor.
-     * This means that developer will either have to type groupId or wait for build execution of all modules
-     * which were fine, but they are still before one which reported errors.
-     * <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
-     * {@code :artifactId} if there is no conflict.
-     *
-     * @param mavenProjects Maven projects which are part of build execution.
-     * @param failedProject 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).
-     */
-    private String getResumeFrom( List<MavenProject> mavenProjects, MavenProject failedProject )
-    {
-        for ( MavenProject buildProject : mavenProjects )
-        {
-            if ( failedProject.getArtifactId().equals( buildProject.getArtifactId() ) && !failedProject.equals(
-                    buildProject ) )
-            {
-                return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
-            }
-        }
-        return ":" + failedProject.getArtifactId();
-    }
-
     private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
                              boolean showErrors )
     {


[maven] 26/31: Moved the -rf helper method, including the tests, back to MavenCli. The BuildResumer is now only focused on the --resume feature.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit e4ef15fe3ba447ab22c5e61fef63b7e94266a479
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Sat Jun 6 10:56:55 2020 +0200

    Moved the -rf helper method, including the tests, back to MavenCli. The BuildResumer is now only focused on the --resume feature.
---
 .../org/apache/maven/execution/BuildResumer.java   | 19 -----------
 .../maven/execution/DefaultBuildResumer.java       | 15 ---------
 .../maven/execution/DefaultBuildResumerTest.java   | 33 +------------------
 .../main/java/org/apache/maven/cli/MavenCli.java   | 33 ++++++++++++++++++-
 .../java/org/apache/maven/cli/MavenCliTest.java    | 38 ++++++++++++++++++++++
 5 files changed, 71 insertions(+), 67 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
index fd6840e..8de72ca 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
@@ -21,8 +21,6 @@ package org.apache.maven.execution;
 
 import org.apache.maven.project.MavenProject;
 
-import java.util.List;
-
 /**
  * This class describes most of the logic needed for the --resume / -r feature. Its goal is to ensure newer
  * builds of the same project that have the -r command-line flag skip successfully built projects during earlier
@@ -56,21 +54,4 @@ public interface BuildResumer
      */
     void removeResumptionData( final MavenProject rootProject );
 
-    /**
-     * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case
-     *   where multiple modules in the reactor have the same artifactId.
-     * <p>
-     * {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the reactor
-     *   have the same artifactId, effective failed module might be later in build reactor.
-     * This means that developer will either have to type groupId or wait for build execution of all modules which
-     *   were fine, but they are still before one which reported errors.
-     * <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
-     * {@code :artifactId} if there is no conflict.
-     *
-     * @param mavenProjects Maven projects which are part of build execution.
-     * @param failedProject 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( final List<MavenProject> mavenProjects, final MavenProject failedProject );
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
index b5fb1b6..84a6ded 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
@@ -93,21 +93,6 @@ public class DefaultBuildResumer implements BuildResumer
         }
     }
 
-    @Override
-    public String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject failedProject )
-    {
-        boolean hasOverlappingArtifactId = mavenProjects.stream()
-                .filter( project -> failedProject.getArtifactId().equals( project.getArtifactId() ) )
-                .count() > 1;
-
-        if ( hasOverlappingArtifactId )
-        {
-            return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
-        }
-
-        return ":" + failedProject.getArtifactId();
-    }
-
     // This method is made package-private for testing purposes
     Properties determineResumptionProperties( MavenExecutionResult result )
     {
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
index d2dd9ee..0664cb4 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
@@ -168,41 +168,10 @@ public class DefaultBuildResumerTest
         assertThat( request.getExcludedProjects(), contains( ":module-a", ":module-b", ":module-c" ) );
     }
 
-    @Test
-    public void resumeFromSelectorIsSuggestedWithoutGroupId()
-    {
-        List<MavenProject> allProjects = asList(
-                createMavenProject( "group", "module-a" ),
-                createMavenProject( "group", "module-b" ) );
-        MavenProject failedProject = allProjects.get( 0 );
-
-        String selector = buildResumer.getResumeFromSelector( allProjects, failedProject );
-
-        assertThat( selector, is( ":module-a" ) );
-    }
-
-    @Test
-    public void resumeFromSelectorContainsGroupIdWhenArtifactIdIsNotUnique()
-    {
-        List<MavenProject> allProjects = asList(
-                createMavenProject( "group-a", "module" ),
-                createMavenProject( "group-b", "module" ) );
-        MavenProject failedProject = allProjects.get( 0 );
-
-        String selector = buildResumer.getResumeFromSelector( allProjects, failedProject );
-
-        assertThat( selector, is( "group-a:module" ) );
-    }
-
     private MavenProject createMavenProject( String artifactId )
     {
-        return createMavenProject( "test", artifactId );
-    }
-
-    private MavenProject createMavenProject( String groupId, String artifactId )
-    {
         MavenProject project = new MavenProject();
-        project.setGroupId( groupId );
+        project.setGroupId( "test" );
         project.setArtifactId( artifactId );
         return project;
     }
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 7778a06..5bf6b32 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
@@ -1038,7 +1038,7 @@ public class MavenCli
             }
             else if ( project != null && !project.equals( sortedProjects.get( 0 ) ) )
             {
-                String resumeFromSelector = buildResumer.getResumeFromSelector( sortedProjects, project );
+                String resumeFromSelector = getResumeFromSelector( sortedProjects, project );
                 logBuildResumeHint( "mvn <args> -rf " + resumeFromSelector );
             }
 
@@ -1066,6 +1066,37 @@ public class MavenCli
         slf4jLogger.error( buffer().a( "  " ).strong( resumeBuildHint ).toString() );
     }
 
+    /**
+     * A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case
+     *   where multiple modules in the reactor have the same artifactId.
+     * <p>
+     * {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the reactor
+     *   have the same artifactId, effective failed module might be later in build reactor.
+     * This means that developer will either have to type groupId or wait for build execution of all modules which
+     *   were fine, but they are still before one which reported errors.
+     * <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
+     * {@code :artifactId} if there is no conflict.
+     * 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.
+     * @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<MavenProject> mavenProjects, MavenProject failedProject )
+    {
+        boolean hasOverlappingArtifactId = mavenProjects.stream()
+                .filter( project -> failedProject.getArtifactId().equals( project.getArtifactId() ) )
+                .count() > 1;
+
+        if ( hasOverlappingArtifactId )
+        {
+            return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
+        }
+
+        return ":" + failedProject.getArtifactId();
+    }
+
     private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
                              boolean showErrors )
     {
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
index 173b78c..b0e536f 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
@@ -19,6 +19,9 @@ package org.apache.maven.cli;
  * under the License.
  */
 
+import static java.util.Arrays.asList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -31,10 +34,12 @@ import static org.mockito.Mockito.times;
 
 import java.io.File;
 import java.util.Collections;
+import java.util.List;
 
 import org.apache.commons.cli.ParseException;
 import org.apache.maven.Maven;
 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
+import org.apache.maven.project.MavenProject;
 import org.apache.maven.shared.utils.logging.MessageUtils;
 import org.apache.maven.toolchain.building.ToolchainsBuildingRequest;
 import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
@@ -346,4 +351,37 @@ public class MavenCliTest
         orderdEventSpyDispatcherMock.verify(eventSpyDispatcherMock, times(1)).onEvent(any(ToolchainsBuildingResult.class));
     }
 
+    @Test
+    public void resumeFromSelectorIsSuggestedWithoutGroupId()
+    {
+        List<MavenProject> allProjects = asList(
+                createMavenProject( "group", "module-a" ),
+                createMavenProject( "group", "module-b" ) );
+        MavenProject failedProject = allProjects.get( 0 );
+
+        String selector = cli.getResumeFromSelector( allProjects, failedProject );
+
+        assertThat( selector, is( ":module-a" ) );
+    }
+
+    @Test
+    public void resumeFromSelectorContainsGroupIdWhenArtifactIdIsNotUnique()
+    {
+        List<MavenProject> allProjects = asList(
+                createMavenProject( "group-a", "module" ),
+                createMavenProject( "group-b", "module" ) );
+        MavenProject failedProject = allProjects.get( 0 );
+
+        String selector = cli.getResumeFromSelector( allProjects, failedProject );
+
+        assertThat( selector, is( "group-a:module" ) );
+    }
+
+    private MavenProject createMavenProject( String groupId, String artifactId )
+    {
+        MavenProject project = new MavenProject();
+        project.setGroupId( groupId );
+        project.setArtifactId( artifactId );
+        return project;
+    }
 }


[maven] 24/31: Add a boolean to the setCanResume method, which denotes whether a build can be resumed or not.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit f2cacd49541f9edf6de7f74d736da0bd5a1c7c0e
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri Jun 5 21:29:17 2020 +0200

    Add a boolean to the setCanResume method, which denotes whether a build can be resumed or not.
---
 maven-core/src/main/java/org/apache/maven/DefaultMaven.java         | 6 ++----
 .../org/apache/maven/execution/DefaultMavenExecutionResult.java     | 4 ++--
 .../main/java/org/apache/maven/execution/MavenExecutionResult.java  | 5 +++--
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 1543591..5c7c9ea 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -378,10 +378,8 @@ public class DefaultMaven
                     {
                         try
                         {
-                            if ( buildResumer.persistResumptionData( result, rootProject ) )
-                            {
-                                result.setCanResume();
-                            }
+                            boolean persistenceResult = buildResumer.persistResumptionData( result, rootProject );
+                            result.setCanResume( persistenceResult );
                         }
                         catch ( BuildResumptionPersistenceException e )
                         {
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
index ae87d5c..ecddd66 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
@@ -118,8 +118,8 @@ public class DefaultMavenExecutionResult
     }
 
     @Override
-    public void setCanResume()
+    public void setCanResume( boolean canResume )
     {
-        this.canResume = true;
+        this.canResume = canResume;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
index 7a86afb..285aab0 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
@@ -76,9 +76,10 @@ public interface MavenExecutionResult
     boolean canResume();
 
     /**
-     * Indicate that the build could be resumed by a second invocation of Maven.
+     * Indicate that the build can or cannot be resumed by a second invocation of Maven.
+     * @param canResume <code>true</code> when it is possible to resume the build, <code>false</code> otherwise.
      * @see org.apache.maven.execution.BuildResumer
      * @see #canResume()
      */
-    void setCanResume();
+    void setCanResume( boolean canResume );
 }


[maven] 04/31: Added license to BuildResumptionManagerTest

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 9d317a0e69cc97924a33d458a48e5816fc084953
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri May 22 09:25:29 2020 +0200

    Added license to BuildResumptionManagerTest
---
 .../apache/maven/cli/BuildResumptionManagerTest.java  | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java
index a70da32..5958c80 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/BuildResumptionManagerTest.java
@@ -1,5 +1,24 @@
 package org.apache.maven.cli;
 
+/*
+ * 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.
+ */
+
 import org.apache.maven.execution.BuildFailure;
 import org.apache.maven.execution.BuildSuccess;
 import org.apache.maven.execution.DefaultMavenExecutionResult;


[maven] 27/31: Rename interface and implementation

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 94b546997511a856ebeea2c6571311701104c4e3
Author: Maarten Mulders <ma...@infosupport.com>
AuthorDate: Wed Jun 17 14:43:41 2020 +0200

    Rename interface and implementation
---
 maven-core/src/main/java/org/apache/maven/DefaultMaven.java       | 8 ++++----
 .../{BuildResumer.java => BuildResumptionDataRepository.java}     | 6 +++---
 .../maven/execution/BuildResumptionPersistenceException.java      | 2 +-
 ...uildResumer.java => DefaultBuildResumptionDataRepository.java} | 6 +++---
 .../java/org/apache/maven/execution/MavenExecutionResult.java     | 4 ++--
 .../src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java | 6 +++---
 ...merTest.java => DefaultBuildResumptionDataRepositoryTest.java} | 4 ++--
 maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java   | 6 +++---
 8 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 5c7c9ea..ad5aad7 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -36,7 +36,7 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.execution.BuildResumer;
+import org.apache.maven.execution.BuildResumptionDataRepository;
 import org.apache.maven.execution.BuildResumptionPersistenceException;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
 import org.apache.maven.execution.ExecutionEvent;
@@ -103,7 +103,7 @@ public class DefaultMaven
     private GraphBuilder graphBuilder;
 
     @Inject
-    private BuildResumer buildResumer;
+    private BuildResumptionDataRepository buildResumptionDataRepository;
 
     @Override
     public MavenExecutionResult execute( MavenExecutionRequest request )
@@ -327,7 +327,7 @@ public class DefaultMaven
                 session.getAllProjects().stream()
                         .filter( MavenProject::isExecutionRoot )
                         .findFirst()
-                        .ifPresent( buildResumer::removeResumptionData );
+                        .ifPresent( buildResumptionDataRepository::removeResumptionData );
             }
         }
         finally
@@ -378,7 +378,7 @@ public class DefaultMaven
                     {
                         try
                         {
-                            boolean persistenceResult = buildResumer.persistResumptionData( result, rootProject );
+                            boolean persistenceResult = buildResumptionDataRepository.persistResumptionData( result, rootProject );
                             result.setCanResume( persistenceResult );
                         }
                         catch ( BuildResumptionPersistenceException e )
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
similarity index 88%
rename from maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
rename to maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
index 8de72ca..8733819 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
@@ -22,11 +22,11 @@ package org.apache.maven.execution;
 import org.apache.maven.project.MavenProject;
 
 /**
- * This class describes most of the logic needed for the --resume / -r feature. Its goal is to ensure newer
- * builds of the same project that have the -r command-line flag skip successfully built projects during earlier
+ * Instances of this interface retrieve and store data for the --resume / -r feature. This data is used to ensure newer
+ * builds of the same project, that have the -r command-line flag, skip successfully built projects during earlier
  * invocations of Maven.
  */
-public interface BuildResumer
+public interface BuildResumptionDataRepository
 {
     /**
      * Persists any data needed to resume the build at a later point in time, using a new Maven invocation. This method
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
index 2d2852f..1f9e802 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
@@ -21,7 +21,7 @@ package org.apache.maven.execution;
 
 /**
  * This exception will be thrown when something fails while persisting build resumption data.
- * @see BuildResumer#persistResumptionData
+ * @see BuildResumptionDataRepository#persistResumptionData
  */
 public class BuildResumptionPersistenceException extends Exception
 {
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
similarity index 97%
rename from maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
rename to maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
index 84a6ded..e6815ce 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
@@ -44,18 +44,18 @@ import java.util.stream.Collectors;
 import static java.util.Comparator.comparing;
 
 /**
- * This implementation of {@link BuildResumer} persists information in a properties file. The file is stored
+ * This implementation of {@link BuildResumptionDataRepository} persists information in a properties file. The file is stored
  * in the build output directory under the Maven execution root.
  */
 @Named
 @Singleton
-public class DefaultBuildResumer implements BuildResumer
+public class DefaultBuildResumptionDataRepository implements BuildResumptionDataRepository
 {
     private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
     private static final String RESUME_FROM_PROPERTY = "resumeFrom";
     private static final String EXCLUDED_PROJECTS_PROPERTY = "excludedProjects";
     private static final String PROPERTY_DELIMITER = ", ";
-    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumer.class );
+    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionDataRepository.class );
 
     @Override
     public boolean persistResumptionData( MavenExecutionResult result, MavenProject rootProject )
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
index 285aab0..8a099bb 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
@@ -70,7 +70,7 @@ public interface MavenExecutionResult
 
     /**
      * Indicates whether or not the build could be resumed by a second invocation of Maven.
-     * @see org.apache.maven.execution.BuildResumer
+     * @see BuildResumptionDataRepository
      * @return <code>true</code> when it is possible to resume the build, <code>false</code> otherwise.
      */
     boolean canResume();
@@ -78,7 +78,7 @@ public interface MavenExecutionResult
     /**
      * Indicate that the build can or cannot be resumed by a second invocation of Maven.
      * @param canResume <code>true</code> when it is possible to resume the build, <code>false</code> otherwise.
-     * @see org.apache.maven.execution.BuildResumer
+     * @see BuildResumptionDataRepository
      * @see #canResume()
      */
     void setCanResume( boolean canResume );
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 1d19c03..07cb80e 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -38,7 +38,7 @@ import org.apache.maven.DefaultMaven;
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.ProjectCycleException;
 import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.execution.BuildResumer;
+import org.apache.maven.execution.BuildResumptionDataRepository;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
@@ -75,7 +75,7 @@ public class DefaultGraphBuilder
     protected ProjectBuilder projectBuilder;
 
     @Inject
-    private BuildResumer buildResumer;
+    private BuildResumptionDataRepository buildResumptionDataRepository;
 
     @Override
     public Result<ProjectDependencyGraph> build( MavenSession session )
@@ -354,7 +354,7 @@ public class DefaultGraphBuilder
                     .filter( MavenProject::isExecutionRoot )
                     .findFirst()
                     .ifPresent( rootProject ->
-                            buildResumer.applyResumptionData( request, rootProject ) );
+                            buildResumptionDataRepository.applyResumptionData( request, rootProject ) );
         }
     }
 
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
similarity index 97%
rename from maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
rename to maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
index 0664cb4..279fb11 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
@@ -38,9 +38,9 @@ import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.is;
 
 @RunWith( MockitoJUnitRunner.class )
-public class DefaultBuildResumerTest
+public class DefaultBuildResumptionDataRepositoryTest
 {
-    private final DefaultBuildResumer buildResumer = new DefaultBuildResumer();
+    private final DefaultBuildResumptionDataRepository buildResumer = new DefaultBuildResumptionDataRepository();
 
     private MavenExecutionResult result;
 
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 5bf6b32..4136a1e 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
@@ -48,7 +48,7 @@ import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.exception.DefaultExceptionHandler;
 import org.apache.maven.exception.ExceptionHandler;
 import org.apache.maven.exception.ExceptionSummary;
-import org.apache.maven.execution.BuildResumer;
+import org.apache.maven.execution.BuildResumptionDataRepository;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.ExecutionListener;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -169,7 +169,7 @@ public class MavenCli
 
     private Map<String, ConfigurationProcessor> configurationProcessors;
 
-    private BuildResumer buildResumer;
+    private BuildResumptionDataRepository buildResumptionDataRepository;
 
     public MavenCli()
     {
@@ -708,7 +708,7 @@ public class MavenCli
 
         dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
 
-        buildResumer = container.lookup( BuildResumer.class );
+        buildResumptionDataRepository = container.lookup( BuildResumptionDataRepository.class );
 
         return container;
     }


[maven] 08/31: Fix bug where the build resume hint log could be logged incorrectly.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 915a3e50b23bf3660905aa057a2becaf78078088
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri May 22 16:16:11 2020 +0200

    Fix bug where the build resume hint log could be logged incorrectly.
---
 .../src/main/java/org/apache/maven/cli/MavenCli.java       | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

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 4877ddd..113af25 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
@@ -1032,18 +1032,15 @@ public class MavenCli
 
             boolean resumeFileCreated = buildResumptionManager.persistResumptionData( result );
 
-            slf4jLogger.error( "" );
-            slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
-
             List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
             if ( resumeFileCreated )
             {
-                slf4jLogger.error( buffer().a( "  " ).strong( "mvn <args> -r " ).toString() );
+                logBuildResumeHint( "mvn <args> -r " );
             }
             else if ( project != null && !project.equals( sortedProjects.get( 0 ) ) )
             {
                 String resumeFromSelector = buildResumptionManager.getResumeFromSelector( sortedProjects, project );
-                slf4jLogger.error( buffer().a( "  " ).strong( "mvn <args> -rf " + resumeFromSelector ).toString() );
+                logBuildResumeHint( "mvn <args> -rf " + resumeFromSelector );
             }
 
             if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
@@ -1063,6 +1060,13 @@ public class MavenCli
         }
     }
 
+    private void logBuildResumeHint( String resumeBuildHint )
+    {
+        slf4jLogger.error( "" );
+        slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
+        slf4jLogger.error( buffer().a( "  " ).strong( resumeBuildHint ).toString() );
+    }
+
     private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
                              boolean showErrors )
     {


[maven] 31/31: Removed unused import

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 8da7f1e92a35d466d6683706a871f9caefb26327
Author: Martin Kanters <mk...@gmail.com>
AuthorDate: Sat Jun 20 11:27:50 2020 +0200

    Removed unused import
---
 .../src/main/java/org/apache/maven/execution/BuildResumptionData.java    | 1 -
 1 file changed, 1 deletion(-)

diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
index 9330929..8889b83 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
@@ -19,7 +19,6 @@ package org.apache.maven.execution;
  * under the License.
  */
 
-import java.util.Collections;
 import java.util.List;
 
 /**


[maven] 02/31: Refactored the getResumeFromSelector logic to be compliant with checkstyle rules.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-5760
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 1d0c15f4e7c16ea58e5d40f9d05de59c96215155
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Fri May 22 09:04:45 2020 +0200

    Refactored the getResumeFromSelector logic to be compliant with checkstyle rules.
---
 .../java/org/apache/maven/cli/BuildResumptionManager.java    | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
index 7820c0a..ecabc81 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/BuildResumptionManager.java
@@ -167,13 +167,15 @@ class BuildResumptionManager
      */
     public String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject failedProject )
     {
-        for ( MavenProject buildProject : mavenProjects )
+        boolean hasOverlappingArtifactId = mavenProjects.stream()
+                .filter( project -> failedProject.getArtifactId().equals( project.getArtifactId() ) )
+                .count() > 1;
+
+        if ( hasOverlappingArtifactId )
         {
-            if ( failedProject.getArtifactId().equals( buildProject.getArtifactId() ) && !failedProject.equals( buildProject ) )
-            {
-                return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
-            }
+            return failedProject.getGroupId() + ":" + failedProject.getArtifactId();
         }
+
         return ":" + failedProject.getArtifactId();
     }