Maven issue with buildnumber:hgchangeset properties not propagating to children - maven

I have a multi-module project which uses the buildnumber:hgchangeset plugin to generate changeSet and changeSetDate properties, which then get blatted out into the manifest for each module, like so:
pom.xml (parent):
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>hgchangeset</goal>
</goals>
</execution>
</executions>
</plugin>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<ProjectVestion>${project.version}</ProjectVestion>
<ChangeSet>${changeSet}</ChangeSet>
<ChangeSetDate>${changeSetDate}</ChangeSetDate>
</manifestEntries>
</archive>
</configuration>
</plugin>
After a bit of experimentation, I discovered that having buildnumber:hgchangeset execute for each module contributed a significant amount of time to the overall build time, presumably because it's forking hg.exe every time it needs to get the changeset ID of the local repo.
I then thought it would be a good idea to set the inherited property to false on the buildnumber plugin, in order to only have it run once for the parent. Unfortunantly, doing this causes the changeSet and changeSetDate properties to not be "visible" to the child modules.
My question is: is it possible to set things up in such a way that buildnumber:hgchangeset runs only once, but the properties that it sets become visible to children modules?
I suppose alternatively I could write things out to a property file, and have each module read it back in, but this does not seem like idiomatic Maven to me.
Thanks in advance,

Related

How to trigger a specific execution of a Maven plugin?

I am trying to figure out whether it is possible to define executions of a Maven plugin in a <pluginManagement> section of a parent pom and pick a specific execution, and only that one, in a child project.
To be more specific, I have several multi-module projects that inherit from our company-wide parent pom. In the <pluginManagement> section of the parent pom, I have several executions of maven-resources-plugin using the copy-resources goal, all bound to phase validate but using different configurations:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<inherited>true</inherited>
<executions>
<execution>
<id>copy-codedeploy</id>
<phase>validate</phase>
...
</execution>
<execution>
<id>copy-settings</id>
<phase>validate</phase>
...
</execution>
<execution>
<id>copy-logback</id>
<phase>validate</phase>
...
</execution>
</executions>
<plugin>
After experimenting many hours on a child project, I would like to:
Avoid having needless executions of copy-logback in all modules, which happens when I define execution copy-logback in the parent POM and has the drawback of creating the destination folder hierarchy in all modules.
Avoid, in case that execution is not defined in the parent POM, defining it in multiple cloned copies in all modules where it is needed.
An example child project has these modules, where the first one is the only module where copy-logback is really needed:
webapp
rest
services
persistence
The best I have arrived at now is to leave common executions in the parent POM, which gives me item #1 in the first list above, but still leaves me cloning the exact same plugin configuration in multiple modules. The configuration that I'm cloning is this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<!-- Copy logback.xml from the parent to the main resources folder, filtering the application name used in log file names. -->
<execution>
<id>copy-logback-file</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.basedir}/src/main/resources</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/../logback-templates</directory>
<filtering>true</filtering>
<includes>
<include>logback.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
This unfortunately diminishes the usefulness of a <pluginManagement> section in the parent POM as the identical configuration cannot be defined only once. I have to define it in each module of our Portfolio that uses logback, which amounts to tens of times.
To solve my duplication problem, I am thinking that maybe, it's possible to define an execution of a plugin that can be selectively triggered where it's needed. Is it possible?
You can add a skip parameter to the configuration of each execution like:
<skip>${copy.logback.skip}</skip>
And then you can choose in each module whether to use or skip the execution by setting the property <copy.logback.skip> to true or false.

Difficulty deploying second artifact with Maven

