Different Maven configurations for different goals - java

I have a Maven project which includes a Maven plugin (the Liquibase Maven plugin) which exposes different goals.
Two of these goals (update and diff) need different parameters which are in conflict between them (because the semantics of the two is different), so I need to give Maven different properties in the two goal executions.
That's what I've done
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.4.1</version>
<!-- This configuration is used for every goal except "diff" -->
<configuration>
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
<promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
</configuration>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>diff</goal>
</goals>
<!-- This configuration is used for the "diff" goal -->
<configuration>
<propertyFile>src/main/resources/liquibaseDiff.properties</propertyFile>
<promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
</configuration>
</execution>
</executions>
</plugin>
However, this configuration is wrong because for each goal (diff, update of the others) only the liquibaseDiff.properties file is used.
Is there any way to pass different configurations for different goals in Maven?

Configuration of plugins can be done in two different locations:
Globally for all executions. The global configuration is done with the <configuration> element under <plugin>. This configuration in inherited by all executions.
Per execution. This is done using the <configuration> element under <execution>.
In your example, consider this POM:
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<!-- put the configuration here that is common to all executions -->
</configuration>
<executions>
<execution>
<id>diff</id>
<goals>
<goal>diff</goal>
</goals>
<configuration>
<!-- put the specific configuration of the diff goal here, this will inherit from the global configuration -->
</configuration>
</execution>
<execution>
<id>update</id>
<goals>
<goal>update</goal>
</goals>
<configuration>
<!-- put the specific configuration of the update goal here, this will inherit from the global configuration -->
</configuration>
</execution>
</executions>
</plugin>
The default inheritance behavior is to merge the content of the configuration element according to element name. If the child POM has a particular element, that value becomes the effective value. If the child POM does not have an element, but the parent does, the parent value becomes the effective value.
In case of conflicts, you can control the default inheritance performed by Maven using combine.children and combine.self. Quoting the Maven docs:
combine.children="append" results in the concatenation of parent and child elements, in that order. combine.self="override", on the other hand, completely suppresses parent configuration.
In addition to this, you need to be aware that when executing a Maven command, on the command line, that directly invokes a goal, such as mvn liquibase:diff, it creates a new execution with an id that is default-cli. As such, since the specific configuration above of the goal diff is done in an execution with id diff, it will not be used. This is actually normal, since the same goal of the same plugin could be present in multiple execution blocks with different configuration: which one should be used if it is executed on the command line, without additional information?
Typically, this situation is solved in 2 manners:
Execute on the command line a specific execution, i.e. the one you configured. This is possible since Maven 3.3.1 and you would execute
mvn liquibase:diff#diff
The #diff in the command above refers to the unique <id> of the execution that is configured in the POM.
Bind your execution to a specific phase of the Maven lifecycle, and let it be executed with the normal flow of the lifecycle. This is generally the prefered solution. In the example above, we could, for example, add a <phase>test</phase> in the execution block of the diff execution; and then Maven will execute it when the test phase is ran during the course of the build.

Related

Maven - check configured value and stop processing

I have a POM file which includes a property (under properties section) which has an IP value that we use when pushing it to git.
<device.ip>1.2.3.4</device.ip>
But for my builds, I need to use a another IP value, so I should change it to my required IP when I start to work on a new branch.
I'd like to be able to check the variable value at build startup and abort it given the variable value is different from what I need.
Any other solutions also welcomed.
(I hope my question would not be downgraded because of lack of code - there is no really code to write here. The scenario is quite self explanatory)
Than you for your advice.
You could use the maven-enforcer-plugin which support such checks.
The usage looks like this for the requirePropery rule.
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M2</version>
<executions>
<execution>
<id>enforce-property</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>device.ip</property>
<message>You must set a device.ip property!</message>
<regex>.*\d.*</regex> <!-- Express the value you need. -->
<regexMessage>The device.ip property contain...</regexMessage>
</requireProperty>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
I would suggest splitting your project in modules.
Module 1 contains your code without any configuration.
Module 2 refers to module 1 and additionally contains what goes into production. For multiple deployments create an additional module for each. This is where your production property goes.
Module 3 refers to module 1 (but not 2) and contains whatever you need for development (configuration like this property and helper classes). For complex scenarios make an additional module for each.
This has worked well for me.

How can I get a maven build to fail on duplicate dependencies?

