Maven build lifecycle phase synchronization across modules - maven

I have a maven project with a reactor and a couple of modules, most of which are being packed as war. The order in which they are specified in the reactor / root pom.xml defines the order in which they are built.
pom.xml
....
<module>library1</module>
<module>library2</module>
<module>webapp1</module><!--war-->
<module>webapp2</module><!--war-->
<module>blackduck-scan</module><!-- create file to be placed into webapp2 post-build but pre-packaging of webapp2 -->
...
The last module, purposely, is destined to simply run an executable in the prepare-package phase. More precisely a blackduck license scanner, which itself eventually produces the license notice file which is then placed into the /webapp folder of one of the web applications to be displayed after deployment.
The idea is what this notice file is being placed after compilation of the applications but before packaging these as WAR artifacts to have it included in the current delivery of our pipeline without re-building just for the sake of re-packaging.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<executable>java</executable>
<workingDirectory>.</workingDirectory>
<arguments>
<argument>-jar</argument>
<argument>synopsys-detect-8.4.0.jar</argument>
</arguments>
...
</configuration>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
I've tried two options to achieve this without success.
a) Adding the plugin/goal to the reactor pom.xml leads to the goal being executed first as soon as the target phase is prepare-package and thus may lead to incomplete scan results while the actual project has not yet been built.
b) Adding then plugin/goal as a module as described above puts the execution at the end of the chain, however, packaging of the webapps has already been concluded.
c) The third (arguably working) but less elegant approach would be to split this into two separate maven calls:
mvn clean install && mvn package
I see that modules are build in sequence and for good reason. However, is there any method to "synchronize" build phases such that each phase is started only after the previous phase has been completed for all modules? Effectively to simply call, all included:
mvn clean install

I believe the option is:
disable war creation and run exploded goal instead
use maven-assembly-plugin to pack target war
inject execution of blackduck between maven-war-plugin and maven-assembly-plugin
smth. like:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<executions>
<execution>
<!-- disabling building war -->
<id>default-war</id>
<phase>none</phase>
</execution>
<execution>
<id>exploded</id>
<phase>prepare-package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- blackduck execution here -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptors>
<descriptor>war-assembly.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
war-assembly.xml:
<assembly>
<id>war</id>
<formats>
<format>war</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}/${project.build.finalName}</directory>
<outputDirectory>.</outputDirectory>
<includes>
<include>/**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

Related

How do I create an uber source jar with Maven?

Is there a well-known way to create an uber source jar? In other words, a jar of all the source code for a project and all its dependencies (or at least those that have a -sources.jar)?
I've looked into doing it with the maven-assembly-plugin, but using a dependencySet with includes of *.*.*.sources.* (or *.sources) doesn't work because those are not actually dependencies of the project, and I don't want to add them all.
You can use the maven-shade-plugin to create an uber jar. Just include the following within your <build> tag -
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>source-jar</id>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createSourcesJar>true</createSourcesJar>
<artifactSet>
<includes>
<include>...</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
To modify the configuration, you can use Resource Transformers within org.apache.maven.plugins.shade.resource package.
And to define the contents of the jar, you can further use includes and excludes within the filters.
I found some information on working with sources in the maven-dependency-plugin.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>src-dependencies</id>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<phase>prepare-package</phase>
<configuration>
<classifier>sources</classifier>
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
<outputDirectory>${project.build.directory}/sources</outputDirectory>
<includeGroupIds>{your group prefix}</includeGroupIds>
<includes>**/*.java</includes>
<includeScope>runtime</includeScope>
</configuration>
</execution>
So if I do that, and then run a maven-assembly-plugin referencing the unpacked files, I can do it in two steps.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<execution>
<id>uber-source</id>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptors>
<descriptor>ubersource.xml</descriptor>
</descriptors>
<outputDirectory>${deploy.internal.directory}</outputDirectory>
<finalName>${project.artifactId}</finalName>
</configuration>
</execution>
</executions>
</plugin>
with a file set in the assembly descriptor ubsersource.xml:
<fileSet>
<directory>${project.build.directory}/sources</directory>
<outputDirectory>.</outputDirectory>
</fileSet>
And then I get my uber source jar...
There is perhaps a subtle distinction in the way the maven-assembly-plugin and maven-dependency-plugin treats sources. If you reference classifier sources in a dependencySet of an assembly descriptor, it looks for sources that are actual dependencies in your pom -- not that useful. However, in maven-dependency-plugin, referencing sources classifier means that sources of your dependencies. Hence why this solution works.
I also wrapped this up in my own plugin using mojo-executor to make it single step, and single declaration in my pom, but that's optional
This is a lot more pom code, but I like it better than the maven-shade-plugin because it does just what I want, and nothing more.

