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