This is an automated email from the ASF dual-hosted git repository. slachiewicz pushed a commit to branch maven-plugin-tools in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git
commit 1c3ede303c30b9d258516e45dbc4089baba8fdda Author: Slawomir Jaranowski <[email protected]> AuthorDate: Thu Sep 16 19:19:51 2021 +0200 [MINVOKER-271] fix detection of setup projects fix implementation according to documentations on params: - invokerTest - pomExcludes - setupIncludes Closes #68 --- pom.xml | 14 +- .../maven/plugins/invoker/AbstractInvokerMojo.java | 175 +++++++++------------ src/main/mdo/invocation.mdo | 12 +- .../maven/plugins/invoker/InvokerMojoTest.java | 114 ++++++++++++-- .../maven/plugins/invoker/InvokerSessionTest.java | 2 +- 5 files changed, 189 insertions(+), 128 deletions(-) diff --git a/pom.xml b/pom.xml index a0ece81..866c7b4 100644 --- a/pom.xml +++ b/pom.xml @@ -280,7 +280,19 @@ under the License. <version>${mavenVersion}</version> <scope>test</scope> </dependency> - + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.20.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>1.7.32</version> + <scope>test</scope> + </dependency> + </dependencies> <build> diff --git a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java index 44d4a7e..fc2d7b8 100644 --- a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java +++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java @@ -89,6 +89,7 @@ import java.nio.file.Paths; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -741,7 +742,7 @@ public abstract class AbstractInvokerMojo + "pom File parameter. Reason: " + e.getMessage(), e ); } - buildJobs = Collections.singletonList( new BuildJob( pom.getName(), BuildJob.Type.NORMAL ) ); + buildJobs = Collections.singletonList( new BuildJob( pom.getName() ) ); } if ( buildJobs.isEmpty() ) @@ -796,23 +797,13 @@ public abstract class AbstractInvokerMojo } // First run setup jobs. - List<BuildJob> setupBuildJobs = null; - try - { - setupBuildJobs = getSetupBuildJobsFromFolders(); - } - catch ( IOException e ) - { - getLog().error( "Failure during scanning of folders.", e ); - // TODO: Check shouldn't we fail in case of problems? - } + List<BuildJob> setupBuildJobs = getSetupJobs( buildJobs ); if ( !setupBuildJobs.isEmpty() ) { - // Run setup jobs in single thread - // mode. + // Run setup jobs in single thread mode. // - // Some Idea about ordering? + // Jobs are ordered according to ordinal value from invoker.properties getLog().info( "Running " + setupBuildJobs.size() + " setup job" + ( ( setupBuildJobs.size() < 2 ) ? "" : "s" ) + ":" ); runBuilds( projectsDir, setupBuildJobs, 1 ); @@ -881,12 +872,18 @@ public abstract class AbstractInvokerMojo } } + private List<BuildJob> getSetupJobs( List<BuildJob> buildJobs ) + { + return buildJobs.stream(). + filter( buildJob -> buildJob.getType().equals( BuildJob.Type.SETUP ) ). + collect( Collectors.toList() ); + } + private List<BuildJob> getNonSetupJobs( List<BuildJob> buildJobs ) { return buildJobs.stream(). filter( buildJob -> !buildJob.getType().equals( BuildJob.Type.SETUP ) ). collect( Collectors.toList() ); - } private void handleScriptRunnerWithScriptClassPath() @@ -2399,11 +2396,46 @@ public abstract class AbstractInvokerMojo } } + private List<String> calculateIncludes() + { + if ( invokerTest != null ) + { + String[] testRegexes = StringUtils.split( invokerTest, "," ); + return Arrays.stream( testRegexes ) + .map( String::trim ) + .filter( s -> !s.isEmpty() ) + .filter( s -> !s.startsWith( "!" ) ) + .collect( Collectors.toList() ); + } + else + { + Set<String> uniqueIncludes = new HashSet<>(); + uniqueIncludes.addAll( pomIncludes ); + uniqueIncludes.addAll( setupIncludes ); + return new ArrayList<>( uniqueIncludes ); + } + } + private List<String> calculateExcludes() throws IOException { - List<String> excludes = - ( pomExcludes != null ) ? new ArrayList<>( pomExcludes ) : new ArrayList<>(); + List<String> excludes; + + if ( invokerTest != null ) + { + String[] testRegexes = StringUtils.split( invokerTest, "," ); + excludes = Arrays.stream( testRegexes ) + .map( String::trim ) + .filter( s -> !s.isEmpty() ) + .filter( s -> s.startsWith( "!" ) ) + .map( s -> s.substring( 1 ) ) + .collect( Collectors.toList() ); + } + else + { + excludes = pomExcludes != null ? new ArrayList<>( pomExcludes ) : new ArrayList<>(); + } + if ( this.settingsFile != null ) { String exclude = relativizePath( this.settingsFile, projectsDirectory.getCanonicalPath() ); @@ -2417,25 +2449,6 @@ public abstract class AbstractInvokerMojo } - /** - * @return The list of setupUp jobs. - * @throws IOException - * @see {@link #setupIncludes} - */ - private List<BuildJob> getSetupBuildJobsFromFolders() - throws IOException, MojoExecutionException - { - List<String> excludes = calculateExcludes(); - - List<BuildJob> setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP ); - if ( getLog().isDebugEnabled() ) - { - getLog().debug( "Setup projects: " + setupPoms ); - } - - return setupPoms; - } - private static class OrdinalComparator implements Comparator<BuildJob> { private static final OrdinalComparator INSTANCE = new OrdinalComparator(); @@ -2456,62 +2469,35 @@ public abstract class AbstractInvokerMojo List<BuildJob> getBuildJobs() throws IOException, MojoExecutionException { - List<BuildJob> buildJobs; - if ( invokerTest == null ) - { - List<String> excludes = calculateExcludes(); + List<String> includes = calculateIncludes(); + List<String> excludes = calculateExcludes(); + List<BuildJob> buildJobsAll = scanProjectsDirectory( includes, excludes ); + List<BuildJob> buildJobsSetup = scanProjectsDirectory( setupIncludes, excludes ); - List<BuildJob> setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP ); - if ( getLog().isDebugEnabled() ) - { - getLog().debug( "Setup projects: " + Collections.singletonList( setupPoms ) ); - } + List<String> setupProjects = buildJobsSetup.stream() + .map( BuildJob::getProject ) + .collect( Collectors.toList() ); - List<BuildJob> normalPoms = scanProjectsDirectory( pomIncludes, excludes, BuildJob.Type.NORMAL ); - Map<String, BuildJob> uniquePoms = new LinkedHashMap<>(); - for ( BuildJob setupPom : setupPoms ) - { - uniquePoms.put( setupPom.getProject(), setupPom ); - } - for ( BuildJob normalPom : normalPoms ) - { - if ( !uniquePoms.containsKey( normalPom.getProject() ) ) - { - uniquePoms.put( normalPom.getProject(), normalPom ); - } - } - - buildJobs = new ArrayList<>( uniquePoms.values() ); - } - else + for ( BuildJob job : buildJobsAll ) { - String[] testRegexes = StringUtils.split( invokerTest, "," ); - List<String> includes = new ArrayList<>( testRegexes.length ); - List<String> excludes = new ArrayList<>(); - - for ( String regex : testRegexes ) + if ( setupProjects.contains( job.getProject() ) ) { - // user just use -Dinvoker.test=MWAR191,MNG111 to use a directory thats the end is not pom.xml - if ( regex.startsWith( "!" ) ) - { - excludes.add( regex.substring( 1 ) ); - } - else - { - includes.add( regex ); - } + job.setType( BuildJob.Type.SETUP ); } - - // it would be nice if we could figure out what types these are... but perhaps - // not necessary for the -Dinvoker.test=xxx t - buildJobs = scanProjectsDirectory( includes, excludes, BuildJob.Type.DIRECT ); + InvokerProperties invokerProperties = + getInvokerProperties( new File( projectsDirectory, job.getProject() ).getParentFile(), + null ); + job.setOrdinal( invokerProperties.getOrdinal() ); } - relativizeProjectPaths( buildJobs ); + // setup ordinal values to have an order here + buildJobsAll.sort( OrdinalComparator.INSTANCE ); + + relativizeProjectPaths( buildJobsAll ); - return buildJobs; + return buildJobsAll; } /** @@ -2522,12 +2508,11 @@ public abstract class AbstractInvokerMojo * * @param includes The include patterns for the scanner, may be <code>null</code>. * @param excludes The exclude patterns for the scanner, may be <code>null</code> to exclude nothing. - * @param type The type to assign to the resulting build jobs, must not be <code>null</code>. * @return The build jobs matching the patterns, never <code>null</code>. * @throws java.io.IOException If the project directory could not be scanned. */ - private List<BuildJob> scanProjectsDirectory( List<String> includes, List<String> excludes, String type ) - throws IOException, MojoExecutionException + private List<BuildJob> scanProjectsDirectory( List<String> includes, List<String> excludes ) + throws IOException { if ( !projectsDirectory.isDirectory() ) { @@ -2552,7 +2537,7 @@ public abstract class AbstractInvokerMojo for ( String includedFile : scanner.getIncludedFiles() ) { - matches.put( includedFile, new BuildJob( includedFile, type ) ); + matches.put( includedFile, new BuildJob( includedFile ) ); } for ( String includedDir : scanner.getIncludedDirectories() ) @@ -2560,27 +2545,15 @@ public abstract class AbstractInvokerMojo String includedFile = includedDir + File.separatorChar + "pom.xml"; if ( new File( scanner.getBasedir(), includedFile ).isFile() ) { - matches.put( includedFile, new BuildJob( includedFile, type ) ); + matches.put( includedFile, new BuildJob( includedFile ) ); } else { - matches.put( includedDir, new BuildJob( includedDir, type ) ); + matches.put( includedDir, new BuildJob( includedDir ) ); } } - List<BuildJob> projects = new ArrayList<>( matches.size() ); - - // setup ordinal values to have an order here - for ( BuildJob buildJob : matches.values() ) - { - InvokerProperties invokerProperties = - getInvokerProperties( new File( projectsDirectory, buildJob.getProject() ).getParentFile(), - null ); - buildJob.setOrdinal( invokerProperties.getOrdinal() ); - projects.add( buildJob ); - } - projects.sort( OrdinalComparator.INSTANCE ); - return projects; + return new ArrayList<>( matches.values() ); } /** diff --git a/src/main/mdo/invocation.mdo b/src/main/mdo/invocation.mdo index bc488f4..9abecec 100644 --- a/src/main/mdo/invocation.mdo +++ b/src/main/mdo/invocation.mdo @@ -95,6 +95,7 @@ under the License. <required>true</required> <type>String</type> <description>The type of the build job.</description> + <defaultValue>normal</defaultValue> </field> <field xml.attribute="true"> <name>ordinal</name> @@ -124,15 +125,13 @@ under the License. } /** - * Creates a new build job with the specified project path and type. + * Creates a new build job with the specified project path. * * @param project The path to the project. - * @param type The type of the build job. */ - public BuildJob( String project, String type ) + public BuildJob( String project ) { this.project = project; - this.type = type; } ]]></code> </codeSegment> @@ -197,11 +196,6 @@ under the License. */ public static final String NORMAL = "normal"; - /** - * A build job that was directly selected via the <code>-Dinvoker.test=xxx,yyy</code> parameter. - */ - public static final String DIRECT = "direct"; - } ]]></code> </codeSegment> diff --git a/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java b/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java index 1c22131..94f69f4 100644 --- a/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java +++ b/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java @@ -19,15 +19,17 @@ package org.apache.maven.plugins.invoker; * under the License. */ -import java.io.File; -import java.util.Collections; -import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import org.apache.maven.plugin.testing.AbstractMojoTestCase; import org.apache.maven.plugins.invoker.model.BuildJob; import org.apache.maven.project.MavenProject; import org.apache.maven.settings.Settings; +import java.io.File; +import java.util.Collections; +import java.util.List; + /** * @author Olivier Lamy * @since 18 nov. 07 @@ -35,6 +37,11 @@ import org.apache.maven.settings.Settings; public class InvokerMojoTest extends AbstractMojoTestCase { + private static final String DUMMY_PROJECT = "dummy" + File.separator + "pom.xml"; + private static final String GOALS_FROM_FILE_PROJECT = "goals-from-file" + File.separator + "pom.xml"; + private static final String INTERPOLATION_PROJECT = "interpolation" + File.separator + "pom.xml"; + private static final String PROFILES_FROM_FILE_PROJECT = "profiles-from-file"; + private MavenProject getMavenProject() { MavenProject mavenProject = new MavenProject(); @@ -44,47 +51,123 @@ public class InvokerMojoTest extends AbstractMojoTestCase public void testSingleInvokerTest() throws Exception { + // given InvokerMojo invokerMojo = new InvokerMojo(); String dirPath = getBasedir() + "/src/test/resources/unit"; - List<String> goals = invokerMojo.getGoals( new File( dirPath ) ); - assertEquals( 1, goals.size() ); setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) ); setVariableValueToObject( invokerMojo, "invokerPropertiesFile", "invoker.properties" ); setVariableValueToObject( invokerMojo, "project", getMavenProject() ); setVariableValueToObject( invokerMojo, "invokerTest", "*dummy*" ); setVariableValueToObject( invokerMojo, "settings", new Settings() ); - List<BuildJob> poms = invokerMojo.getBuildJobs(); - assertEquals( 1, poms.size() ); + + // when + List<BuildJob> jobs = invokerMojo.getBuildJobs(); + + // then + assertThat( jobs ) + .map( BuildJob::getProject ) + .containsExactlyInAnyOrder( DUMMY_PROJECT ); } public void testMultiInvokerTest() throws Exception { + // given InvokerMojo invokerMojo = new InvokerMojo(); String dirPath = getBasedir() + "/src/test/resources/unit"; - List<String> goals = invokerMojo.getGoals( new File( dirPath ) ); - assertEquals( 1, goals.size() ); setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) ); setVariableValueToObject( invokerMojo, "invokerPropertiesFile", "invoker.properties" ); setVariableValueToObject( invokerMojo, "project", getMavenProject() ); setVariableValueToObject( invokerMojo, "invokerTest", "*dummy*,*terpolatio*" ); setVariableValueToObject( invokerMojo, "settings", new Settings() ); - List<BuildJob> poms = invokerMojo.getBuildJobs(); - assertEquals( 2, poms.size() ); + + // when + List<BuildJob> jobs = invokerMojo.getBuildJobs(); + + // then + assertThat( jobs ) + .map( BuildJob::getProject ) + .containsExactlyInAnyOrder( DUMMY_PROJECT, INTERPOLATION_PROJECT ); } public void testFullPatternInvokerTest() throws Exception { + // given InvokerMojo invokerMojo = new InvokerMojo(); String dirPath = getBasedir() + "/src/test/resources/unit"; - List<String> goals = invokerMojo.getGoals( new File( dirPath ) ); - assertEquals( 1, goals.size() ); setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) ); setVariableValueToObject( invokerMojo, "invokerPropertiesFile", "invoker.properties" ); setVariableValueToObject( invokerMojo, "project", getMavenProject() ); setVariableValueToObject( invokerMojo, "invokerTest", "*" ); setVariableValueToObject( invokerMojo, "settings", new Settings() ); - List<BuildJob> poms = invokerMojo.getBuildJobs(); - assertEquals( 4, poms.size() ); + + // when + List<BuildJob> jobs = invokerMojo.getBuildJobs(); + + // then + assertThat( jobs ) + .map( BuildJob::getProject ) + .containsExactlyInAnyOrder( + DUMMY_PROJECT, GOALS_FROM_FILE_PROJECT, + INTERPOLATION_PROJECT, PROFILES_FROM_FILE_PROJECT ); + } + + public void testSetupInProjectList() throws Exception + { + // given + InvokerMojo invokerMojo = new InvokerMojo(); + String dirPath = getBasedir() + "/src/test/resources/unit"; + setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) ); + setVariableValueToObject( invokerMojo, "invokerPropertiesFile", "invoker.properties" ); + setVariableValueToObject( invokerMojo, "project", getMavenProject() ); + setVariableValueToObject( invokerMojo, "settings", new Settings() ); + setVariableValueToObject( invokerMojo, "setupIncludes", Collections.singletonList( "dum*/pom.xml" ) ); + + // when + List<BuildJob> jobs = invokerMojo.getBuildJobs(); + + // then + + // we have all projects with pom.xml + assertThat( jobs ) + .map( BuildJob::getProject ) + .containsExactlyInAnyOrder( + DUMMY_PROJECT, GOALS_FROM_FILE_PROJECT, INTERPOLATION_PROJECT ); + + // and we have one setup project + assertThat( jobs ) + .filteredOn( job -> BuildJob.Type.SETUP.equals( job.getType() ) ) + .map( BuildJob::getProject ) + .containsExactlyInAnyOrder( DUMMY_PROJECT ); + } + + public void testSetupProjectIsFiltered() throws Exception + { + // given + InvokerMojo invokerMojo = new InvokerMojo(); + String dirPath = getBasedir() + "/src/test/resources/unit"; + setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) ); + setVariableValueToObject( invokerMojo, "invokerPropertiesFile", "invoker.properties" ); + setVariableValueToObject( invokerMojo, "project", getMavenProject() ); + setVariableValueToObject( invokerMojo, "settings", new Settings() ); + setVariableValueToObject( invokerMojo, "setupIncludes", Collections.singletonList( "dum*/pom.xml" ) ); + setVariableValueToObject( invokerMojo, "invokerTest", "*from-file*" ); + + + // when + List<BuildJob> jobs = invokerMojo.getBuildJobs(); + + // then + + // we have filtered projects + assertThat( jobs ) + .map( BuildJob::getProject ) + .containsExactlyInAnyOrder( + GOALS_FROM_FILE_PROJECT, PROFILES_FROM_FILE_PROJECT ); + + // and we don't have a setup project + assertThat( jobs ) + .filteredOn( job -> BuildJob.Type.SETUP.equals( job.getType() ) ) + .isEmpty(); } public void testAlreadyCloned() @@ -116,5 +199,4 @@ public class InvokerMojoTest extends AbstractMojoTestCase assertEquals( expectedParallelThreads, invokerMojo.getParallelThreadsCount() ); } } - } diff --git a/src/test/java/org/apache/maven/plugins/invoker/InvokerSessionTest.java b/src/test/java/org/apache/maven/plugins/invoker/InvokerSessionTest.java index bd5c029..8960670 100644 --- a/src/test/java/org/apache/maven/plugins/invoker/InvokerSessionTest.java +++ b/src/test/java/org/apache/maven/plugins/invoker/InvokerSessionTest.java @@ -40,7 +40,7 @@ public class InvokerSessionTest public void skipSummary() { Log logger = mock( Log.class ); - BuildJob skippedBuildJob = new BuildJob( "minvoker-279", null ); + BuildJob skippedBuildJob = new BuildJob( "minvoker-279" ); skippedBuildJob.setResult( BuildJob.Result.SKIPPED ); InvokerSession session = new InvokerSession( Collections.singletonList( skippedBuildJob ) );