maven zip uber-jar and shell script

I would like maven to combine an uber-jar created by the shade-plugin and a shell script from the all_files directory.
The project structure looks like this:
all_files/
mvn_script.sh
projB-shaded.jar
maven_project/
guide/
parent-pom.xml
projA/
pom.xml
projB/
pom.xml
The jar is produced by projectB's pom file and then placed into the outtermost folder to be ready to be zipped with the shell script. The reason is so that the shell script can call the jar file to execute the project.
I want other programmers to be able to easily unzip the file and run the shell script without worry. And I also need to have maven package the script and jar together. I'm not sure exactly how to implement that within the shaded plugin.
Note: I do not want to use assembly-plugin because it doesn't package dependent jars well.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<outputFile>../../guide/${project.artifactId}-${project.version}-shaded.jar</outputFile>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>projB.classB</Main-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
You don't want to use the maven-assembly-plugin for creating the uber-jar. But you will want to use it to create that ZIP.
Currently, your maven-shade-plugin is bound to the package phase. You could shift that execution to the prepare-package phase (since it actually prepares your final packaging) add an execution of the maven-assembly-plugin bound to the package phase. Your assembly would create a ZIP based on the shaded JAR (which will exist since the shade plugin will have been executed) and the shell script.
A sample descriptor would be the following:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>your-id</id>
<formats>
<format>zip</format>
</formats>
<files>
<file>
<source>${project.build.directory}/projB-shaded.jar</source>
<outputDirectory>/</outputDirectory>
</file>
<file>
<source>/path/to/mvn_script.sh</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
</assembly>
with the following POM configuration:
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!-- current configuration -->
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>assemble</id>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptors>
<descriptor>/path/to/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
The typical location for the assembly descritor is under src/assembly as per the Maven standard directory layout.

Create a zip file and add it to a war file with maven

