This is an automated email from the ASF dual-hosted git repository. olamy pushed a commit to branch MINVOKER-174_build_job_order in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git
commit b48c8e1189fdb1436e27ccfea0ec75ca50968970 Author: olivier lamy <[email protected]> AuthorDate: Thu Sep 5 17:21:58 2019 +1000 [MINVOKER-174] add a property to configure build order Signed-off-by: olivier lamy <[email protected]> --- src/it/project-setup/pom.xml | 1 + .../src/it/project3/invoker.properties | 18 +++ .../src/it/project6/invoker.properties | 18 +++ src/it/project-setup/{ => src/it/project6}/pom.xml | 41 +------ src/it/project-setup/verify.bsh | 8 ++ .../maven/plugins/invoker/AbstractInvokerMojo.java | 126 ++++++++++----------- .../maven/plugins/invoker/InvokerProperties.java | 16 ++- .../maven/plugins/invoker/InvokerSession.java | 5 +- src/main/mdo/invocation.mdo | 9 +- .../maven/plugins/invoker/InvokerMojoTest.java | 30 ++++- 10 files changed, 152 insertions(+), 120 deletions(-) diff --git a/src/it/project-setup/pom.xml b/src/it/project-setup/pom.xml index b68981b..0922bba 100644 --- a/src/it/project-setup/pom.xml +++ b/src/it/project-setup/pom.xml @@ -43,6 +43,7 @@ under the License. <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo> <setupIncludes> <setupInclude>project3</setupInclude> + <setupInclude>project6</setupInclude> </setupIncludes> <pomIncludes> <pomInclude>*/pom.xml</pomInclude> diff --git a/src/it/project-setup/src/it/project3/invoker.properties b/src/it/project-setup/src/it/project3/invoker.properties new file mode 100644 index 0000000..5cf17e6 --- /dev/null +++ b/src/it/project-setup/src/it/project3/invoker.properties @@ -0,0 +1,18 @@ +# 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. + +invoker.ordinal=1 diff --git a/src/it/project-setup/src/it/project6/invoker.properties b/src/it/project-setup/src/it/project6/invoker.properties new file mode 100644 index 0000000..081215b --- /dev/null +++ b/src/it/project-setup/src/it/project6/invoker.properties @@ -0,0 +1,18 @@ +# 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. + +invoker.ordinal=2 diff --git a/src/it/project-setup/pom.xml b/src/it/project-setup/src/it/project6/pom.xml similarity index 52% copy from src/it/project-setup/pom.xml copy to src/it/project-setup/src/it/project6/pom.xml index b68981b..4be5874 100644 --- a/src/it/project-setup/pom.xml +++ b/src/it/project-setup/src/it/project6/pom.xml @@ -21,47 +21,12 @@ under the License. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> - - <groupId>org.apache.maven.plugins.invoker</groupId> - <artifactId>project-setup</artifactId> - <version>1.0-SNAPSHOT</version> + <groupId>test</groupId> + <artifactId>project6</artifactId> + <version>0.1-SNAPSHOT</version> <packaging>pom</packaging> - <description>Test to check that setup projects are run ahead of the other ones.</description> - <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-invoker-plugin</artifactId> - <version>@pom.version@</version> - <configuration> - <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo> - <setupIncludes> - <setupInclude>project3</setupInclude> - </setupIncludes> - <pomIncludes> - <pomInclude>*/pom.xml</pomInclude> - </pomIncludes> - <goals> - <goal>validate</goal> - </goals> - </configuration> - <executions> - <execution> - <id>integration-test</id> - <phase>initialize</phase> - <goals> - <goal>run</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </project> diff --git a/src/it/project-setup/verify.bsh b/src/it/project-setup/verify.bsh index ff4a005..59a985d 100644 --- a/src/it/project-setup/verify.bsh +++ b/src/it/project-setup/verify.bsh @@ -51,6 +51,14 @@ try return false; } + int indexProject3 = log.indexOf( "Building: project3" ); + int indexProject6 = log.indexOf( "Building: project6" ); + if(indexProject3 > indexProject6) + { + System.out.println( "FAILED! project3 should be build before project6" ); + return false; + } + File reportFile = new File( basedir, "target/invoker-reports/BUILD-project1.xml" ); if ( !reportFile.exists() ) { 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 4197c86..da8d390 100644 --- a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java +++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java @@ -93,6 +93,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -566,6 +567,12 @@ public abstract class AbstractInvokerMojo * # Path to an alternate <code>settings.xml</code> to use for Maven invocation with this IT. * # Since plugin version 3.0.1 * invoker.settingsFile = ../ + * + * # An integer value to control run order of projects. sorted in the ascending order of the ordinal. + * In other words, the BuildJobs with the slowest numbers will be executed first + * # Since plugin version 3.2.1 + * invoker.ordinal = 3 + * invoker.ordinal = 1 * </pre> * * @since 1.2 @@ -691,7 +698,7 @@ public abstract class AbstractInvokerMojo setupReportsFolder(); } - BuildJob[] buildJobs; + List<BuildJob> buildJobs; if ( pom == null ) { try @@ -716,10 +723,10 @@ public abstract class AbstractInvokerMojo + "pom File parameter. Reason: " + e.getMessage(), e ); } - buildJobs = new BuildJob[] { new BuildJob( pom.getName(), BuildJob.Type.NORMAL ) }; + buildJobs = Collections.singletonList( new BuildJob( pom.getName(), BuildJob.Type.NORMAL ) ); } - if ( ( buildJobs == null ) || ( buildJobs.length < 1 ) ) + if ( buildJobs.isEmpty() ) { doFailIfNoProjects(); @@ -754,7 +761,7 @@ public abstract class AbstractInvokerMojo } // First run setup jobs. - BuildJob[] setupBuildJobs = null; + List<BuildJob> setupBuildJobs = null; try { setupBuildJobs = getSetupBuildJobsFromFolders(); @@ -765,20 +772,20 @@ public abstract class AbstractInvokerMojo // TODO: Check shouldn't we fail in case of problems? } - if ( ( setupBuildJobs != null ) && ( setupBuildJobs.length > 0 ) ) + if ( !setupBuildJobs.isEmpty() ) { // Run setup jobs in single thread // mode. // // Some Idea about ordering? - getLog().info( "Running " + setupBuildJobs.length + " setup job" - + ( ( setupBuildJobs.length < 2 ) ? "" : "s" ) + ":" ); + getLog().info( "Running " + setupBuildJobs.size() + " setup job" + + ( ( setupBuildJobs.size() < 2 ) ? "" : "s" ) + ":" ); runBuilds( projectsDir, setupBuildJobs, 1 ); getLog().info( "Setup done." ); } // Afterwards run all other jobs. - BuildJob[] nonSetupBuildJobs = getNonSetupJobs( buildJobs ); + List<BuildJob> nonSetupBuildJobs = getNonSetupJobs( buildJobs ); // We will run the non setup jobs with the configured // parallelThreads number. runBuilds( projectsDir, nonSetupBuildJobs, parallelThreads ); @@ -816,7 +823,7 @@ public abstract class AbstractInvokerMojo } } - private BuildJob[] getNonSetupJobs( BuildJob[] buildJobs ) + private List<BuildJob> getNonSetupJobs( List<BuildJob> buildJobs ) { List<BuildJob> result = new LinkedList<>(); for ( BuildJob buildJob : buildJobs ) @@ -826,8 +833,7 @@ public abstract class AbstractInvokerMojo result.add( buildJob ); } } - BuildJob[] buildNonSetupJobs = result.toArray( new BuildJob[result.size()] ); - return buildNonSetupJobs; + return result; } private void handleScriptRunnerWithScriptClassPath() @@ -858,7 +864,7 @@ public abstract class AbstractInvokerMojo scriptRunner.setClassPath( scriptClassPath ); } - private void writeSummaryFile( BuildJob[] buildJobs ) + private void writeSummaryFile( List<BuildJob> buildJobs ) throws MojoExecutionException { @@ -1216,7 +1222,7 @@ public abstract class AbstractInvokerMojo * @param buildJobs The build jobs to run must not be <code>null</code> nor contain <code>null</code> elements. * @throws org.apache.maven.plugin.MojoExecutionException If any build could not be launched. */ - private void runBuilds( final File projectsDir, BuildJob[] buildJobs, int runWithParallelThreads ) + private void runBuilds( final File projectsDir, List<BuildJob> buildJobs, int runWithParallelThreads ) throws MojoExecutionException { if ( !localRepositoryPath.exists() ) @@ -2381,42 +2387,53 @@ public abstract class AbstractInvokerMojo * @throws IOException * @see {@link #setupIncludes} */ - private BuildJob[] getSetupBuildJobsFromFolders() - throws IOException + private List<BuildJob> getSetupBuildJobsFromFolders() + throws IOException, MojoExecutionException { List<String> excludes = calculateExcludes(); - BuildJob[] setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP ); + List<BuildJob> setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP ); if ( getLog().isDebugEnabled() ) { - getLog().debug( "Setup projects: " + Arrays.asList( setupPoms ) ); + getLog().debug( "Setup projects: " + setupPoms ); } return setupPoms; } + private static class OrdinalComparator implements Comparator + { + private static final OrdinalComparator INSTANCE = new OrdinalComparator(); + + @Override + public int compare( Object o1, Object o2 ) + { + return Integer.compare( ( ( BuildJob ) o1 ).getOrdinal(), ( ( BuildJob ) o2 ).getOrdinal() ); + } + } + /** * Gets the build jobs that should be processed. Note that the order of the returned build jobs is significant. * * @return The build jobs to process, may be empty but never <code>null</code>. * @throws java.io.IOException If the projects directory could not be scanned. */ - BuildJob[] getBuildJobs() - throws IOException + List<BuildJob> getBuildJobs() + throws IOException, MojoExecutionException { - BuildJob[] buildJobs; + List<BuildJob> buildJobs; if ( invokerTest == null ) { List<String> excludes = calculateExcludes(); - BuildJob[] setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP ); + List<BuildJob> setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP ); if ( getLog().isDebugEnabled() ) { getLog().debug( "Setup projects: " + Arrays.asList( setupPoms ) ); } - BuildJob[] normalPoms = scanProjectsDirectory( pomIncludes, excludes, BuildJob.Type.NORMAL ); + List<BuildJob> normalPoms = scanProjectsDirectory( pomIncludes, excludes, BuildJob.Type.NORMAL ); Map<String, BuildJob> uniquePoms = new LinkedHashMap<>(); for ( BuildJob setupPom : setupPoms ) @@ -2431,7 +2448,7 @@ public abstract class AbstractInvokerMojo } } - buildJobs = uniquePoms.values().toArray( new BuildJob[uniquePoms.size()] ); + buildJobs = new ArrayList<>( uniquePoms.values() ); } else { @@ -2474,12 +2491,12 @@ public abstract class AbstractInvokerMojo * @return The build jobs matching the patterns, never <code>null</code>. * @throws java.io.IOException If the project directory could not be scanned. */ - private BuildJob[] scanProjectsDirectory( List<String> includes, List<String> excludes, String type ) - throws IOException + private List<BuildJob> scanProjectsDirectory( List<String> includes, List<String> excludes, String type ) + throws IOException, MojoExecutionException { if ( !projectsDirectory.isDirectory() ) { - return new BuildJob[0]; + return Collections.emptyList(); } DirectoryScanner scanner = new DirectoryScanner(); @@ -2516,7 +2533,19 @@ public abstract class AbstractInvokerMojo } } - return matches.values().toArray( new BuildJob[matches.size()] ); + 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 ); + } + Collections.sort( projects, OrdinalComparator.INSTANCE ); + return projects; } /** @@ -2528,7 +2557,7 @@ public abstract class AbstractInvokerMojo * contain <code>null</code> elements. * @throws java.io.IOException If any path could not be relativized. */ - private void relativizeProjectPaths( BuildJob[] buildJobs ) + private void relativizeProjectPaths( List<BuildJob> buildJobs ) throws IOException { String projectsDirPath = projectsDirectory.getCanonicalPath(); @@ -2778,47 +2807,6 @@ public abstract class AbstractInvokerMojo props = new Properties(); } -// Path projectsSourceFolder = this.projectsDirectory.toPath(); -// Path projectsTargetFolder; -// if ( cloneProjectsTo != null ) -// { -// projectsTargetFolder = cloneProjectsTo.toPath(); -// } -// else -// { -// projectsTargetFolder = projectsSourceFolder; -// } -// -// Path projectDir = projectsTargetFolder.relativize( projectDirectory.toPath() ); -// -// for ( int i = 0; i < projectDir.getNameCount(); i++ ) -// { -// Path subInvokerProperties; -// if ( i == 0 ) -// { -// subInvokerProperties = projectsSourceFolder.resolve( invokerPropertiesFile ); -// } -// else -// { -// subInvokerProperties = -// projectsSourceFolder.resolve( projectDir.subpath( 0, i ) ).resolve( invokerPropertiesFile ); -// } -// -// getLog().debug( "Looking for " + subInvokerProperties ); -// -// if ( Files.isRegularFile( subInvokerProperties ) ) -// { -// try ( InputStream in = new FileInputStream( subInvokerProperties.toFile() ) ) -// { -// props.load( in ); -// } -// catch ( IOException e ) -// { -// throw new MojoExecutionException( "Failed to read invoker properties: " + subInvokerProperties ); -// } -// } -// } - File propertiesFile = new File( projectDirectory, invokerPropertiesFile ); if ( propertiesFile.isFile() ) { diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java index e8ba20e..a3b8f3c 100644 --- a/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java +++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java @@ -54,7 +54,8 @@ class InvokerProperties SYSTEM_PROPERTIES_FILE( "invoker.systemPropertiesFile" ), DEBUG( "invoker.debug" ), SETTINGS_FILE ( "invoker.settingsFile" ), - TIMEOUT_IN_SECONDS ( "invoker.timeoutInSeconds" ); + TIMEOUT_IN_SECONDS ( "invoker.timeoutInSeconds" ), + ORDINAL ( "invoker.ordinal" ); private final String key; @@ -137,6 +138,15 @@ class InvokerProperties } /** + * Get the corresponding ordinal value + * @return The ordinal value + */ + public int getOrdinal() + { + return Integer.parseInt( this.properties.getProperty( "invoker.ordinal", "0" ) ); + } + + /** * Gets the specification of JRE versions on which this build job should be run. * * @return The specification of JRE versions or an empty string if not set. @@ -302,14 +312,14 @@ class InvokerProperties String goals = get( InvocationProperty.GOALS, index ); if ( goals != null ) { - request.setGoals( new ArrayList<String>( Arrays.asList( StringUtils.split( goals, ", \t\n\r\f" ) ) ) ); + request.setGoals( new ArrayList<>( Arrays.asList( StringUtils.split( goals, ", \t\n\r\f" ) ) ) ); } String profiles = get( InvocationProperty.PROFILES, index ); if ( profiles != null ) { // CHECKSTYLE_OFF: LineLength - request.setProfiles( new ArrayList<String>( Arrays.asList( StringUtils.split( profiles, + request.setProfiles( new ArrayList<>( Arrays.asList( StringUtils.split( profiles, ", \t\n\r\f" ) ) ) ); // CHECKSTYLE_ON: LineLength } diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java index 7c11479..43ed9bb 100644 --- a/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java +++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java @@ -22,7 +22,6 @@ package org.apache.maven.plugins.invoker; import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.apache.maven.plugin.MojoFailureException; @@ -60,9 +59,9 @@ class InvokerSession * * @param buildJobs The build jobs to set, must not be <code>null</code>. */ - InvokerSession( BuildJob[] buildJobs ) + InvokerSession( List<BuildJob> buildJobs ) { - this.buildJobs = new ArrayList<>( Arrays.asList( buildJobs ) ); + this.buildJobs = new ArrayList<>( buildJobs ); } /** diff --git a/src/main/mdo/invocation.mdo b/src/main/mdo/invocation.mdo index f402423..a019b2d 100644 --- a/src/main/mdo/invocation.mdo +++ b/src/main/mdo/invocation.mdo @@ -96,6 +96,13 @@ under the License. <type>String</type> <description>The type of the build job.</description> </field> + <field xml.attribute="true"> + <name>ordinal</name> + <version>1.0.0</version> + <required>false</required> + <type>int</type> + <description>BuildJobs will be sorted in the ascending order of the ordinal. In other words, the BuildJobs with the slowest numbers will be executed first</description> + </field> </fields> <codeSegments> <codeSegment> @@ -209,4 +216,4 @@ under the License. </codeSegments> </class> </classes> -</model> \ No newline at end of file +</model> 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 b58234c..5d51c40 100644 --- a/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java +++ b/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java @@ -25,6 +25,8 @@ import java.util.List; 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; /** * @author Olivier Lamy @@ -34,6 +36,13 @@ public class InvokerMojoTest extends AbstractMojoTestCase { + private MavenProject getMavenProject() + { + MavenProject mavenProject = new MavenProject(); + mavenProject.setFile(new File("target/foo.txt")); + return mavenProject; + } + public void testSingleInvokerTest() throws Exception { @@ -42,9 +51,12 @@ public class InvokerMojoTest 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*" ); - BuildJob[] poms = invokerMojo.getBuildJobs(); - assertEquals( 1, poms.length ); + setVariableValueToObject( invokerMojo, "settings", new Settings() ); + List<BuildJob> poms = invokerMojo.getBuildJobs(); + assertEquals( 1, poms.size() ); } public void testMultiInvokerTest() @@ -55,9 +67,12 @@ public class InvokerMojoTest 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*" ); - BuildJob[] poms = invokerMojo.getBuildJobs(); - assertEquals( 2, poms.length ); + setVariableValueToObject( invokerMojo, "settings", new Settings() ); + List<BuildJob> poms = invokerMojo.getBuildJobs(); + assertEquals( 2, poms.size() ); } public void testFullPatternInvokerTest() @@ -68,9 +83,12 @@ public class InvokerMojoTest 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", "*" ); - BuildJob[] poms = invokerMojo.getBuildJobs(); - assertEquals( 4, poms.length ); + setVariableValueToObject( invokerMojo, "settings", new Settings() ); + List<BuildJob> poms = invokerMojo.getBuildJobs(); + assertEquals( 4, poms.size() ); } public void testAlreadyCloned()
