You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2019/07/18 00:43:08 UTC

[maven-invoker-plugin] branch MINVOKER-196_junit_report_style created (now c7e9d8c)

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

olamy pushed a change to branch MINVOKER-196_junit_report_style
in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git.


      at c7e9d8c  [MINVOKER-196] Support for JUnit report style

This branch includes the following new commits:

     new c7e9d8c  [MINVOKER-196] Support for JUnit report style

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[maven-invoker-plugin] 01/01: [MINVOKER-196] Support for JUnit report style

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olamy pushed a commit to branch MINVOKER-196_junit_report_style
in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git

commit c7e9d8c58f18c306740e8eff5997ef594ee505db
Author: olivier lamy <ol...@apache.org>
AuthorDate: Thu Jul 18 10:42:45 2019 +1000

    [MINVOKER-196] Support for JUnit report style
    
    Signed-off-by: olivier lamy <ol...@apache.org>
---
 pom.xml                                            |   5 +-
 src/it/MINVOKER-191/pom.xml                        |   1 +
 .../pom.xml                                        |  25 ++--
 .../src/it/project}/pom.xml                        |  41 +------
 .../src/it/project/verify.groovy                   |  42 +++++++
 .../src/it/project_2/pom.xml                       |  71 +++++++++++
 .../src/it/project_2/verify.groovy                 |  20 ++++
 .../src/it/settings.xml                            |  31 +++++
 .../MINVOKER-196_junit_report_file/verify.groovy   |  43 +++++++
 src/it/fail-build/pom.xml                          |   1 +
 src/it/pom-filtering-reactor/pom.xml               |   1 +
 src/it/script-errors/pom.xml                       |   1 +
 src/it/skip-run/pom.xml                            |   1 +
 .../maven/plugins/invoker/AbstractInvokerMojo.java | 130 ++++++++++++++++++---
 14 files changed, 348 insertions(+), 65 deletions(-)

diff --git a/pom.xml b/pom.xml
index 334d206..e20cf72 100644
--- a/pom.xml
+++ b/pom.xml
@@ -315,7 +315,7 @@ under the License.
             <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-invoker-plugin</artifactId>
-              <version>3.1.0</version>
+              <version>3.2.0</version>
               <configuration>
                 <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
                 <preBuildHookScript>setup</preBuildHookScript>
@@ -371,6 +371,9 @@ under the License.
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-invoker-plugin</artifactId>
               <version>${project.version}</version>
+              <configuration>
+                <writeJunitReport>true</writeJunitReport>
+              </configuration>
             </plugin>
           </plugins>
         </pluginManagement>
diff --git a/src/it/MINVOKER-191/pom.xml b/src/it/MINVOKER-191/pom.xml
index 2e8a898..e556e96 100644
--- a/src/it/MINVOKER-191/pom.xml
+++ b/src/it/MINVOKER-191/pom.xml
@@ -66,6 +66,7 @@ under the License.
           <artifactId>maven-invoker-plugin</artifactId>
           <version>@project.version@</version>
           <configuration>
+            <writeJunitReport>true</writeJunitReport>
             <properties>
               <!-- e.g. ensure that Java7 picks up TLSv1.2 when connecting with Central -->
               <https.protocols>${https.protocols}</https.protocols>
diff --git a/src/it/script-errors/pom.xml b/src/it/MINVOKER-196_junit_report_file/pom.xml
similarity index 73%
copy from src/it/script-errors/pom.xml
copy to src/it/MINVOKER-196_junit_report_file/pom.xml
index 124bd90..1a4f11e 100644
--- a/src/it/script-errors/pom.xml
+++ b/src/it/MINVOKER-196_junit_report_file/pom.xml
@@ -23,13 +23,12 @@ under the License.
   <modelVersion>4.0.0</modelVersion>
 
   <groupId>org.apache.maven.plugins.invoker</groupId>
-  <artifactId>script-errors</artifactId>
+  <artifactId>local-repo-url</artifactId>
   <version>1.0-SNAPSHOT</version>
