Varying plugin configuration for each child module - maven

I have a multi-module build which contains modules which can target either Java 5 or Java 6. I want to allow modules to opt-in to Java 6, and leaving the default to 5.
To set Java 5 as a target I need to configure the following:
maven-compiler-plugin: source and target set to 1.5
maven-bundle-plugin: configure the Bundle-RuntimeExecutionEnvironment to J2SE-1.5
To set Java 6 as a target I need to configure the following:
maven-compiler-plugin: source and target set to 1.6
maven-bundle-plugin: configure the Bundle-RuntimeExecutionEnvironment to JavaSE-1.6
I considered having two properties: java.compiler.source and osgi.bree which can be defined by each module, but this leaves place for error.
How can I override the configuration of these two plugins per module with a single switch?

I would personally structure your project so that Java 5 modules descend from one parent POM and Java 6 modules from another parent POM.
Global Parent (majority of global settings)
Java5 parent (just define source/bundle)
module A
module B
Java 6 parent (just define source/bundle)
module C

How about allowing child modules to set a my.java.version property (or whatever you want it named) and embedding a Groovy script that sets version properties for the compiler and bundle plugins? Something like this in the parent pom:
<project ...>
...
<properties>
<my.java.version>1.5</my.java.version> <!-- default Java version -->
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<!-- set up properties in an early lifecycle phase -->
<phase>initialize</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<!-- this can be as simple or complex as you need it to be -->
<source>
if (project.properties['my.java.version'] == '1.6') {
project.properties['my.compiler.version'] = '1.6'
project.properties['my.execution.environment.version'] = 'JavaSE-1.6'
}
else {
project.properties['my.compiler.version'] = '1.5'
project.properties['my.execution.environment.version'] = 'J2SE-1.5'
}
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<!-- now use the properties from above in the plugin configurations -->
<!-- assume that both of these plugins will execute in a phase later than 'initialize' -->
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${my.compiler.version}</source>
<target>${my.compiler.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<!-- sorry if this part isn't correct; never used this plugin before -->
<instructions>
<Bundle-RuntimeExecutionEnvironment>${my.execution.environment.version}</Bundle-RuntimeExecutionEnvironment>
</instructions>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

I don't think there is an elegant Maven way to solve this complex scenario, neither yours or Duncan's proposed solution are easy maintainable IMO, when number of sub module becomes tremendous.
For maximum maintainability, I would write shell script (and/or batch file on Windows) in case Maven can't do the job very well, for example, a set-version.sh (and set-version.bat) that loop all sub module and reset the default java.compiler.source and osgi.bree properties based on a version-feed.txt, the version-feed.txt gives you a single central place for manipulating your version varying. As you can see, the cons is this is really not a Maven solution, it requires running set-version.sh before mvn ... every time version customization is required.
In addition, For build/release standardization, I would use maven-enforcer-plugin to play/pause the build process based on a property version.set(which is flagged by set-version.sh) and prompt some warning/error message if developer is not follow the correct procedure when doing build. The version.set also gives the flexibility if you prefer to use the default values defined in every sub module, instead of running set-version.sh, just directly set it to true in the parent pom.xml or from command-line parameter.
Sample directory structure:
parent/
module-a/
module-b/
module-c/
... ...
pom.xml
set-version.sh
set-version.bat
version-feed.txt
Hope this make sense.

Related

How to redirect unit test output Maven

I'm working in a Java 8 project built using maven. Whenever I do a mvn install the root of my project gets polluted with the output files produced from my unit tests.
How can I redirect that output to somewhere else (maybe target directory) rather than the root directory of my project?
I thought about rewriting the unit tests to point the output to target but that seems a bit silly to me. Perhaps there is a plugin or a maven directive which might do what I want to accomplish?
I tried configuring the surefire plugin but this didn't help :(
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<!-- Set working directory for content -->
<workingDirectory>target/test-classes</workingDirectory>
<useFile>false</useFile>
<!-- Just set to some large numbers for all tests to work -->
<argLine>-Xmx1g -Xss1m -XX:MaxPermSize=128m</argLine>
<skipTests>${skip.unit.tests}</skipTests>
</configuration>
</plugin>
Looks like my initial attempt was almost there, just upgraded the version and it worked :)
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<!-- Set working directory for content -->
<workingDirectory>target/test-classes</workingDirectory>
<useFile>false</useFile>
<!-- Just set to some large numbers for all tests to work -->
<argLine>-Xmx1g -Xss1m -XX:MaxPermSize=128m</argLine>
<skipTests>${skip.unit.tests}</skipTests>
</configuration>
</plugin>
There is new configuration option redirectTestOutputToFile since version 2.3 for exactly this purpose.

