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/04/24 10:01:37 UTC

[maven] branch master updated: [MNG-6863] --also-make is being ignored when calling --resume-from

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

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


The following commit(s) were added to refs/heads/master by this push:
     new f6c07d9  [MNG-6863] --also-make is being ignored when calling --resume-from
f6c07d9 is described below

commit f6c07d9358252bb4e9b0ad13c2729c6a42d0a4e8
Author: Martin Kanters <mk...@gmail.com>
AuthorDate: Fri Apr 24 12:01:27 2020 +0200

    [MNG-6863] --also-make is being ignored when calling --resume-from
    
    [MNG-6676] Resume reactor build after skipped project using -pl !X -rf X combination
    
    Co-authored-by: Martin Kanters <Ma...@infosupport.com>
---
 .../apache/maven/graph/DefaultGraphBuilder.java    | 135 +++++-----
 .../maven/graph/DefaultGraphBuilderTest.java       | 290 +++++++++++++++++++++
 2 files changed, 367 insertions(+), 58 deletions(-)

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 6d15230..99f0266 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
@@ -125,8 +125,8 @@ public class DefaultGraphBuilder
         ProjectDependencyGraph projectDependencyGraph = new DefaultProjectDependencyGraph( projects );
         List<MavenProject> activeProjects = projectDependencyGraph.getSortedProjects();
         activeProjects = trimSelectedProjects( activeProjects, projectDependencyGraph, session.getRequest() );
+        activeProjects = trimResumedProjects( activeProjects, projectDependencyGraph, session.getRequest() );
         activeProjects = trimExcludedProjects( activeProjects, session.getRequest() );
-        activeProjects = trimResumedProjects( activeProjects, session.getRequest() );
 
         if ( activeProjects.size() != projectDependencyGraph.getSortedProjects().size() )
         {
@@ -144,6 +144,8 @@ public class DefaultGraphBuilder
 
         if ( !request.getSelectedProjects().isEmpty() )
         {
+            result = new ArrayList<>( projects.size() );
+
             File reactorDirectory = null;
             if ( request.getBaseDirectory() != null )
             {
@@ -176,52 +178,54 @@ public class DefaultGraphBuilder
                 }
             }
 
-            boolean makeUpstream = false;
-            boolean makeDownstream = false;
+            result.addAll( selectedProjects );
 
-            if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) )
-            {
-                makeUpstream = true;
-            }
-            else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) )
-            {
-                makeDownstream = true;
-            }
-            else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) )
-            {
-                makeUpstream = true;
-                makeDownstream = true;
-            }
-            else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) )
-            {
-                throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(),
-                                                   request.getPom() );
-            }
+            result = includeAlsoMakeTransitively( result, request, graph );
+        }
+
+        return result;
+    }
+
+    private List<MavenProject> trimResumedProjects( List<MavenProject> projects, ProjectDependencyGraph graph,
+                                                    MavenExecutionRequest request )
+            throws MavenExecutionException
+    {
+        List<MavenProject> result = projects;
 
-            if ( makeUpstream || makeDownstream )
+        if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
+        {
+            File reactorDirectory = null;
+            if ( request.getBaseDirectory() != null )
             {
-                for ( MavenProject selectedProject : new ArrayList<>( selectedProjects ) )
-                {
-                    if ( makeUpstream )
-                    {
-                        selectedProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) );
-                    }
-                    if ( makeDownstream )
-                    {
-                        selectedProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) );
-                    }
-                }
+                reactorDirectory = new File( request.getBaseDirectory() );
             }
 
-            result = new ArrayList<>( selectedProjects.size() );
+            String selector = request.getResumeFrom();
+
+            result = new ArrayList<>( projects.size() );
+
+            boolean resumed = false;
 
             for ( MavenProject project : projects )
             {
-                if ( selectedProjects.contains( project ) )
+                if ( !resumed && isMatchingProject( project, selector, reactorDirectory ) )
+                {
+                    resumed = true;
+                }
+
+                if ( resumed )
                 {
                     result.add( project );
                 }
             }
+
+            if ( !resumed )
+            {
+                throw new MavenExecutionException( "Could not find project to resume reactor build from: " + selector
+                        + " vs " + formatProjects( projects ), request.getPom() );
+            }
+
+            result = includeAlsoMakeTransitively( result, request, graph );
         }
 
         return result;
@@ -280,42 +284,57 @@ public class DefaultGraphBuilder
         return result;
     }
 