-  <packaging>pom</packaging>
+  <packaging>jar</packaging>
 
   <description>
-    Test to check that any kind of error from the script, i.e. both java.lang.Exception and java.lang.Error,
-    is caught by the interpreter facade and does not go up to the main build (MINVOKER-78).
+    Test to check for proper filtering of "localRepositoryUrl" token.
   </description>
 
   <properties>
@@ -39,20 +38,24 @@ under the License.
   <build>
     <plugins>
       <plugin>
+        <!-- This triggers the download of a known version of this plugin which can then be safely invoked by the IT project -->
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.2</version>
+      </plugin>
+      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-invoker-plugin</artifactId>
-        <version>@project.version@</version>
+        <version>@pom.version@</version>
         <configuration>
-          <cloneProjectsTo>${project.build.directory}/its</cloneProjectsTo>
-          <pomIncludes>
-            <pomInclude>*/pom.xml</pomInclude>
-          </pomIncludes>
-          <preBuildHookScript>setup</preBuildHookScript>
+          <ignoreFailures>true</ignoreFailures>
+          <writeJunitReport>true</writeJunitReport>
           <postBuildHookScript>verify</postBuildHookScript>
+          <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
+          <settingsFile>src/it/settings.xml</settingsFile>
           <goals>
             <goal>validate</goal>
           </goals>
-          <ignoreFailures>true</ignoreFailures>
         </configuration>
         <executions>
           <execution>
diff --git a/src/it/skip-run/pom.xml b/src/it/MINVOKER-196_junit_report_file/src/it/project/pom.xml
similarity index 52%
copy from src/it/skip-run/pom.xml
copy to src/it/MINVOKER-196_junit_report_file/src/it/project/pom.xml
index 1c25b73..63be41e 100644
--- a/src/it/skip-run/pom.xml
+++ b/src/it/MINVOKER-196_junit_report_file/src/it/project/pom.xml
@@ -21,45 +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>skip-run</artifactId>
-  <version>1.0-SNAPSHOT</version>
-  <packaging>pom</packaging>
-
-  <description>Test to check that invoker.skip=true will skip all invocations</description>
+  <groupId>test</groupId>
+  <artifactId>test</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
 
   <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>@project.version@</version>