Maven : exclude target/generated-sources from compilation

This question, just to be sure my interpretation is correct :
I'm using Mojohaus jaxb2-maven-plugin to generate java classes from .xsd files, and by default it puts them in target/generated-sources
Now, I want to get track of these classes in source control (target is of course excluded), and I may one day slightly customize one with an annotation or a line of code, and I may even change my class generation plugin, so what do is I copy these classes and packages in src/main/java
This upsets Maven when I try to compile because he considers "target/generated-sources" as a source directory and he finds all clases twice. For what I understand, I can exclude classes inside a source directory, but I can't remove a source directory from Maven build, am I right ?
So the only solution would be to configure my jaxb2 plugin to generate the classes elsewhere, right ?
UPDATE :
Ok, this doesn't work as I thought, if I change the outputDirectory of my jaxb plugin, it's still included as a source directory by Maven, and I have no clue why.
<configuration>
<outputDirectory>${project.build.directory}/tatata/jaxb</outputDirectory>
</configuration>
UPDATE 2 : The explanation is the plugin is adding the outputDirectory as a maven source directory during the generate-sources phase of the build, and it's not optionnal or customizable.
First things first, do not add generation code to source control. Do not modify it manually. You will get into trouble. Believe me, I've seen it too many times. A new version of the schema and you're lost.
Ok, now to your question.
With maven-jaxb2-plugin you could turn off adding generation directory as a compile source root with:
<configuration>
<addCompileSourceRoot>false</addCompileSourceRoot>
</configuration>
Disclaimer: I'm the author of maven-jaxb2-plugin.
The answer from Lexicore is an interesting lead but my question was about the plugin I'm currently using, not how to do it with an other plugin.
So here is the workaround for the Mojohaus plugin : you can just skip the generate-sources by default (no need to do this task at every build when your model changes once in a week, then once in a year), and trigger it only when needed using a dedicated maven profile : How to skip generate-sources in Maven
you can always specify the target directory(generateDirectory) in pom config file as below. Hope it helps
`
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generateDirectory>${basedir}/src/main/java</generateDirectory>
<generatePackage>com.myproj.proxy</generatePackage>
<schemas>
<schema>
<!-- <url>${project.basedir}/src/main/resources/wsdl/test.wsdl</url> -->
<fileset>
<!-- Defaults to schemaDirectory. -->
<directory>${basedir}/src/main/resources/wsdl</directory>
<!-- Defaults to schemaIncludes. -->
<includes>
<include>*.wsdl</include>
</includes>
</fileset>
</schema>
</schemas>
</configuration>
</plugin>
`

Required to create Maven plugin or 'some kind of wrapper' or should I use a parent pom