If I have two dependencies which are the same in the same pom, I want the build to fail. Currently I can detect it happening with the Maven Dependency Plugin's "analyze-duplicate". However, there's no option to failOnWarning like some of the others (plus, it prints at Info level, not Warning). Is there an alternative to extending this?
Generally, when you want the build to fail for some reason, the good plugin to look into the Maven Enforcer Plugin. This plugin can be configured with a set of rules that, when verified, will fail the build.
In this case, it would need to be a rule that checks for duplicate dependencies, and there is a built-in rule just for that: <banDuplicatePomDependencyVersions>. As such, you could have
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce-no-duplicate-dependencies</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<banDuplicatePomDependencyVersions/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
This rule is unfortunately not documented (yet, it will be in the next version, see MENFORCER-259), but it exists since version 1.3 of the plugin (MENFORCER-152).
What this rule does is checking that there are no 2 duplicate declaration with the same 'dependencies.dependency.(groupId:artifactId:type:classifier)'; which is to say that two declared dependencies with the same group id and artifact id declared in the POM will have to have a different type and/or classifier.

Maven deploy two jars with different classifiers from two separate pom.xml

I want to deploy two jar artifacts with different classifiers, but at the moment that fails because both supply their own version of pom.xml. How can I fix that, so that both pom.xmls can be uploaded along with their artifacts?
Example - I have com.test.company.somelib-1.0.0-cmp1.jar and com.test.company.somelib-1.0.0-cmp2.jar, where cmpX is a classifier. Both packages contain (logically) the same code and classes (of the same version), they only differ slightly in the way they were preprocessed. The classifier annotation is there due to backwards compatibility we need to maintain.
Long story short, first artifact uploads fine, second one fails with Forbidden, because our repository does not allow overwriting artifacts (and I want to keep it that way).
There is a slightly different pipeline that creates both the packages, so it is easier to have their builds separate. I just want to deploy them as two packages of the same name and different classifier.
Thanks for help
Edit: it has been suggested to use Maven profiles. I can see that they would work, but they would not be ideal.
Consider the setup I have depicted on the picture below - there is a CI server (TeamCity).
There is a "starter" build (Sources). This build checkouts all required source files.
From this starter build several other builds are triggered (processing using x.x.x/compile). Each of those builds adjusts a template-pom.xml (fills in particular classifier and other info), and then builds and deploys its artifact to our Artifactory.
With the setup I want to achieve if I decide to add another processing-build, all I need to do is add another "branch". If I was using profiles, I would need to also add a new profile to the pom.xml file.
Correct me if I am wrong please. Profiles seem to be able to achieve the goal, but not ideally, at least in my case.
I strongly discourage having 2 (or more) different pom files with the same GAV.
But I understand your need is raised by legacy reasons.
I have not tried this myself but it could be working:
Leave one build (= maven project) as you have it now. On the other build skip the normal deployment and manually invoke the deploy-file goal of the deploy plugin like so:
<build>
<plugins>
<!-- skip normal execution of deploy plugin -->
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<executions>
<execution>
<id>default-deploy</id>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
<!-- invoke with goal: deploy-file -->
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<executions>
<execution>
<id>someId</id>
<phase>deploy</phase>
<goals>
<goal>deploy-file</goal>
</goals>
<inherited>false</inherited>
<configuration>
<file>path-to-your-artifact-jar</file>
<generatePom>false</generatePom>
<artifactId>xxx</artifactId>
<groupId>xxx</groupId>
<version>xxx</version>
<classifier>xxx</classifier>
<packaging>xxx</packaging>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

Still confused about Goals in Maven