-        <configuration>
-          <debug>true</debug>
-          <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
-          <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/MINVOKER-196_junit_report_file/src/it/project/verify.groovy b/src/it/MINVOKER-196_junit_report_file/src/it/project/verify.groovy
new file mode 100644
index 0000000..6b8ec74
--- /dev/null
+++ b/src/it/MINVOKER-196_junit_report_file/src/it/project/verify.groovy
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+// ensure script context contains localRepositoryPath
+assert new File( basedir, "../../../target/it-repo" ).canonicalFile.equals( localRepositoryPath )
+
+File interpolatedSettings = new File( basedir, "../interpolated-settings.xml" )
+assert interpolatedSettings.isFile()
+
+def filename = new File( basedir, "../../../../../local-repo" ).canonicalPath
+// Convert URL, see org.apache.maven.plugins.invoker.AbstractInvokerMojo.toUrl(String)
+String url = "file://" + new File(  filename  ).toURI().path
+if ( url.endsWith( "/" ) )
+{
+    url = url.substring( 0, url.length() - 1 )
+}
+
+def settings = new XmlSlurper().parse( interpolatedSettings )
+
+// ensure right settings and mirror are picked up
+def sandboxMirror = settings.mirrors.mirror[0]
+assert sandboxMirror.id.text() == "sandbox"
+assert sandboxMirror.url.text() != "@localRepositoryUrl@"
+
+// sandboxMirror.url is NOT filled with localRepositoryPath, but with the localRepository of the parent Settings
+assert sandboxMirror.url.text() == url
diff --git a/src/it/MINVOKER-196_junit_report_file/src/it/project_2/pom.xml b/src/it/MINVOKER-196_junit_report_file/src/it/project_2/pom.xml
new file mode 100644
index 0000000..88e03db
--- /dev/null
+++ b/src/it/MINVOKER-196_junit_report_file/src/it/project_2/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<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>test</groupId>
+  <artifactId>pom-filtering</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <!-- ${...} must be left unfiltered -->
+    <prop0>${project.version}</prop0>
+    <!-- these must be filtered -->
+    <prop1>@project.version@</prop1>
+    <prop2>@propertyFromPluginConfig@</prop2>
+    <prop3>@propertyFromPropertiesSection@</prop3>
+    <!-- this must not be resolved to project.version, i.e. the prefix matters -->
+    <prop4>@project-is-not-the-pom.version@</prop4>
+    <!-- POM values must precede other properties -->
+    <prop5>@project.name@</prop5>
+    <prop6>@pom.name@</prop6>
+    <!-- properties from the plugin config must precede values from the POM's <properties> section -->
+    <prop7>@itProperty@</prop7>
+    <!-- properties with prefix "project"/"pom" must fallback to plugin config if no matching POM value exists -->
+    <prop8>@project.nonExistingPomValue@</prop8>
+    <!-- built-in properties must not be overridden by properties from the plugin configuration -->
+    <prop9>@basedir@</prop9>
+    <prop10>@baseurl@</prop10>
+    <prop11>@localRepository@</prop11>
+    <prop12>@localRepositoryUrl@</prop12>
+  </properties>
+
+  <build>
+    <!-- using the Resources Plugin to create a backup of the executed POM for later inspection by the parent build -->
+    <resources>
+      <resource>
+        <directory>${basedir}</directory>
+        <filtering>false</filtering>
+        <includes>
+          <include>*.xml</include>
+        </includes>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.2</version>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/src/it/MINVOKER-196_junit_report_file/src/it/project_2/verify.groovy b/src/it/MINVOKER-196_junit_report_file/src/it/project_2/verify.groovy
new file mode 100644
index 0000000..af6082a
--- /dev/null
+++ b/src/it/MINVOKER-196_junit_report_file/src/it/project_2/verify.groovy
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+assert new File( basedir, "../../../target/it-repo_not_here" ).canonicalFile.equals( localRepositoryPath )
diff --git a/src/it/MINVOKER-196_junit_report_file/src/it/settings.xml b/src/it/MINVOKER-196_junit_report_file/src/it/settings.xml
new file mode 100644
index 0000000..ca7b8ab
--- /dev/null
+++ b/src/it/MINVOKER-196_junit_report_file/src/it/settings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<settings>
+  <mirrors>
+    <mirror>
+      <id>sandbox</id>
+      <name>A completely isolated repo to test the interpolation of "localRepositoryUrl"</name>
+      <url>@localRepositoryUrl@</url>
+      <mirrorOf>*</mirrorOf>
+    </mirror>
+  </mirrors>
+</settings>
diff --git a/src/it/MINVOKER-196_junit_report_file/verify.groovy b/src/it/MINVOKER-196_junit_report_file/verify.groovy
new file mode 100644
index 0000000..5a97c50
--- /dev/null
+++ b/src/it/MINVOKER-196_junit_report_file/verify.groovy
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+File buildLog = new File( basedir, 'build.log' )
+assert buildLog.text.contains( '[INFO] run post-build script verify.groovy' )
+
+File invokerReports = new File( new File(basedir, "target"), 'invoker-reports' )
+assert buildLog.exists()
+
+// test on first project
+def testsuite = new XmlSlurper().parse( new File( invokerReports, "TEST-project.xml" ) )
+
+assert testsuite.@tests.text() == "1"
+
+assert testsuite.testcase.@name.text() == "project"
+def systemOut = testsuite.testcase.'**'.findAll { node -> node.name() == 'system-out' }.get(0)
+assert !systemOut.text().isEmpty()
+
+
+// test on second project
+testsuite = new XmlSlurper().parse( new File( invokerReports, "TEST-project_2.xml" ) )
+
+assert testsuite.@tests.text() == "1"
+assert testsuite.@failures.text() == "1"
+
+assert testsuite.testcase.@name.text() == "project_2"
+def failureMessage = testsuite.testcase.failure.@message
+assert !failureMessage.text().isEmpty()
diff --git a/src/it/fail-build/pom.xml b/src/it/fail-build/pom.xml
index 15c63b5..10ec51d 100644
--- a/src/it/fail-build/pom.xml
+++ b/src/it/fail-build/pom.xml
@@ -40,6 +40,7 @@ under the License.
         <artifactId>maven-invoker-plugin</artifactId>
         <version>@pom.version@</version>
         <configuration>