We are using the frontend-maven-plugin in several (10+) projects.
These projects are build in combination with our own CMS. These projects are using a specific 'parent' in the pom, such as:
<parent>
<groupId>nl.companyname</groupId>
<artifactId>companyname-corporate-pom</artifactId>
<version>2.0.13</version>
</parent>
In this 'corporate pom', we have some predefined configuration and 'plugin management', such as:
<project.frontendmavenplugin.version>1.3</project.frontendmavenplugin.version>
<project.frontendmavenplugin.workingDirectory>./</project.frontendmavenplugin.workingDirectory>
<project.node.downloadRoot>http://nodejs.COMPANYURL.nl/dist/</project.node.downloadRoot>
<project.node.version>v6.9.1</project.node.version>
<project.yarn.version>v0.17.9</project.yarn.version>
<project.yarn.downloadRoot>http://yarnpkg.COMPANYURL.nl/</project.yarn.downloadRoot>
<project.npm.registryUrl>http://nexus.COMPANYURL.nl/content/groups/npm-all/</project.npm.registryUrl>
and
<build>
<pluginManagement>
<!-- Generic configuration for plugins used by (almost) all projects. -->
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>${project.frontendmavenplugin.version}</version>
<executions>
<execution>
<id>install node and yarn</id>
<goals>
<goal>install-node-and-yarn</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<workingDirectory>${project.frontendmavenplugin.workingDirectory}</workingDirectory>
<nodeVersion>${project.node.version}</nodeVersion>
<nodeDownloadRoot>${project.node.downloadRoot}</nodeDownloadRoot>
<yarnVersion>${project.yarn.version}</yarnVersion>
<yarnDownloadRoot>${project.yarn.downloadRoot}</yarnDownloadRoot>
</configuration>
</execution>
etc.
This way we don't have to copy/manage all configuration in each project.
This works great.
But: we are now also creating more and more new applications (based on Spring Boot) which are independent from our CMS and where we cannot use this 'parent pom' because Spring Boot has it's own (spring-boot-starter-parent) and our 'corporate pom' also contains very specific plugins / configuration which only applies to our CMS (which we are not including in these Spring Boot projects).
So what I need is something more 'standalone' for the frontend-maven-plugin configuration (and maybe in the future more 'platform' independent config/plugins). As far as I know, it's not possible to have more then 1 parent, so are there any other options?
I thought of creating a new 'companyname-frontend-maven-plugin' which both contains the PluginManagement as all the (extendable) configuration for the Frontend Maven Plugin. But I don't know if this will work and also it's a lot of work creating and maintaining this in git / Jenkins etc.
Are there any other options I could look in to?
Thank you all for your time!
maybe you can use a profile.
You can create a "corporate" pom that inherit from spring-boot-starter-parent and that contains a maven profile with all the properties and plugins required by your cms. So, when you are working on the CMS you will enable the "cms-profile".
Kind regards.

Accessing configuration value from another configuration in the Maven Release plugin

Is it possible in Maven to access a configuration value from another configuration value? For example, in the Release Plugin it is possible to access the project.version key during configuration of the tagNameFormat element. What I would like to do is to then use the tagNameFormat value in another element named completionGoals. See below:
<!-- Snippet from a POM -->
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<tagNameFormat>${my.pom.property}#{project.version}-${my.pom.property.extra}</tagNameFormat>
<checkModificationExcludes>
<checkModificationExclude>pom.xml</checkModificationExclude>
</checkModificationExcludes>
<completionGoals>clean verify help:evaluate -Dexpression=${tagNameFormat}</completionGoals>
</configuration>
<executions>
<execution>
<id>default</id>
<goals>
<goal>prepare</goal>
<goal>perform</goal>
</goals>
<configuration>
<pomFileName>${release.pom.path}pom.xml</pomFileName>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
Notably, in the above configuration, I can see that the tagNameFormat itself is populated with both the standard POM version property and my own custom property (that incidentally is runtime-defined at the command-line). However, when I try to access the value to define another configuration element, completionGoals, completionGoals appears as a variable placeholder, e.g. "${tagNameFormat}" literally appears in the resulting command. (Verified by running Maven with the -X and -e flags.)
Question(s):
Is it possible to get a populated plugin configuration value from the Maven plugin configuration in the POM?
Am I referring to the tagNameFormat configuration element correctly? How could I do this with the Release plugin?
What does the '#' versus the '$' mean? (Guess: Dynamically versus statically evaluated?)
The only way I'm aware of is to define another POM property:
<property>
<my.pom.property>...</my.pom.property>
<my.pom.property.extra>...</my.pom.property.extra>
...
<myTagNameFormat>${my.pom.property}#{project.version}-${my.pom.property.extra}</myTagNameFormat>
</property>
and to use it accordingly:
<tagNameFormat>${myTagNameFormat}</tagNameFormat>
...
<completionGoals>clean verify help:evaluate -Dexpression=${myTagNameFormat}</completionGoals>
Re 3.: AFAIK, the variable delimiters ${...} and #...# are equivalent and I've never read or heard the contrary. But, to be honest, I've never ever used #...# since I'm used to ${...} from Bash and that's also the only one mentioned on the Filter doc page. (#...# is only mentioned at Escape filtering and such I didn't know that it even exists for a long time.)