A mavenized version of an old project of mine creates two Jar files, one for command line and one for GUI use. As it currently stands, it deploys only the primary artifact to the local repository. The jars are created by having two executions for maven-jar-plugin, and both get created in the target directory. What happens is the GUI file overwrites the primary one, with the wrong name:
[INFO] Installing /Users/gmcgath/DevProjects/git/jhove/target/jhove-GUI-1.12.0-SNAPSHOT.jar to /Users/gmcgath/.m2/repository/edu/harvard/hul/ois/jhove/1.12.0-SNAPSHOT/jhove-1.12.0-SNAPSHOT.jar
I'm trying to use the build-helper plugin to get the GUI jar deployed to the repository, using the following:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${project.artifactId}-GUI-${project.version}</file>
<type>jar</type>
<classifier>gui</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
Maven runs to completion without any errors, but doesn't copy the jar properly. The log tells me it's trying to copy the GUI jar from the project-level directory instead of the target to the correct destination. The GUI file is still overwriting the primary jar.
[INFO] Installing /Users/gmcgath/DevProjects/git/jhove/jhove-GUI-1.12.0-SNAPSHOT to /Users/gmcgath/.m2/repository/edu/harvard/hul/ois/jhove/1.12.0-SNAPSHOT/jhove-1.12.0-SNAPSHOT-gui.jar
(The "harvard" part is historical. Keeping this open-source project was part of my severance package. :)
So I'm doing something basically wrong. How can I fix this? Should I be using the assembly plugin instead, even though it looks more complicated?
Update: Partially fixed. The file element in the artifact needs to be
<file>${project.build.directory}/${project.artifactId}-GUI-${project.version}.jar</file>
I'm still looking for the fix to get the primary artifact copied correctly.
OK, here's my fix. The first part, as indicated above, was to get the directory and extension right in the build-helper artifact. It should have been
<file>${project.build.directory}/${project.artifactId}-GUI-${project.version}.jar</file>
The other issue was in a part of the pom.xml that I didn't post. The two executions lacked a classifier element, and so looked like this:
<executions>
<execution>
<!-- console app - don't change id, will cause build problems -->
<id>default-jar</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<classifier>cmd</classifier>
<archive>
<manifest>
<mainClass>Jhove</mainClass>
</manifest>
</archive>
</configuration>
</execution>
<execution>
<id>gui-app-jar</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<classifier>gui</classifier>
<archive>
<manifest>
<mainClass>JhoveView</mainClass>
</manifest>
</archive>
<finalName>${project.artifactId}-GUI-${project.version}</finalName>
</configuration>
</execution>
</executions>
Everything looks OK now.

Is it possible to specify a dependency on a particular maven phase?

I am using the maven-docbkx-plugin to generate HTML and PDF output from docbook sources. I have several books, and these link to each other using olinks.
The olink database is generated in one maven phase (generate-resources), and the actual HTML and PDF generation, which looks up this database is executed in a subsequent maven phase (compile).
I have divided the maven project into a multi-module project, as each book has tens of included sub-documents. The docbkx-maven-plugin configuration is all done in the parent, then it is just the top-level docbook source that needs to be specified in the child POM.
But ... this does not work dependency-wise, as each module requires that the generate-resources of every other module has been run before it runs its compile phase, so that it can access the olink database of each of the other books.
Is there a way to do this in maven? Or will I need to re-structure into two maven projects (which will break the modularity of this project considerably, as all of the configuration will need to be declared in each project)?
The structure of the parent POM is:
...
<build>
<plugins>
<pluginManagenent>
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.14</version>
<executions>
<execution>
<id>xrefdb</id>
<phase>generate-resources</phase>
<configuration>
...
</configuration>
<goals>
<goal>generate-html</goal>
</goals>
</execution>
<execution>
<id>html</id>
<phase>compile</phase>
<configuration>
...
</configuration>
<goals>
<goal>generate-html</goal>
</goals>
</execution>
</executions>
</plugin>
</pluginManagement>
</plugins>
</build>
</project>
And the modules:
<project>
...
<build>
<plugins>
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.14</version>
<configuration>
...
</configuration>
</plugin>
</plugins>
</build>
</project>
I've done a bit more research on this, and from what I have read, what I am asking is not possible (but I would be happy to be advised otherwise). I have split my project into two, and given them a common parent from which they can draw their common configuration.
Another way I've solved this problem is to use maven profiles. I perform the first pass of all the modules in the first profile, then perform the second pass in a second profile.
It means the project has to be run twice to build all of its artifacts, but it is much more maintainable than spreading the sources over multiple projects.

NetBeans - how to set default startup Maven module in multi-module maven project?