+          <writeJunitReport>true</writeJunitReport>
           <debug>true</debug>
           <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
           <pomIncludes>
diff --git a/src/it/pom-filtering-reactor/pom.xml b/src/it/pom-filtering-reactor/pom.xml
index 1911edd..79dac5f 100644
--- a/src/it/pom-filtering-reactor/pom.xml
+++ b/src/it/pom-filtering-reactor/pom.xml
@@ -40,6 +40,7 @@ under the License.
         <artifactId>maven-invoker-plugin</artifactId>
         <version>@pom.version@</version>
         <configuration>
+          <writeJunitReport>true</writeJunitReport>
           <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
           <pomIncludes>
             <pomInclude>*/pom.xml</pomInclude>
diff --git a/src/it/script-errors/pom.xml b/src/it/script-errors/pom.xml
index 124bd90..3d600d4 100644
--- a/src/it/script-errors/pom.xml
+++ b/src/it/script-errors/pom.xml
@@ -43,6 +43,7 @@ under the License.
         <artifactId>maven-invoker-plugin</artifactId>
         <version>@project.version@</version>
         <configuration>
+          <writeJunitReport>true</writeJunitReport>
           <cloneProjectsTo>${project.build.directory}/its</cloneProjectsTo>
           <pomIncludes>
             <pomInclude>*/pom.xml</pomInclude>
diff --git a/src/it/skip-run/pom.xml b/src/it/skip-run/pom.xml
index 1c25b73..c09f180 100644
--- a/src/it/skip-run/pom.xml
+++ b/src/it/skip-run/pom.xml
@@ -40,6 +40,7 @@ under the License.
         <artifactId>maven-invoker-plugin</artifactId>
         <version>@project.version@</version>
         <configuration>
+          <writeJunitReport>true</writeJunitReport>
           <debug>true</debug>
           <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
           <pomIncludes>
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 bf2f618..e46dab3 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
@@ -70,6 +70,8 @@ import org.codehaus.plexus.util.cli.CommandLineException;
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 import org.codehaus.plexus.util.cli.Commandline;
 import org.codehaus.plexus.util.cli.StreamConsumer;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomWriter;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
@@ -626,6 +628,20 @@ public abstract class AbstractInvokerMojo
     private int timeoutInSeconds;
 
     /**
+     * Write test result in junit format.
+     * @since 3.1.2
+     */
+    @Parameter( defaultValue = "false", property = "invoker.writeJunitReport" )
+    private boolean writeJunitReport;
+
+    /**
+     * The package name use in junit report
+     * @since 3.1.2
+     */
+    @Parameter( defaultValue = "maven.invoker.it", property = "invoker.junitPackageName" )
+    private String junitPackageName = "maven.invoker.it";
+
+    /**
      * The scripter runner that is responsible to execute hook scripts.
      */
     private ScriptRunner scriptRunner;
