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/20 18:42:25 UTC

[maven] 01/06: Support --also-make flag in combination with --resume-from.

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

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

commit 56a163aa495c9e459811727bd43ac511e2c6c992
Author: Martin Kanters <Ma...@infosupport.com>
AuthorDate: Wed Apr 8 21:25:52 2020 +0200

    Support --also-make flag in combination with --resume-from.
    
    Calculate up and downstream dependencies after filtering projects for the --resume-from flag.
---
 .../apache/maven/graph/DefaultGraphBuilder.java    | 135 ++++++++-------
 .../maven/graph/DefaultGraphBuilderTest.java       | 187 +++++++++++++++++++++
 2 files changed, 264 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..07a4cf0 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 = includeAlsoMakeTransitives( 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 = includeAlsoMakeTransitives( 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> includeAlsoMakeTransitives( 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..93db7c1
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
@@ -0,0 +1,187 @@
+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.Model;
+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.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith( Parameterized.class )
+public class DefaultGraphBuilderTest
+{
+    private static final String MODULE_A = "module-a";
+    private static final String MODULE_B = "module-b";
+    private static final String MODULE_C = "module-c";
+
+    @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 String parameterDescription;
+    private List<String> parameterSelectedProjects;
+    private List<String> parameterExcludedProjects;
+    private String parameterResumeFrom;
+    private String parameterMakeBehavior;
+    private List<String> parameterExpectedReactorProjects;
+
+    @Parameters
+    public static Collection<Object[]> parameters()
+    {
+        return asList( new Object[][] {
+                { "Full reactor", emptyList(), emptyList(), "", "", asList( MODULE_A, MODULE_B, MODULE_C ) },
+                { "Selected project", singletonList( MODULE_B ), emptyList(), "", "", singletonList( MODULE_B )},
+                { "Excluded project", emptyList(), singletonList( MODULE_B ), "", "", asList( MODULE_A, MODULE_C )},
+                { "Resuming from project", emptyList(), emptyList(), MODULE_B, "", asList( MODULE_B, MODULE_C )},
+                { "Selected project with also make dependencies", singletonList( MODULE_C ), emptyList(), "", REACTOR_MAKE_UPSTREAM, asList( MODULE_B, MODULE_C )},
+                { "Selected project with also make dependents", singletonList( MODULE_B ), emptyList(), "", REACTOR_MAKE_DOWNSTREAM, asList( MODULE_B, MODULE_C )},
+                { "Resuming from project with also make dependencies", emptyList(), emptyList(), MODULE_C, REACTOR_MAKE_UPSTREAM, asList( MODULE_B, MODULE_C )},
+                { "Selected project with resume from an also make dependency (MNG-4960 IT#1)", singletonList( MODULE_C ), emptyList(), MODULE_B, REACTOR_MAKE_UPSTREAM, asList( MODULE_B, MODULE_C )},
+                { "Selected project with resume from an also make dependent (MNG-4960 IT#2)", singletonList( MODULE_B ), emptyList(), MODULE_C, REACTOR_MAKE_DOWNSTREAM, 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.parameterExpectedReactorProjects = expectedReactorProjects;
+    }
+
+    @Test
+    public void test()
+    {
+        // 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 = parameterExpectedReactorProjects.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 );
+        MavenProject projectModuleA = getMockMavenProject( "module-a" );
+        MavenProject projectModuleB = getMockMavenProject( "module-b" );
+        MavenProject projectModuleC = getMockMavenProject( "module-c" );
+        Dependency dependencyOnModuleB = mock( Dependency.class );
+
+        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( projectModuleA );
+        when( projectBuildingResult2.getProject() ).thenReturn( projectModuleB );
+        when( projectBuildingResult3.getProject() ).thenReturn( projectModuleC );
+
+        when( projectBuilder.build( anyList(), anyBoolean(), any( ProjectBuildingRequest.class ) ) ).thenReturn( asList( projectBuildingResult1, projectBuildingResult2, projectBuildingResult3 ) );
+
+        when( dependencyOnModuleB.getGroupId() ).thenReturn( "org.apache.maven.graph.unittest" );
+        when( dependencyOnModuleB.getArtifactId() ).thenReturn( "module-b" );
+        when( dependencyOnModuleB.getVersion() ).thenReturn( "1.0" );
+        when( projectModuleC.getDependencies() ).thenReturn( singletonList( dependencyOnModuleB ) );
+
+        artifactIdProjectMap = ImmutableMap.of(
+                MODULE_A, projectModuleA,
+                MODULE_B, projectModuleB,
+                MODULE_C, projectModuleC
+        );
+    }
+
+    private MavenProject getMockMavenProject( String artifactId )
+    {
+        MavenProject mavenProject = mock( MavenProject.class );
+        when( mavenProject.getGroupId() ).thenReturn( "org.apache.maven.graph.unittest" );
+        when( mavenProject.getArtifactId() ).thenReturn( artifactId );
+        when( mavenProject.getVersion() ).thenReturn( "1.0" );
+        when( mavenProject.getModel() ).thenReturn( mock( Model.class ) );
+        return mavenProject;
+    }
+}
\ No newline at end of file