You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2022/07/29 09:30:48 UTC
[maven] branch master updated: [MNG-7443] Implement consistent logging between optional projects and optional profiles
This is an automated email from the ASF dual-hosted git repository.
michaelo 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 a53a1aa23 [MNG-7443] Implement consistent logging between optional projects and optional profiles
a53a1aa23 is described below
commit a53a1aa232bc383baf055d884a7c66319d10d404
Author: Giovanni van der Schelde <Gi...@infosupport.com>
AuthorDate: Tue Mar 29 15:28:53 2022 +0200
[MNG-7443] Implement consistent logging between optional projects and optional profiles
This closes #701
---
.../main/java/org/apache/maven/DefaultMaven.java | 38 +++-
.../apache/maven/graph/DefaultGraphBuilder.java | 103 +---------
.../org/apache/maven/graph/ProjectSelector.java | 158 +++++++++++++++
.../apache/maven/graph/ProjectSelectorTest.java | 221 +++++++++++++++++++++
4 files changed, 418 insertions(+), 102 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 14b613899..9792c219c 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -29,8 +29,10 @@ import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ProfileActivation;
+import org.apache.maven.execution.ProjectActivation;
import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.graph.GraphBuilder;
+import org.apache.maven.graph.ProjectSelector;
import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.internal.aether.MavenChainedWorkspaceReader;
@@ -54,6 +56,7 @@ import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.WorkspaceReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.slf4j.helpers.MessageFormatter;
import javax.inject.Inject;
import javax.inject.Named;
@@ -107,6 +110,8 @@ public class DefaultMaven
private final SuperPomProvider superPomProvider;
+ private final ProjectSelector projectSelector;
+
@Inject
public DefaultMaven(
ProjectBuilder projectBuilder,
@@ -132,6 +137,7 @@ public class DefaultMaven
this.buildResumptionAnalyzer = buildResumptionAnalyzer;
this.buildResumptionDataRepository = buildResumptionDataRepository;
this.superPomProvider = superPomProvider;
+ this.projectSelector = new ProjectSelector(); // if necessary switch to DI
}
@Override
@@ -323,6 +329,7 @@ public class DefaultMaven
lifecycleStarter.execute( session );
+ validateOptionalProjects( request, session );
validateOptionalProfiles( session, request.getProfileActivation() );
if ( session.getResult().hasExceptions() )
@@ -623,14 +630,30 @@ public class DefaultMaven
if ( !notFoundRequiredProfiles.isEmpty() )
{
- final String message = String.format(
- "The requested profiles [%s] could not be activated or deactivated because they do not exist.",
- String.join( ", ", notFoundRequiredProfiles )
- );
+ // Use SLF4J formatter for consistency with warnings reported by logger
+ final String message = MessageFormatter.format(
+ "The requested profiles {} could not be activated or deactivated because they do not"
+ + " exist.", notFoundRequiredProfiles ).getMessage();
addExceptionToResult( session.getResult(), new MissingProfilesException( message ) );
}
}
+ /**
+ * Check whether any of the requested optional projects were not activated or deactivated.
+ * @param request the {@link MavenExecutionRequest}.
+ * @param session the {@link MavenSession}.
+ */
+ private void validateOptionalProjects( MavenExecutionRequest request, MavenSession session )
+ {
+ final ProjectActivation projectActivation = request.getProjectActivation();
+ final Set<String> allOptionalSelectors = new HashSet<>();
+ allOptionalSelectors.addAll( projectActivation.getOptionalActiveProjectSelectors() );
+ allOptionalSelectors.addAll( projectActivation.getRequiredActiveProjectSelectors() );
+ // We intentionally ignore the results of this method.
+ // As a side effect it will log the optional projects that could not be resolved.
+ projectSelector.getOptionalProjectsBySelectors( request, session.getAllProjects(), allOptionalSelectors );
+ }
+
/**
* Check whether any of the requested optional profiles were not activated or deactivated.
* @param session the Maven session.
@@ -650,11 +673,8 @@ public class DefaultMaven
if ( !notFoundOptionalProfiles.isEmpty() )
{
- final String message = String.format(
- "The requested optional profiles [%s] could not be activated or deactivated because they "
- + "do not exist.", String.join( ", ", notFoundOptionalProfiles )
- );
- logger.info( message );
+ logger.info( "The requested optional profiles {} could not be activated or deactivated because they do not"
+ + " exist.", notFoundOptionalProfiles );
}
}
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 ff863df4a..0d4f6ca45 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
@@ -25,10 +25,8 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
@@ -73,6 +71,7 @@ public class DefaultGraphBuilder
private final PomlessCollectionStrategy pomlessCollectionStrategy;
private final MultiModuleCollectionStrategy multiModuleCollectionStrategy;
private final RequestPomCollectionStrategy requestPomCollectionStrategy;
+ private final ProjectSelector projectSelector;
@Inject
public DefaultGraphBuilder( BuildResumptionDataRepository buildResumptionDataRepository,
@@ -84,6 +83,7 @@ public class DefaultGraphBuilder
this.pomlessCollectionStrategy = pomlessCollectionStrategy;
this.multiModuleCollectionStrategy = multiModuleCollectionStrategy;
this.requestPomCollectionStrategy = requestPomCollectionStrategy;
+ this.projectSelector = new ProjectSelector(); // if necessary switch to DI
}
@Override
@@ -186,9 +186,9 @@ public class DefaultGraphBuilder
{
Set<MavenProject> selectedProjects = new HashSet<>( requiredSelectors.size() + optionalSelectors.size() );
selectedProjects.addAll(
- getProjectsBySelectors( request, allSortedProjects, requiredSelectors, true ) );
+ projectSelector.getRequiredProjectsBySelectors( request, allSortedProjects, requiredSelectors ) );
selectedProjects.addAll(
- getProjectsBySelectors( request, allSortedProjects, optionalSelectors, false ) );
+ projectSelector.getOptionalProjectsBySelectors( request, allSortedProjects, optionalSelectors ) );
// it can be empty when an optional project is missing from the reactor, fallback to returning all projects
if ( !selectedProjects.isEmpty() )
@@ -206,46 +206,6 @@ public class DefaultGraphBuilder
return result;
}
- private Set<MavenProject> getProjectsBySelectors( MavenExecutionRequest request, List<MavenProject> projects,
- Set<String> projectSelectors, boolean required )
- throws MavenExecutionException
- {
- Set<MavenProject> selectedProjects = new LinkedHashSet<>();
- File reactorDirectory = getReactorDirectory( request );
-
- for ( String selector : projectSelectors )
- {
- Optional<MavenProject> optSelectedProject = projects.stream()
- .filter( project -> isMatchingProject( project, selector, reactorDirectory ) )
- .findFirst();
- if ( !optSelectedProject.isPresent() )
- {
- String message = "Could not find the selected project in the reactor: " + selector;
- if ( required )
- {
- throw new MavenExecutionException( message, request.getPom() );
- }
- else
- {
- LOGGER.info( message );
- break;
- }
- }
-
- MavenProject selectedProject = optSelectedProject.get();
-
- selectedProjects.add( selectedProject );
-
- List<MavenProject> children = selectedProject.getCollectedProjects();
- if ( children != null && request.isRecursive() )
- {
- selectedProjects.addAll( children );
- }
- }
-
- return selectedProjects;
- }
-
private List<MavenProject> trimResumedProjects( List<MavenProject> projects, ProjectDependencyGraph graph,
MavenExecutionRequest request )
throws MavenExecutionException
@@ -254,12 +214,12 @@ public class DefaultGraphBuilder
if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
{
- File reactorDirectory = getReactorDirectory( request );
+ File reactorDirectory = projectSelector.getBaseDirectoryFromRequest( request );
String selector = request.getResumeFrom();
MavenProject resumingFromProject = projects.stream()
- .filter( project -> isMatchingProject( project, selector, reactorDirectory ) )
+ .filter( project -> projectSelector.isMatchingProject( project, selector, reactorDirectory ) )
.findFirst()
.orElseThrow( () -> new MavenExecutionException(
"Could not find project to resume reactor build from: " + selector + " vs "
@@ -286,8 +246,10 @@ public class DefaultGraphBuilder
{
Set<MavenProject> excludedProjects = new HashSet<>( requiredSelectors.size() + optionalSelectors.size() );
List<MavenProject> allProjects = graph.getAllProjects();
- excludedProjects.addAll( getProjectsBySelectors( request, allProjects, requiredSelectors, true ) );
- excludedProjects.addAll( getProjectsBySelectors( request, allProjects, optionalSelectors, false ) );
+ excludedProjects.addAll(
+ projectSelector.getRequiredProjectsBySelectors( request, allProjects, requiredSelectors ) );
+ excludedProjects.addAll(
+ projectSelector.getOptionalProjectsBySelectors( request, allProjects, optionalSelectors ) );
result = new ArrayList<>( projects );
result.removeAll( excludedProjects );
@@ -398,51 +360,6 @@ public class DefaultGraphBuilder
return projectNames.toString();
}
- private boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory )
- {
- // [groupId]:artifactId
- if ( selector.indexOf( ':' ) >= 0 )
- {
- String id = ':' + project.getArtifactId();
-
- if ( id.equals( selector ) )
- {
- return true;
- }
-
- id = project.getGroupId() + id;
-
- return id.equals( selector );
- }
-
- // relative path, e.g. "sub", "../sub" or "."
- else if ( reactorDirectory != null )
- {
- File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() );
-
- if ( selectedProject.isFile() )
- {
- return selectedProject.equals( project.getFile() );
- }
- else if ( selectedProject.isDirectory() )
- {
- return selectedProject.equals( project.getBasedir() );
- }
- }
-
- return false;
- }
-
- private File getReactorDirectory( MavenExecutionRequest request )
- {
- if ( request.getBaseDirectory() != null )
- {
- return new File( request.getBaseDirectory() );
- }
-
- return null;
- }
-
// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Project collection
diff --git a/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java b/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
new file mode 100644
index 000000000..bc81abc2b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
@@ -0,0 +1,158 @@
+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 org.apache.maven.MavenExecutionException;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.project.MavenProject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Utility class to extract {@link MavenProject} from the project graph during the execution phase based on optional or
+ * required selectors.
+ */
+public final class ProjectSelector
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger( ProjectSelector.class );
+
+ public Set<MavenProject> getRequiredProjectsBySelectors( MavenExecutionRequest request, List<MavenProject> projects,
+ Set<String> projectSelectors )
+ throws MavenExecutionException
+ {
+ Set<MavenProject> selectedProjects = new LinkedHashSet<>();
+ File baseDirectory = getBaseDirectoryFromRequest( request );
+ for ( String selector : projectSelectors )
+ {
+ Optional<MavenProject> optSelectedProject =
+ findOptionalProjectBySelector( projects, baseDirectory, selector );
+ if ( !optSelectedProject.isPresent() )
+ {
+ String message = "Could not find the selected project in the reactor: " + selector;
+ throw new MavenExecutionException( message, request.getPom() );
+ }
+
+ MavenProject selectedProject = optSelectedProject.get();
+
+ selectedProjects.add( selectedProject );
+ selectedProjects.addAll( getChildProjects( selectedProject, request ) );
+ }
+
+ return selectedProjects;
+ }
+
+ public Set<MavenProject> getOptionalProjectsBySelectors( MavenExecutionRequest request, List<MavenProject> projects,
+ Set<String> projectSelectors )
+ {
+ Set<MavenProject> resolvedOptionalProjects = new LinkedHashSet<>();
+ Set<String> unresolvedOptionalSelectors = new HashSet<>();
+ File baseDirectory = getBaseDirectoryFromRequest( request );
+ for ( String selector : projectSelectors )
+ {
+ Optional<MavenProject> optSelectedProject =
+ findOptionalProjectBySelector( projects, baseDirectory, selector );
+ if ( optSelectedProject.isPresent() )
+ {
+ resolvedOptionalProjects.add( optSelectedProject.get() );
+ resolvedOptionalProjects.addAll( getChildProjects( optSelectedProject.get(), request ) );
+ }
+ else
+ {
+ unresolvedOptionalSelectors.add( selector );
+ }
+ }
+
+ if ( !unresolvedOptionalSelectors.isEmpty() )
+ {
+ LOGGER.info( "The requested optional projects {} do not exist.", unresolvedOptionalSelectors );
+ }
+
+ return resolvedOptionalProjects;
+ }
+
+ private List<MavenProject> getChildProjects( MavenProject parent, MavenExecutionRequest request )
+ {
+ final List<MavenProject> children = parent.getCollectedProjects();
+ if ( children != null && request.isRecursive() )
+ {
+ return children;
+ }
+ else
+ {
+ return new ArrayList<>();
+ }
+ }
+
+ private Optional<MavenProject> findOptionalProjectBySelector( List<MavenProject> projects, File reactorDirectory,
+ String selector )
+ {
+ return projects.stream()
+ .filter( project -> isMatchingProject( project, selector, reactorDirectory ) )
+ .findFirst();
+ }
+
+ File getBaseDirectoryFromRequest( MavenExecutionRequest request )
+ {
+ return request.getBaseDirectory() != null ? new File( request.getBaseDirectory() ) : null;
+ }
+
+ boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory )
+ {
+ // [groupId]:artifactId
+ if ( selector.contains( ":" ) )
+ {
+ String id = ':' + project.getArtifactId();
+
+ if ( id.equals( selector ) )
+ {
+ return true;
+ }
+
+ id = project.getGroupId() + id;
+
+ return id.equals( selector );
+ }
+
+ // relative path, e.g. "sub", "../sub" or "."
+ else if ( reactorDirectory != null )
+ {
+ File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() );
+
+ if ( selectedProject.isFile() )
+ {
+ return selectedProject.equals( project.getFile() );
+ }
+ else if ( selectedProject.isDirectory() )
+ {
+ return selectedProject.equals( project.getBasedir() );
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/graph/ProjectSelectorTest.java b/maven-core/src/test/java/org/apache/maven/graph/ProjectSelectorTest.java
new file mode 100644
index 000000000..34bb4453f
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/graph/ProjectSelectorTest.java
@@ -0,0 +1,221 @@
+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 org.apache.maven.MavenExecutionException;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EmptySource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class ProjectSelectorTest
+{
+ private final ProjectSelector sut = new ProjectSelector();
+ private final MavenExecutionRequest mavenExecutionRequest = mock( MavenExecutionRequest.class );
+
+ @Test
+ void getBaseDirectoryFromRequestWhenDirectoryIsNullReturnNull()
+ {
+ when( mavenExecutionRequest.getBaseDirectory() ).thenReturn( null );
+
+ final File baseDirectoryFromRequest = sut.getBaseDirectoryFromRequest( mavenExecutionRequest );
+
+ assertThat( baseDirectoryFromRequest, nullValue() );
+ }
+
+ @Test
+ void getBaseDirectoryFromRequestWhenDirectoryIsValidReturnFile()
+ {
+ when( mavenExecutionRequest.getBaseDirectory() ).thenReturn( "path/to/file" );
+
+ final File baseDirectoryFromRequest = sut.getBaseDirectoryFromRequest( mavenExecutionRequest );
+
+ assertThat( baseDirectoryFromRequest, notNullValue() );
+ assertThat( baseDirectoryFromRequest.getPath(), is( new File( "path/to/file" ).getPath() ) );
+ }
+
+ @ParameterizedTest
+ @ValueSource( strings = {":wrong-selector", "wrong-selector"} )
+ @EmptySource
+ void isMatchingProjectNoMatchOnSelectorReturnsFalse( String selector )
+ {
+ final boolean result = sut.isMatchingProject( createMavenProject("maven-core" ), selector, null );
+ assertThat( result, is( false ) );
+ }
+
+ @ParameterizedTest
+ @ValueSource( strings = {":maven-core", "org.apache.maven:maven-core"} )
+ void isMatchingProjectMatchOnSelectorReturnsTrue( String selector )
+ {
+ final boolean result = sut.isMatchingProject( createMavenProject("maven-core" ), selector, null );
+ assertThat( result, is( true ) );
+ }
+
+ @Test
+ void isMatchingProjectMatchOnFileReturnsTrue() throws IOException
+ {
+ final File tempFile = File.createTempFile( "maven-core-unit-test-pom", ".xml" );
+ final String selector = tempFile.getName();
+ final MavenProject mavenProject = createMavenProject("maven-core" );
+ mavenProject.setFile( tempFile );
+
+ final boolean result = sut.isMatchingProject( mavenProject, selector, tempFile.getParentFile() );
+
+ tempFile.delete();
+ assertThat( result, is( true ) );
+ }
+
+ @Test
+ void isMatchingProjectMatchOnDirectoryReturnsTrue(@TempDir File tempDir)
+ {
+ String selector = "maven-core";
+ final File tempProjectDir = new File( tempDir, "maven-core" );
+ tempProjectDir.mkdir();
+ final MavenProject mavenProject = createMavenProject("maven-core" );
+ mavenProject.setFile( new File( tempProjectDir, "some-file.xml" ) );
+
+ final boolean result = sut.isMatchingProject( mavenProject, selector, tempDir );
+
+ tempProjectDir.delete();
+ assertThat( result, is( true ) );
+ }
+
+ @Test
+ void getOptionalProjectsBySelectorsReturnsMatches()
+ {
+ final HashSet<String> selectors = new HashSet<>();
+ selectors.add( ":maven-core" );
+ selectors.add( ":optional" );
+
+ final MavenProject mavenProject = createMavenProject("maven-core" );
+ final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+
+ final Set<MavenProject> optionalProjectsBySelectors =
+ sut.getOptionalProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+
+ assertThat( optionalProjectsBySelectors.size(), is( 1 ) );
+ assertThat( optionalProjectsBySelectors, contains( mavenProject ) );
+ }
+
+ @Test
+ void getRequiredProjectsBySelectorsThrowsMavenExecutionException()
+ {
+ final HashSet<String> selectors = new HashSet<>();
+ selectors.add( ":maven-core" );
+ selectors.add( ":required" );
+
+ final MavenProject mavenProject = createMavenProject("maven-core" );
+ final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+
+ final MavenExecutionException exception = assertThrows( MavenExecutionException.class,
+ () -> sut.getRequiredProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors ) );
+ assertThat( exception.getMessage(), containsString( "Could not find" ) );
+ assertThat( exception.getMessage(), containsString( ":required" ) );
+ }
+
+ @Test
+ void getRequiredProjectsBySelectorsReturnsProject() throws MavenExecutionException
+ {
+ final HashSet<String> selectors = new HashSet<>();
+ selectors.add( ":maven-core" );
+
+ final MavenProject mavenProject = createMavenProject("maven-core" );
+ final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+
+ final Set<MavenProject> requiredProjectsBySelectors =
+ sut.getRequiredProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+
+ assertThat( requiredProjectsBySelectors.size(), is( 1 ) );
+ assertThat( requiredProjectsBySelectors, contains( mavenProject ) );
+ }
+
+ @Test
+ void getRequiredProjectsBySelectorsReturnsProjectWithChildProjects() throws MavenExecutionException
+ {
+ when( mavenExecutionRequest.isRecursive() ).thenReturn( true );
+
+ final HashSet<String> selectors = new HashSet<>();
+ selectors.add( ":maven-core" );
+
+ final MavenProject mavenProject = createMavenProject("maven-core" );
+ final MavenProject child = createMavenProject("maven-core-child" );
+ mavenProject.setCollectedProjects( Collections.singletonList( child ) );
+ final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+
+ final Set<MavenProject> requiredProjectsBySelectors =
+ sut.getRequiredProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+
+ assertThat( requiredProjectsBySelectors.size(), is( 2 ) );
+ assertThat( requiredProjectsBySelectors, contains( mavenProject, child ) );
+ }
+
+ @Test
+ void getOptionalProjectsBySelectorsReturnsProjectWithChildProjects()
+ {
+ when( mavenExecutionRequest.isRecursive() ).thenReturn( true );
+
+ final HashSet<String> selectors = new HashSet<>();
+ selectors.add( ":maven-core" );
+
+ final MavenProject mavenProject = createMavenProject("maven-core" );
+ final MavenProject child = createMavenProject("maven-core-child" );
+ mavenProject.setCollectedProjects( Collections.singletonList( child ) );
+ final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+
+ final Set<MavenProject> optionalProjectsBySelectors =
+ sut.getOptionalProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+
+ assertThat( optionalProjectsBySelectors.size(), is( 2 ) );
+ assertThat( optionalProjectsBySelectors, contains( mavenProject, child ) );
+ }
+
+ private MavenProject createMavenProject(String artifactId )
+ {
+ MavenProject mavenProject = new MavenProject();
+ mavenProject.setGroupId( "org.apache.maven" );
+ mavenProject.setArtifactId( artifactId );
+ mavenProject.setVersion( "1.0" );
+ mavenProject.setFile( new File( artifactId, "some-dir" ) );
+ mavenProject.setCollectedProjects( new ArrayList<>() );
+ return mavenProject;
+ }
+
+}