I kind of understand most things in Maven, but trying to understand goals is very frustrating. The main problem is that Maven seems to want to hide everything and anything to do with Goals.
If I have a plugin with an execution, and this execution has a goal,
does the goal attach itself somewhere near particular other goals?
How does it know which phase it belongs in?
Does it somehow replace some other goal?
Case in point :
<plugins>
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>wsimport-from-jdk</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<executable>${tool.wsimport}</executable>
<wsdlUrls>
<wsdlUrl>http://WorkPC:8080/server-web/AirlineWS?wsdl</wsdlUrl>
</wsdlUrls>
<packageName>com.bluewalrus</packageName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
This is a wsImport goal which generates artifacts from a web service. It happens before I compile my project. How on earth can this XML tell me where this goal should execute? It just doesn't seem clear to me.
I mean what I am saying, is that I would expect something like "bind-to-process-resources right after goal-xyz". It all seems a bit nebulous to me.
Unfortunately, the pom.xml cannot tell you everything about how a plugin's goals are bound. A plugin can define a default lifecycle phase to bind to and this will not be reflected in the pom.xml. Looking at the documentation for the jaxws-maven-plugin I see this line for the wsimport goal:
Binds by default to the lifecycle phase: generate-sources.
You can override the lifecycle phase to bind to by adding a <phase> element to the plugin's <execution>. For example, if you wanted the goal to run right before packing the artifact (not sure why you would, but bear with me for this example) you could specify <phase>package</phase> after the execution <id>
I would recommend taking a look at the official Maven guide to configuring plugins for more details.
Also you would want to read:
The phases's order in standard lifecycles
The phases's bindings for lifecycle and packaging types

maven, execution tag, id tag missing