-    private List<MavenProject> trimResumedProjects( List<MavenProject> projects, MavenExecutionRequest request )
-        throws MavenExecutionException
+    private List<MavenProject> includeAlsoMakeTransitively( List<MavenProject> projects, MavenExecutionRequest request,
+                                                            ProjectDependencyGraph graph )
+            throws MavenExecutionException
     {
-        List<MavenProject> result = projects;
-
-        if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
-        {
-            File reactorDirectory = null;
-            if ( request.getBaseDirectory() != null )
-            {
-                reactorDirectory = new File( request.getBaseDirectory() );
-            }
+        List<MavenProject> result;
 
-            String selector = request.getResumeFrom();
+        boolean makeUpstream = false;
+        boolean makeDownstream = false;
 
-            result = new ArrayList<>( projects.size() );
+        if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) )
+        {
+            makeUpstream = true;
+        }
+        else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) )
+        {
+            makeDownstream = true;
+        }
+        else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) )
+        {
+            makeUpstream = true;
+            makeDownstream = true;
+        }
+        else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) )
+        {
+            throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(),
+                    request.getPom() );
+        }
 
-            boolean resumed = false;
+        if ( makeUpstream || makeDownstream )
+        {
 
-            for ( MavenProject project : projects )
+            for ( MavenProject project : new ArrayList<>( projects ) )
             {
-                if ( !resumed && isMatchingProject( project, selector, reactorDirectory ) )
+                if ( makeUpstream )
                 {
-                    resumed = true;
+                    projects.addAll( graph.getUpstreamProjects( project, true ) );
                 }
-
-                if ( resumed )
+                if ( makeDownstream )
                 {
-                    result.add( project );
+                    projects.addAll( graph.getDownstreamProjects( project, true ) );
                 }
             }
+        }
 
-            if ( !resumed )
+        result = new ArrayList<>( projects.size() );
+
+        for ( MavenProject project : graph.getSortedProjects() )
+        {
+            if ( projects.contains( project ) )
             {
-                throw new MavenExecutionException( "Could not find project to resume reactor build from: " + selector
-                    + " vs " + formatProjects( projects ), request.getPom() );
+                result.add( project );
             }
         }
 