@@ -803,11 +819,11 @@ public abstract class AbstractInvokerMojo
     private BuildJob[] getNonSetupJobs( BuildJob[] buildJobs )
     {
         List<BuildJob> result = new LinkedList<>();
-        for ( int i = 0; i < buildJobs.length; i++ )
+        for ( BuildJob buildJob : buildJobs )
         {
-            if ( !buildJobs[i].getType().equals( BuildJob.Type.SETUP ) )
+            if ( !buildJob.getType().equals( BuildJob.Type.SETUP ) )
             {
-                result.add( buildJobs[i] );
+                result.add( buildJob );
             }
         }
         BuildJob[] buildNonSetupJobs = result.toArray( new BuildJob[result.size()] );
@@ -850,9 +866,8 @@ public abstract class AbstractInvokerMojo
 
         try ( Writer writer = new BufferedWriter( new FileWriter( summaryReportFile ) ) )
         {
-            for ( int i = 0; i < buildJobs.length; i++ )
+            for ( BuildJob buildJob : buildJobs )
             {
-                BuildJob buildJob = buildJobs[i];
                 if ( !buildJob.getResult().equals( BuildJob.Result.SUCCESS ) )
                 {
                     writer.append( buildJob.getResult() );
@@ -975,7 +990,7 @@ public abstract class AbstractInvokerMojo
                 collectProjects( projectsDir, parent, projectPaths, false );
             }
 
-            Collection<String> modulePaths = new LinkedHashSet<String>();
+            Collection<String> modulePaths = new LinkedHashSet<>();
 
             modulePaths.addAll( model.getModules() );
 
@@ -1634,6 +1649,7 @@ public abstract class AbstractInvokerMojo
         // let's set what details we can
         buildJob.setName( invokerProperties.getJobName() );
         buildJob.setDescription( invokerProperties.getJobDescription() );
+        ExecutionResult executionResult = null;
 
         try
         {
@@ -1645,9 +1661,10 @@ public abstract class AbstractInvokerMojo
                 try
                 {
                     // CHECKSTYLE_OFF: LineLength
-                    executed =
+                    executionResult =
                         runBuild( basedir, interpolatedPomFile, settingsFile, actualJavaHome, invokerProperties );
                     // CHECKSTYLE_ON: LineLength
+                    executed = executionResult.executed;
                 }
                 finally
                 {
@@ -1752,7 +1769,7 @@ public abstract class AbstractInvokerMojo
         finally
         {
             deleteInterpolatedPomFile( interpolatedPomFile );
-            writeBuildReport( buildJob );
+            writeBuildReport( buildJob, executionResult );
         }
     }
 
@@ -1819,7 +1836,7 @@ public abstract class AbstractInvokerMojo
      * @param buildJob The build job whose report should be written, must not be <code>null</code>.
      * @throws org.apache.maven.plugin.MojoExecutionException If the report could not be written.
      */
-    private void writeBuildReport( BuildJob buildJob )
+    private void writeBuildReport( BuildJob buildJob, ExecutionResult executionResult )
         throws MojoExecutionException
     {
         if ( disableReports )
@@ -1845,6 +1862,73 @@ public abstract class AbstractInvokerMojo
         {
             throw new MojoExecutionException( "Failed to write build report " + reportFile, e );
         }
+
+        if ( writeJunitReport )
+        {
+            writeJunitReport( buildJob, safeFileName, executionResult );
+        }
+    }
+
+    private void writeJunitReport( BuildJob buildJob, String safeFileName, ExecutionResult executionResult )
+        throws MojoExecutionException
+    {
+        File reportFile = new File( reportsDirectory, "TEST-" + safeFileName + ".xml" );
+        Xpp3Dom testsuite = new Xpp3Dom( "testsuite" );
+        testsuite.setAttribute( "tests", "1" );
+        testsuite.setAttribute( "time", Double.toString( buildJob.getTime() ) );
+        Xpp3Dom testcase = new Xpp3Dom( "testcase" );
+        testsuite.addChild( testcase );
+        switch ( buildJob.getResult() )
+        {
+            case BuildJob.Result.SUCCESS:
+                break;
+            case BuildJob.Result.SKIPPED:
+                testsuite.setAttribute( "skipped", "1" );
+                // adding the failure element
+                Xpp3Dom skipped = new Xpp3Dom( "skipped" );
+                testcase.addChild( skipped );
+                skipped.setValue( buildJob.getFailureMessage() );
+                break;
+            case BuildJob.Result.ERROR:
+                testsuite.setAttribute( "errors", "1" );
+                break;
+            default:
+                testsuite.setAttribute( "failures", "1" );
+                // adding the failure element
+                Xpp3Dom failure = new Xpp3Dom( "failure" );
+                testcase.addChild( failure );
+                failure.setAttribute( "message", buildJob.getFailureMessage() );
+        }
+        testcase.setAttribute( "classname", junitPackageName + "." + safeFileName );
+        testcase.setAttribute( "name", safeFileName );
+        Xpp3Dom systemOut = new Xpp3Dom( "system-out" );
+        testcase.addChild( systemOut );
+
+        if ( executionResult != null && executionResult.fileLogger != null )
+        {
+            getLog().info( "fileLogger:" + executionResult.fileLogger.getOutputFile() );
+            try
+            {
+                systemOut.setValue( FileUtils.fileRead( executionResult.fileLogger.getOutputFile() ) );
+            }
+            catch ( IOException e )
+            {
+                throw new MojoExecutionException( "Failed to read logfile " + executionResult.fileLogger.getOutputFile()
+                    , e );
+            }
+        }
+        else
+        {
+            getLog().info( safeFileName + ", executionResult:" + executionResult );
+        }
+        try ( FileOutputStream fos = new FileOutputStream( reportFile );
+              Writer osw = new OutputStreamWriter( fos, buildJob.getModelEncoding() ) )
+        {
+            Xpp3DomWriter.write( osw, testsuite );
+        } catch ( IOException e )
+        {
+            throw new MojoExecutionException( "Failed to write JUnit build report " + reportFile, e );
+        }
     }
 
     /**
@@ -1872,7 +1956,7 @@ public abstract class AbstractInvokerMojo
      * @throws org.apache.maven.shared.scriptinterpreter.RunFailureException If either a hook script or the build itself
      *             failed.
      */
-    private boolean runBuild( File basedir, File pomFile, File settingsFile, File actualJavaHome,
+    private ExecutionResult runBuild( File basedir, File pomFile, File settingsFile, File actualJavaHome,
                               InvokerProperties invokerProperties )
         throws MojoExecutionException, RunFailureException
     {
@@ -1895,6 +1979,7 @@ public abstract class AbstractInvokerMojo
 
         FileLogger logger = setupBuildLogFile( basedir );
         boolean selectorResult = true;
+        ExecutionResult executionResult = new ExecutionResult();
         try
         {
             try
@@ -1910,7 +1995,8 @@ public abstract class AbstractInvokerMojo
             catch ( RunFailureException e )
             {
                 selectorResult = false;
-                return false;
+                executionResult.executed = false;
+                return executionResult;
             }
 
             scriptRunner.run( "pre-build script", basedir, preBuildHookScript, context, logger,
@@ -2010,11 +2096,10 @@ public abstract class AbstractInvokerMojo
                     }
                 }
 
-                InvocationResult result;
-
                 try
                 {
-                    result = invoker.execute( request );
+                    InvocationResult result = invoker.execute( request );
+                    verify( result, invocationIndex, invokerProperties, logger );
                 }
                 catch ( final MavenInvocationException e )
                 {
@@ -2022,7 +2107,6 @@ public abstract class AbstractInvokerMojo
                     throw new RunFailureException( "Maven invocation failed. " + e.getMessage(),
                                                    BuildJob.Result.FAILURE_BUILD );
                 }
-                verify( result, invocationIndex, invokerProperties, logger );
             }
         }
         catch ( IOException e )
@@ -2040,7 +2124,21 @@ public abstract class AbstractInvokerMojo
                 logger.close();
             }
         }
-        return true;
+        executionResult.executed = true;
+        executionResult. fileLogger = logger;
+        return executionResult;
+    }
+
+    private static class ExecutionResult
+    {
+        boolean executed;
+        FileLogger fileLogger;
+
+        @Override
+        public String toString()
+        {
+            return "ExecutionResult{" + "executed=" + executed + ", fileLogger=" + fileLogger + '}';
+        }
     }
 
     private void runPostBuildHook( File basedir, Map<String, Object> context, FileLogger logger )