I have some example RESTful client projects that go along with a RESTful Java web service I am working on. Basically, these projects should not be built but instead zipped up and included in the war file so that they will be available as static resources when the war file is deployed. This makes it easy to update the example clients along with the actual Java web service and guarantee that they are deployed together.
I've been able to use the maven assembly plugin to create a zip file but that stage executes after the war stage. I haven't been able to figure out the maven incantation needed to create the zip file then add it to the war file.
Here is what I have so far, but it only does about half the job. Also, I need to move the ExampleProject directory so the unzipped files don't go into the final war file.
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptor>src/assembly/AssembleExamples.xml</descriptor>
<finalName>examples.zip</finalName>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
AssembleExamples.xml
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/WebContent/docs/</directory>
<outputDirectory/>
<includes>
<include>ExampleProject/pom.xml</include>
<include>ExampleProject/src/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Two of the plugins maven-war-plugin and maven-assembly-plugin are required to be executed in the same phase, package. First, maven-assembly-plugin and then maven-war-plugin. You need to add the plugins in the following order to make sure that they run in same phase and correct order:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.1</version>
<executions>
<execution>
<id>prepare-war</id>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptor>src/assembly/AssembleExamples.xml</descriptor>
<finalName>examples.zip</finalName>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
You can generate the war using mvn package.
Here is how I ended up doing it.
Thanks to Mithun I realized that there are two ways to configure the war plugin and the way I was doing it was not appropriate for my situation.
This is what I added to my pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<configuration>
<descriptor>src/assembly/AssembleJavaExample.xml</descriptor>
<finalName>myexample</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}/${project.build.finalName}/docs</outputDirectory>
</configuration>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>true</failOnMissingWebXml>
<warName>mywar</warName>
<warSourceExcludes>docs/myexample/**</warSourceExcludes>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
</execution>
</executions>
</plugin>
The assembly plugin had to go first so it would execute before the war plugin. The assembly plugin creates the zip file and places it in the directory that the war plugin uses to create the war file (the outputDirectory configuration). I then had to exclude the example sources from being included in the war file (the warSourceExcludes configuration). I'm not sure if this is the best way but it seems to be working out quite well.

clean a folder contents during pre-integration-test phase

I have parent pom where I'm trying to unpack some scripts, execute them inside and in "pre-integration-test" phase, so it runs by default for all child modules.
My problem here is I need to delete the contents of certain directory each time it runs. I tried using ant-plugin which never runs in the pre-integration-phase. Also to note I'm calling several profiles while building the project.
mvn clean install -Pprofile1,profile2,integration
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>pre-integration-test</phase>
<configuration>
<tasks>
<delete>
<fileset dir="checkout\myproject\specific_directory\**.*"/>
<delete/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
Overall I have four plugins including ant clean all running in pre-integration-phase. Except ant clean up task all others run correctly.
Based on the documentation and on my personal experience i assume you configured the plugin in the wrong area. Furthermore have you called mvn via:
mvn verify
to execute integration-test phase.
<build>
[...]
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>cleanup</id>
<phase>pre-integration-test</phase>
<goals>
<goal>clean</goal>
</goals>
<configuration>
<filesets>
<fileset>
<directory>some/relative/path</directory>
<includes>
<include>**/*.tmp</include>
<include>**/*.log</include>
</includes>
</fileset>
</filesets>
</configuration>
</execution>
<executions>
</plugin>
[...]
</build>

Maven 3: Generate Javadoc for defined artifacts

I want to generate javadocs only for certain artifacts of my project from within a dedicated docs-project.
That means that I would like to have an independent project called "docs" for example. In the docs/pom.xml I would like to define the artifacts that should be included in the generated javadocs.
So far I learned that I have to generate a separate sources.jar for the projects I want to include. But I can't figure out how to go on from there.
For now I can only imagine two approaches:
Get the artifacts (sources.jar) I want to include, unpack them and somehow point the Javadoc plugin to the source directory.
Define the artifacts I am interested as dependency and use the "dependencySourceInclude" option of the javadoc-plugin. But I am not sure if this is usage as intended.
Any suggestions how to solve this problem?
I have found a solution my self. It is a bit of a hack but it does work for me. I chose to go with my first idea:
Get the artifacts (sources.jar) I want to include, unpack them and somehow point the javadoc plugin to the source directory.
This solution has four differents parts which I'll explain in more detail later:
Generate sources.jars in all artifacts I want to include
Unpack those sources.jars
Generate Javadoc by pointing the javadoc-plugin to the unpacked sources
Package the generated apidocs in a zip file
Now in more detail:
1. Generate sources.jars in all artifacts I want to include
To generate sources.jars you have to use the maven-sources-plugin as follows:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>bundle-sources</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
You have to do this in every project/module/artifact you want to include in your apidocs.
2. Unpack those sources.jars
In you pom.xml you use to generate the javadocs you have to add the following plugins to unpack the sources.jar files.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-artifact-sources</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId><!-- your artifact here --></artifactId>
<version>${project.version}</version>
<classifier>sources</classifier>
<overWrite>true</overWrite>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/unpack_sources</outputDirectory>
</configuration>
</execution>
<!-- add more unpack-executions here -->
</executions>
</plugin>
You can add as many unpack-execution-blocks as you like.
3. Generate Javadoc by pointing the javadoc-plugin to the unpacked sources
Now the tricky part. Letting the javadoc-plugin know where to look for the source files. The imported definition is the <sourcepath> definition. In this section we define the folder where we have unpacked the sources in step 2.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<configuration>
<sourcepath>${project.build.directory}/unpack_sources</sourcepath>
</configuration>
<executions>
<execution>
<goals>
<goal>javadoc</goal>
</goals>
<phase>process-resources</phase>
</execution>
</executions>
</plugin>
When you call mvn clean install at this point you will end up with a site folder inside your target folder. In this site folder you'll find your apidocs. But to make this build all shiny and stuff we want to assemble the apidocs into a zip archive.
4. Package the generated apidocs in a zip file
To assemble the docs you have to use the maven-assembly-plugin and a extra assembly-file.
First the plugin-defintion inside your pom:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>docs-assembly</id>
<phase>package</phase>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/assemble.xml</descriptor>
</descriptors>
</configuration>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
assemble.xml:
<?xml version="1.0" encoding="UTF-8"?>
<assembly>
<id>${project.build.finalName}</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/site/apidocs</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>

Resources