I'm looking at the plugin section of a pom I'm inspecting and found this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-docck-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>pre-site</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
If you observe the execution section you will notice that it does not have an id tag. My question is how is the id tag used by Maven and how the absence of one influences the observed behavior. I looked into Maven tutorials and could infer that id's of different execution phases must be unique, in a pom not necessarily across the inherited poms, but it did not mention how it is utilized.
For Maven 3.0.x at least, when not specified, the ID for an execution is default-goalName. So for the example you have, the ID would be default-check. The value default-cli may also be used to configure command line executions.
The execution IDs are used when creating the effective POM from the POM itself, any parent POMs (including the Maven super POM), and settings.xml. Maven merges configuration for plugin executions having the same ID across these POMs. Here's an example. Assume this plugin config is in a parent POM (only Maven super POM is higher up in the hierarchy.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<!-- default-jar is the ID assigned to the jar:jar execution
included automatically by Maven. This demonstrates how we
can tweak the built-in plugin executions to meet our needs.
Note we do not have to specify phase or goals, as those are
inherited. In the example we add a configuration block and
change the values of the <forceCreation> and <finalName>
elements. -->
<execution>
<id>default-jar</id>
<configuration>
<finalName>firstJar</finalName>
<forceCreation>true</forceCreation>
</configuration>
</execution>
<!-- Add an execution of the jar plugin to build a jar with the
same contents but different name. We assign an execution ID.
Because we are not inheriting config for this execution it's our
responsibility to specify phase and goals, as well as the config
we want. Executions are run in order so this one will run after
the default. -->
<execution>
<id>another-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<finalName>duplicateJar</finalName>
</configuration>
</execution>
<!-- Configure plugin behavior if we execute the jar:jar goal
directly from the command line. Don't bind this to a phase;
we don't want to run this as part of the normal lifecycle. -->
<execution>
<id>default-cli</id>
<configuration>
<finalName>cmdLineJar</finalName>
</configuration>
</execution>
</executions>
</plugin>
With the above config:
mvn clean package - builds firstJar.jar and duplicateJar.jar
mvn jar:jar - builds cmdLineJar.jar (note, no clean lifecycle!)
mvn clean jar:jar - removes target dir, builds empty (except for manifest) cmdLineJar.jar; because jar:jar does not run the full lifecycle, just one goal
mvn clean prepare-package jar:jar - runs lifecycle thru prepare-package, then builds a non-empty cmdLineJar.jar
The problem can not be treated with respect to id tag only but notice the different values of it through the examples. This has been tested with maven 3.0.5. Consider the following pom part:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-docck-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>some-other-other-id</id> <!-- No goal for execution is defined -->
<phase>pre-site</phase>
</execution>
<execution>
<phase>pre-site</phase> <!-- No id for execution is defined -->
<goals>
<goal>check</goal>
</goals>
</execution>
<execution>
<id>some-id</id> <!-- No phase for execution is defined -->
<goals>
<goal>check</goal>
</goals>
</execution>
<execution>
<id>some-other-id</id> <!-- Both id and phase defined -->
<phase>pre-site</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
When run mvn clean site from command line it outputs the following:
[INFO] --- maven-docck-plugin:1.0:check (default) # MavenJavaApplication ---
[INFO] Skipping unsupported project: MavenJavaApplication
[INFO] No documentation errors were found.
[INFO]
[INFO] --- maven-docck-plugin:1.0:check (some-other-id) # MavenJavaApplication ---
[INFO] Skipping unsupported project: MavenJavaApplication
[INFO] No documentation errors were found.
Notice that the execution outputs are always in form of:
<plugin-name>:<plugin-version>:<phase> (<execution-id>)
Case 1: No goal for execution is defined
From Build lifecycle basics:
A plugin goal represents a specific task (finer than a build phase) which contributes to the building and managing of a project. It may be bound to zero or more build phases. A goal not bound to any build phase could be executed outside of the build lifecycle by direct invocation. (...) Moreover, if a goal is bound to one or more build phases, that goal will be called in all those phases.
From Guide to configuring plugins: Configuring build plugins:
But if the goal is not bound to any lifecycle phase then it simply won't be executed during the build lifecycle.
From what is quoted, it may be concluded that the execution with id some-other-other-id can be ran from the command line, but that is not so, it can never be ran - it will be covered in the 5th example.
Case 2: No id for execution is defined
The definition of goal and a phase in the first execution is enough for it to get run so it gets assigned a default execution id of value default and it gets executed.
Case 3: No phase for execution is defined
Since the phase is not defined anywhere this execution does not get executed. It can be verified by the fact that the output does not contain the line with its execution id.
Case 4: Both id and phase defined
This execution defines all three: an id, a phase and a goal so it gets executed.
Case 5: CLI execution
If you run (read the syntax in the docck plugin documentation):
mvn docck:check -Doffline=true
it will output:
[INFO] --- maven-docck-plugin:1.0:check (default-cli) # MavenJavaApplication ---
From Guide to configuring default mojo executions:
Starting in Maven 2.2.0, each mojo invoked directly from the command line will have an execution Id of default-cli assigned to it, which will allow the configuration of that execution from the POM by using this default execution Id
You can provide the properties for the goal executed from CLI in three different ways:
in the command line directly
in the plugin configuration
in the execution tag with id of value default-cli
Specifically, the above command is equivalent of running
mvn docck:check
with the pom containing:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-docck-plugin</artifactId>
<version>1.0</version>
<configuration>
<offline>true</offline>
</configuration>
</plugin>
or:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-docck-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>default-cli</id>
<phase>pre-site</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<offline>true</offline>
</configuration>
</execution>
</executions>
</plugin>
This last part comes in handy if you want to keep the global configuration for some common properties in different executions, but you want a complete other set of properties for running from CLI.
Case 6: The default execution
Since the maven-docck-plugin has no default binding I'll cover it with the maven-compiler-plugin. Consider an empty pom with jar packaging. If you run:
mvn clean install
it will trigger the compile phase also and you will see in output:
[INFO] --- maven-compiler-plugin:2.3.1:compile (default-compile) # MavenJavaApplication ---
To cover the value of the id tag, from Guide to Configuring Default Mojo Executions:
Likewise, each mojo bound to the build lifecycle via the default lifecycle mapping for the specified POM packaging will have an execution Id of default-<goalName> assigned to it, to allow configuration of each default mojo execution independently.
If you run mvn help:effective-pom you will find the default execution definition for compiler plugin in output:
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
It gets inherited from super POM for the jar packaging type:
When no packaging is declared, Maven assumes the artifact is the default: jar. The valid types are Plexus role-hints (read more on Plexus for a explanation of roles and role-hints) of the component role org.apache.maven.lifecycle.mapping.LifecycleMapping. The current core packaging values are: pom, jar, maven-plugin, ejb, war, ear, rar, par. These define the default list of goals which execute to each corresponding build lifecycle stage for a particular package structure.
In other words, the above default execution definition is the consequence of a default lifecycle mapping (documentation, definition ) for the compiler-plugin:
The Compiler Plugin has two goals. Both are already bound to their proper phases within the Maven Lifecycle and are therefore, automatically executed during their respective phases.
compiler:compile is bound to the compile phase and is used to compile the main source files.
Uniqueness of an execution id tag
From Guide to configuring plugins.html: Using the executions tag:
Note that while execution id's have to be unique among all executions of a single plugin within a POM, they don't have to be unique across an inheritance hierarchy of POMs. Executions of the same id from different POMs are merged. The same applies to executions that are defined by profiles.

Categories