diff --git a/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java b/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
new file mode 100644
index 0000000..5fdd73e
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
@@ -0,0 +1,290 @@
+package org.apache.maven.graph;
+
+/*
+ * 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.collect.ImmutableMap;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.building.Result;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingResult;
+import org.codehaus.plexus.util.StringUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static junit.framework.TestCase.assertEquals;
+import static org.apache.maven.execution.MavenExecutionRequest.*;
+import static org.apache.maven.execution.MavenExecutionRequest.REACTOR_MAKE_UPSTREAM;
+import static org.apache.maven.graph.DefaultGraphBuilderTest.ScenarioBuilder.scenario;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith( Parameterized.class )
+public class DefaultGraphBuilderTest
+{
+    private static final String INDEPENDENT_MODULE = "module-independent";
+    private static final String MODULE_A = "module-a";
+    private static final String MODULE_B = "module-b"; // depends on module-a
+    private static final String MODULE_C = "module-c"; // depends on module-b
+
+    @InjectMocks
+    private DefaultGraphBuilder graphBuilder;
+
+    @Mock
+    private ProjectBuilder projectBuilder;
+
+    @Mock
+    private MavenSession session;
+
+    @Mock
+    private MavenExecutionRequest mavenExecutionRequest;
+
+    private Map<String, MavenProject> artifactIdProjectMap;
+
+    // Parameters for the test
+    private final String parameterDescription;
+    private final List<String> parameterSelectedProjects;
+    private final List<String> parameterExcludedProjects;
+    private final String parameterResumeFrom;
+    private final String parameterMakeBehavior;
+    private final List<String> parameterExpectedResult;
+
+    @Parameters(name = "{index}. {0}")
+    public static Collection<Object[]> parameters()
+    {
+        return asList(
+                scenario( "Full reactor" )
+                        .expectResult( asList( INDEPENDENT_MODULE, MODULE_A, MODULE_B, MODULE_C ) ),
+                scenario( "Selected project" )
+                        .selectedProjects( singletonList( MODULE_B ) )
+                        .expectResult( singletonList( MODULE_B ) ),
+                scenario( "Excluded project" )
+                        .excludedProjects( singletonList( MODULE_B ) )
+                        .expectResult( asList( INDEPENDENT_MODULE, MODULE_A, MODULE_C ) ),
+                scenario( "Resuming from project" )
+                        .resumeFrom( MODULE_B )
+                        .expectResult( asList( MODULE_B, MODULE_C ) ),
+                scenario( "Selected project with also make dependencies" )
+                        .selectedProjects( singletonList( MODULE_C ) )
+                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
+                        .expectResult( asList( MODULE_A, MODULE_B, MODULE_C ) ),
+                scenario( "Selected project with also make dependents" )
+                        .selectedProjects( singletonList( MODULE_B ) )
+                        .makeBehavior( REACTOR_MAKE_DOWNSTREAM )
+                        .expectResult( asList( MODULE_B, MODULE_C ) ),
+                scenario( "Resuming from project with also make dependencies" )
+                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
+                        .resumeFrom( MODULE_C )
+                        .expectResult( asList( MODULE_A, MODULE_B, MODULE_C ) ),
+                scenario( "Selected project with resume from an also make dependency (MNG-4960 IT#1)" )
+                        .selectedProjects( singletonList( MODULE_C ) )
+                        .resumeFrom( MODULE_B )
+                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
+                        .expectResult( asList( MODULE_A, MODULE_B, MODULE_C ) ),
+                scenario( "Selected project with resume from an also make dependent (MNG-4960 IT#2)" )
+                        .selectedProjects( singletonList( MODULE_B ) )
+                        .resumeFrom( MODULE_C )
+                        .makeBehavior( REACTOR_MAKE_DOWNSTREAM )
+                        .expectResult( singletonList( MODULE_C ) ),
+                scenario( "Excluding an also make dependency from selectedProject does take its transitive dependency" )
+                        .selectedProjects( singletonList( MODULE_C ) )
+                        .excludedProjects( singletonList( MODULE_B ) )
+                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
+                        .expectResult( asList( MODULE_A, MODULE_C ) ),
+                scenario( "Excluding an also make dependency from resumeFrom does take its transitive dependency" )
+                        .resumeFrom( MODULE_C )
+                        .excludedProjects( singletonList( MODULE_B ) )
+                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
+                        .expectResult( asList( MODULE_A, MODULE_C ) ),
+                scenario( "Resume from exclude project downstream" )
+                        .resumeFrom( MODULE_A )
+                        .excludedProjects( singletonList( MODULE_B ) )
+                        .expectResult( asList( MODULE_A, MODULE_C ) ),
+                scenario( "Exclude the project we are resuming from (as proposed in MNG-6676)" )
+                        .resumeFrom( MODULE_B )
+                        .excludedProjects( singletonList( MODULE_B ) )
+                        .expectResult( singletonList( MODULE_C ) )
+
+
+        );
+    }
+
+    public DefaultGraphBuilderTest( String description, List<String> selectedProjects, List<String> excludedProjects, String resumedFrom, String makeBehavior, List<String> expectedReactorProjects )
+    {
+        this.parameterDescription = description;
+        this.parameterSelectedProjects = selectedProjects;
+        this.parameterExcludedProjects = excludedProjects;
+        this.parameterResumeFrom = resumedFrom;
+        this.parameterMakeBehavior = makeBehavior;
+        this.parameterExpectedResult = expectedReactorProjects;
+    }
+
+    @Test
+    public void testGetReactorProjects()
+    {
+        // Given
+        List<String> selectedProjects = parameterSelectedProjects.stream().map( p -> ":" + p ).collect( Collectors.toList() );
+        List<String> excludedProjects = parameterExcludedProjects.stream().map( p -> ":" + p ).collect( Collectors.toList() );
+
+        when( mavenExecutionRequest.getSelectedProjects() ).thenReturn( selectedProjects );
+        when( mavenExecutionRequest.getExcludedProjects() ).thenReturn( excludedProjects );
+        when( mavenExecutionRequest.getMakeBehavior() ).thenReturn( parameterMakeBehavior );
+        if ( StringUtils.isNotEmpty( parameterResumeFrom ) )
+        {
+            when( mavenExecutionRequest.getResumeFrom() ).thenReturn( ":" + parameterResumeFrom );
+        }
+
+        // When
+        Result<ProjectDependencyGraph> result = graphBuilder.build( session );
+
+        // Then
+        List<MavenProject> actualReactorProjects = result.get().getSortedProjects();
+        List<MavenProject> expectedReactorProjects = parameterExpectedResult.stream()
+                .map( artifactIdProjectMap::get )
+                .collect( Collectors.toList());
+        assertEquals( parameterDescription, expectedReactorProjects, actualReactorProjects );
+    }
+
+    @Before
+    public void before() throws Exception
+    {
+        MockitoAnnotations.initMocks( this );
+
+        ProjectBuildingRequest projectBuildingRequest = mock( ProjectBuildingRequest.class );
+        ProjectBuildingResult projectBuildingResult1 = mock( ProjectBuildingResult.class );
+        ProjectBuildingResult projectBuildingResult2 = mock( ProjectBuildingResult.class );
+        ProjectBuildingResult projectBuildingResult3 = mock( ProjectBuildingResult.class );
+        ProjectBuildingResult projectBuildingResult4 = mock( ProjectBuildingResult.class );
+        MavenProject projectIndependentModule = getMavenProject( "independent-module" );
+        MavenProject projectModuleA = getMavenProject( "module-a" );
+        MavenProject projectModuleB = getMavenProject( "module-b" );
+        MavenProject projectModuleC = getMavenProject( "module-c" );
+        projectModuleB.setDependencies( singletonList( toDependency( projectModuleA) ) );
+        projectModuleC.setDependencies( singletonList( toDependency( projectModuleB) ) );
+
+        when( session.getRequest() ).thenReturn( mavenExecutionRequest );
+        when( session.getProjects() ).thenReturn( null ); // needed, otherwise it will be an empty list by default
+
+        when( mavenExecutionRequest.getProjectBuildingRequest() ).thenReturn( projectBuildingRequest );
+        when( mavenExecutionRequest.getPom() ).thenReturn( new File( "/tmp/unit-test" ) );
+
+        when( projectBuildingResult1.getProject() ).thenReturn( projectIndependentModule );
+        when( projectBuildingResult2.getProject() ).thenReturn( projectModuleA );
+        when( projectBuildingResult3.getProject() ).thenReturn( projectModuleB );
+        when( projectBuildingResult4.getProject() ).thenReturn( projectModuleC );
+
+        when( projectBuilder.build( anyList(), anyBoolean(), any( ProjectBuildingRequest.class ) ) )
+                .thenReturn( asList( projectBuildingResult1, projectBuildingResult2, projectBuildingResult3, projectBuildingResult4 ) );
+
+        artifactIdProjectMap = ImmutableMap.of(
+                INDEPENDENT_MODULE, projectIndependentModule,
+                MODULE_A, projectModuleA,
+                MODULE_B, projectModuleB,
+                MODULE_C, projectModuleC
+        );
+    }
+
+    private MavenProject getMavenProject( String artifactId )
+    {
+        MavenProject mavenProject = new MavenProject();
+        mavenProject.setGroupId( "unittest" );
+        mavenProject.setArtifactId( artifactId );
+        mavenProject.setVersion( "1.0" );
+        return mavenProject;
+    }
+
+    private Dependency toDependency( MavenProject mavenProject )
+    {
+        Dependency dependency = new Dependency();
+        dependency.setGroupId( mavenProject.getGroupId() );
+        dependency.setArtifactId( mavenProject.getArtifactId() );
+        dependency.setVersion( mavenProject.getVersion() );
+        return dependency;
+    }
+
+    static class ScenarioBuilder
+    {
+        private String description;
+        private List<String> selectedProjects = emptyList();
+        private List<String> excludedProjects = emptyList();
+        private String resumeFrom = "";
+        private String makeBehavior = "";
+
+        private ScenarioBuilder() { }
+
+        public static ScenarioBuilder scenario( String description )
+        {
+            ScenarioBuilder scenarioBuilder = new ScenarioBuilder();
+            scenarioBuilder.description = description;
+            return scenarioBuilder;
+        }
+
+        public ScenarioBuilder selectedProjects( List<String> selectedProjects )
+        {
+            this.selectedProjects = selectedProjects;
+            return this;
+        }
+
+        public ScenarioBuilder excludedProjects( List<String> excludedProjects )
+        {
+            this.excludedProjects = excludedProjects;
+            return this;
+        }
+
+        public ScenarioBuilder resumeFrom( String resumeFrom )
+        {
+            this.resumeFrom = resumeFrom;
+            return this;
+        }
+
+        public ScenarioBuilder makeBehavior( String makeBehavior )
+        {
+            this.makeBehavior = makeBehavior;
+            return this;
+        }
+
+        public Object[] expectResult( List<String> expectedReactorProjects )
+        {
+            return new Object[] {
+                    description, selectedProjects, excludedProjects, resumeFrom, makeBehavior, expectedReactorProjects
+            };
+        }
+    }
+}
\ No newline at end of file