I'm looking for the way to configure Netbeans workspace for multi-module maven project to always start some module when pressing CTRL+F5 (Debug main project). Being within maven project this shortcut always starts the project whose source file is currently being open. This is annoying - to start debugger i always have to either switch to some source file from the 'main' module or find that module in project explorer (huge sub-tree) and right click -> Debug (both are regular useless waste of time )
Similar question is about re-running last unit test - i can't find shortcut for this, but i see related bug report is not addressed since Aug 2010: http://netbeans.org/bugzilla/show_bug.cgi?id=189113.
You have to put that action specified in the nbactions.xml like:
<action>
<actionName>debug</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
</goals>
<properties>
<jpda.listen>maven</jpda.listen>
<exec.args>-classpath %classpath com.domain.package.Main start</exec.args>
<exec.executable>java</exec.executable>
<exec.workingdir>./content</exec.workingdir>
</properties>
</action>
So it will excecute the Main file in a module of your proyect.
If you want to excecute a Main java file of a dependency project you must include this plugin entry:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dependency-jars/</outputDirectory>
</configuration>
</execution>
</plugin>
This will allow your maven project to copy all dependencies you need to your target during packaging phase. Then use this other plugin entry for making the Main class you need accessible:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.domain.package.Main</mainClass>
<classpathPrefix>dependency-jars/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
You may change the folder where dependency jars will be or even make it a property in the pom.xml of your parent maven project.

Configuring Javadoc aggregation in Maven

I'm trying to create an aggregate Javadoc site for all the modules in my project, but I can't seem to configure the plugin in a way that is satisfactory. Mainly, I can't seem to get it to aggregate the javadocs all the while detecting links and excluding certain packages. Essentially, it appears the configuration of the plugin is ignored entirely.
I have a root pom.xml that refers to a bunch of submodules and contains the following configuration:
<modules>
<module>foo</module>
<module>bar</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.maven.apache.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>aggregate</id>
<phase>site</phase>
<goals>
<goal>aggregate</goal>
</goals>
<configuration>
<links>
<link>http://docs.oracle.com/javase/6/docs/api</link>
<link>http://static.netty.io/3.5/api</link>
<link>http://google-guice.googlecode.com/git/javadoc</link>
<link>http://docs.guava-libraries.googlecode.com/git-history/release/javadoc</link>
<link>http://fasterxml.github.com/jackson-databind/javadoc/2.0.4</link>
<link>https://developers.google.com/protocol-buffers/docs/reference/java</link>
</links>
<bootclasspath>${sun.boot.class.path}</bootclasspath>
<additionalJOption>-J-Xmx1024m</additionalJOption>
<detectJavaApiLink>true</detectJavaApiLink>
<detectLinks>true</detectLinks>
<excludePackageNames>*.testing.*</excludePackageNames>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
But when I run mvn javadoc:aggregate with this setup, I end up with a javadoc site that has no links to any of the referenced libraries and still includes all the testing classes.
I don't even see the plugin attempting to download the package-list for each declared link source.
On the other hand, generating the javadoc for each individual module works well and as expected.
What am I getting wrong?
Plugin configurations can be placed on two levels; inside the execution tag or outside of it ("global").
When the configuration is inside the execution tag it belongs to that particular execution. In your case you will have to run mvn site for it to execute since it is bound to that phase.
When the mvn javadoc:aggregate command is used it looks for the "global" configuration. In your pom there is no such configuration and thus it uses the default configuration.
Change your plugin configuration to this instead:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<configuration>
<links>
<link>http://docs.oracle.com/javase/7/docs/api</link>
<link>http://static.netty.io/3.5/api</link>
<link>http://google-guice.googlecode.com/git/javadoc</link>
<link>http://docs.guava-libraries.googlecode.com/git-history/release/javadoc</link>
<link>http://fasterxml.github.com/jackson-databind/javadoc/2.0.4</link>
<link>https://developers.google.com/protocol-buffers/docs/reference/java</link>
</links>
<bootclasspath>${sun.boot.class.path}</bootclasspath>
<additionalJOption>-J-Xmx1024m</additionalJOption>
<detectJavaApiLink>true</detectJavaApiLink>
<detectLinks>true</detectLinks>
<excludePackageNames>*.testing.*</excludePackageNames>
</configuration>
<executions>
<execution>
<id>aggregate</id>
<phase>site</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
You can place a configuration inside the execution part to override and specialize the configuration for that execution.
BTW The <groupId> is wrong in your pom. It should be
<groupId>org.apache.maven.plugins</groupId>
and not
<groupId>org.maven.apache.plugins</groupId>

Resources