Sharing common resources between non-JAR maven projects

I have several Maven projects, say a,b,c, inheriting from a single parent (let's call it parent), and also being modules (of a different project than parent, let's call it super).
These projects all have a pom packaging. Each of these projects has specific configuration, but they also have a common part. To be more speficic, each project two JMeter test configuration files: one specialized for the given project, and another one that is common and identical for all projects.
The problem is - how should I configure the POMs so this common config file is shared among the projects?
A workaround would be to merge all of them into super, and use profiles. However, in this case, I would have to do a separate build for each configuration manually (whereas now I can just build super).
There are similar questions, like this one, but they deal with the jar plugin, which is not relevant for this case.
Structure, for reference:
POM Inheritance:
parent
|
-------------
| | |
a b c
File structure:
super
|
|-a
|
|-b
|
|-c
I have used the maven-remote-resources-plugin for a similar purpose. Create a separate resources project (com.company:resourceProj) of type jar. Put the JMeter resource files in /src/main/resources.
/src/main/resources/common.properties (your filenames obviously)
/src/main/resources/a.properties
etc.
Follow the directions in the example to create the bundle.
Now, add this config to your parent POM (in a testing profile if you want):
<properties>
<shared.resources.dir>${project.build.directory}/shared-resources</shared.resources.dir>
</properties>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<executions>
<execution>
<id>load-resources</id>
<phase>initialize</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<resourceBundles>
<resourceBundle>com.company:resourceProj:version</resourceBundle>
</resourceBundles>
<attached>false</attached>
<outputDirectory>${shared.resources.dir}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Now, tell Maven these are test resources. If your test resource elements are consistent across the modules, this can go in the parent too, if they are different it goes in the module POM. (In my experience with Maven 3 resources defined in a child project take precedence over the parent's; they aren't merged.)
<testResources>
<testResource>
<directory>${shared.resources.dir}</directory>
<includes>
<include>common.properties</include>
<include>${module.file}.properties</include>
</includes>
</testResource>
<!-- any other test resources here -->
</testResources>
In the child module, define the resources module property (this is module a):
<properties>
<module.file>a</module.file>
</properties>
Adapt this to meet your use case.
---- Edit ----
If the configuration is placed into a parent POM, the parent POM may fail to build depending on what configuration is provided by the child. When we are building the shared base/parent projects we don't want to require that all of the properties that should be provided by child projects (inheriters) are defined. So we activate this profile when building the shared projects to bypass anything that only applies to children.
To do this, add an empty file pom-packaging.marker to the parent project's basedir. Then add this profile to the parent POM. When the parent project is built, Maven will find the marker file, enable the profile, and disable all of the executions included in the profile. When a child project is built, the marker file doesn't exist, so the configuration in the main part of the POM will take effect.
I've used this technique with the Enforcer plugin as well - the parent defines the enforcer rules that should be applied to projects inheriting from the parent, but cannot satisfy the rules when it is built. If the plugin provides a "skip" property, you may enable that in this profile instead of using phase = none in plugin configuration.
<profile>
<id>pom-packaging</id>
<activation>
<file>
<exists>pom-packaging.marker</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<executions>
<execution>
<id>load-resources</id>
<phase>none</phase> <!-- disables this execution -->
</execution>
</executions>
</plugin>
.... other plugin executions here ....
</plugins>
</build>
</profile>
The idea with import scope dependencies is that you can put shared resources into a separate project, which is then imported by a number of other ones; I was thinking you could include your shared config file in this way.
You create a new project with packaging pom (maybe at the same level as the parent?), and then include it in the parent's dependencyManagement section with scope import. Each of your child projects can then receive it by inheritance. It might seem like overkill to make an entire project for just a single file, but I wouldn't have a problem with that.
I haven't actually tried this with a tree of pom-packaged projects, so you might have to play around a bit, but the approach I think is sound. There's a (very extensive) example here:
Importing Dependencies

Resources