Executing Maven3 exec plugin with no inheritance - java

I have a multi module maven java project where I want to execute the exec plugin in order to execute a custom command after the Jars has been created.
I call maven package assembly:assembly exec:exec on the parent POM to create the project output.
I used the following in the parent POM:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<executable>myExecutable.exe</executable>
<workingDirectory>${basedir}</workingDirectory>
<arguments>....</arguments>
</configuration>
</plugin>
When doing so, my executable got executed correctly but was executed for every child module as well.
In order to try and fix it, I've set the plugin to not get inherit to the child modules:
<inherited>false</inherited>
But now the exec plugin fails with a The parameters 'executable' for goal org.codehaus.mojo:exec-maven-plugin:1.2.1:exec are missing or invalid error.
I've tried setting the plugin to run under the "executions" element and assign it to a maven life cycle phase. This caused the executable to run successfully, but I am unable to do this since I need to execute other plugins (assembly plugin) before I execute this exec plugin.
How can I run this (exec) plugin just once after the package phase has completed and the other plugin (assembly) has been finished as well?
In other words, I want to execute 'package' for all of my child modules and then execute the exec plugin just once from the parent.
I will appreciate any help.

When you run a command at the parent POM level, you are telling Maven to invoke that part of the lifecycle for every module.
If you only want to invoke exec:exec for the child module, you should only declare that plugin for the child module (as it has no meaning for other modules that inherit the parent) and invoke Maven with the --projects or -pl argument:
mvn -pl child package assembly:assembly exec:exec
This command, when executed from the parent project, executes package assembly:assembly exec:exec for only the child project.
However, if what you really are trying to accomplish is that you can package all of the modules in a single command, and you want the assembly:assembly and exec:exec goals to be executed for that child module during the package phase, then you want to bind these plugins to that phase. For example:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<executable>myExecutable.exe</executable>
<workingDirectory>${basedir}</workingDirectory>
<arguments>....</arguments>
</configuration>
<executions>
<!-- run the exec goal of this plugin every time this module is packaged -->
<execution>
<phase>package</phase>
<goals><goal>exec</goal></goals>
</execution>
</executions>
</plugin>

This will skip inheritance on exec-maven-plugin executions previously configured:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
...
</build>

Related

How to build a module separately in multimodular maven project?

Following maven-ci-friendly article in official Maven documentation, this multimodule project (minimal example) was created.
There are three modules and a root project (inception):
/inception
/modules
/base (common parent of 'core' and 'facade')
/core (child of 'base')
/facade (child of 'base' having 'core' as a dependency)
Executing mvn package from inception works as expected - all 3 *.jar artifacts are being created in the corresponding target forlders.
I would like to have an option of building facade module separately.
Unfortunately, mvn package from modules/facade fails to collect dependencies and fails with error
[ERROR] Failed to execute goal on project sample-facade:
Could not resolve dependencies for project sample.group:sample-facade:jar:0.0.1:
Failed to collect dependencies at sample.group:sample-core:jar:0.0.1:
Failed to read artifact descriptor for sample.group:sample-core:jar:0.0.1:
Could not transfer artifact sample.group:sample-base:pom:${revision}
The surface problem is that ${revision} is not being resolved into 0.0.1.
Could you help me workaround this issue?
The flatten-maven-plugin solves the problem.
Thanks to #khmarbaise, who adviced in the comments reading the docs to the end.
Adding the plugin to /modules/base/pom.xml solved the problem with building a submodule separately:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.2.5</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
Before starting a phase on facade module, it is required to have base and core in the local repository, so maven could find the artifacts. Hence, here is the sequence of actions in root:
mvn install -pl modules/base,modules/core (or just mvn install)
mvn package -pl modules/facade

How to run a Maven enforcer rule before the Maven release prepare changes the pom.xml?

I've created a custom Maven enforcer rule. This rule will check the content of the <scm><connection> value to ensure that it points to the trunk or branches/* (i.e. not a tag).
This enforcer is configured in the pom.xml like that:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>
<dependencies>
<dependency>
<groupId>my.company</groupId>
<artifactId>maven-release-enforcer</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>enforce-release-check</id>
<goals>
<goal>enforce</goal>
</goals>
<phase>validate</phase>
<configuration>
<rules>
<releaseCheck implementation="my.company.maven.release.enforcer.MavenReleaseEnforcer"/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Unfortunately, when we use it with the Maven Release plugin, the latter plugin changes the content of the <scm><connection> value during its [enter link description here]prepare2 goal, so before the enforcer is effectively called. This results in a failure of my custom rule, as the <scm><connection> points to a tag at this time.
So my question: is there a way to force the enforcer to be called before the Maven Release plugin start to modify the pom.xml?
ps: the Jenkins job is divided into 2 steps: mvn clean release:prepare and mvn release:perform.
when you call
mvn clean release:prepare
only the clean phase and the prepare goal is excuted.
You could use
mvn clean validate release:prepare
to include the validate phase or
mvn clean maven-enforcer-plugin:enforce release:prepare
to just trigger the enforcer plugin

Mechanics of Goal execution in Maven

I have the wsimport plugin in my project.
I would like to execute the wsimport. According to the website, the string to execute is "mvn jaxws:wsimport".
Firstly, is this string deductable from the XML ?
The artifact ID is :
<artifactId>jaxws-maven-plugin</artifactId>
and goal :
<goal>wsimport</goal>
so is the artifact-part just the substring of the artifactid leading up to "-maven-plugin" ?
..And when I execute my plugin goal "mvn jaxws:wsimport" does this completely ignore which phase I am in? Ie. is this running outside of the phase? And if no, is there a way to run this standalone?
ie. is there a way I can set the phase to none? (eg [phase]none[/phase]).
Pom code :
<build>
<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>
</build>
When you issue a command like mvn [plugin]:[goal], it launches Maven out of any lifecycle, so if you do not intend to perform that goal inside a lifecycle, but only via such commands, you shouldn't have any <execution> defined, just place <configuration> right after <version>.
About how Maven can shorten the plugin call (i.e. mvn dependency:tree instead of mvn org.apache.maven.plugins:maven-dependency-plugin:2.1:tree), it is based on several conventions:
When no version defined, it tries to take the latest from available repositories
When the groupId is omitted, it looks among the predefined or user-defined pluginGroups to find a suitable one. See here for more information (Configuring Maven to Search for Plugins)
On the same page, you can see how plugins prefixes are used to shorten the plugin prefix, by using a prefix instead of the artifactId of the plugin. Thirdparty plugins should use [prefix]-maven-plugin construction, and it looks OK here.
And to disable the default execution of a plugin (although it might not be useful in this case), you can use this answer

Using property file in maven

I don't quite understand how it can be used. There is a property defined in the file. I try to use maven property plugin to read it and save. The property is used in the liquibase plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-1</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>src/main/resources/properties/app.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>2.0.5</version>
<configuration>
<propertyFile>src/main/resources/db/config/${env}-data-access.properties</propertyFile>
<changeLogFile>src/main/resources/db/changelog/db.changelog-master.xml</changeLogFile>
<migrationSqlOutputFile>src/main/resources/db/gen/migrate.sql</migrationSqlOutputFile>
<!--<logging>debug</logging>-->
<logging>info</logging>
<promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
<!--<verbose>false</verbose>-->
<dropFirst>true</dropFirst>
</configuration>
</plugin>
According to the documentation in order to read property and save it I have to run: mvn properties:read-project-properties. But I'm getting the following error in this case:
[ERROR] Failed to execute goal org.codehaus.mojo:properties-maven-plugin:1.0-alpha-2:read-project-properties (default-cli) on project SpringWebFlow:
The parameters 'files' for goal org.codehaus.mojo:properties-maven-plugin:1.0-alpha-2:read-project-properties are missing or invalid -> [Help 1]
I've changed pom.xml, removed the <execution> section and moved the <configuration> section:
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-1</version>
<configuration>
<files>
<file>src/main/resources/properties/app.properties</file>
</files>
</configuration>
Ok. now, when I run mvn properties:read-project-properties the error disappeared. But where in this case the property is saved? Cause when I start the following maven goal:
mvn liquibase:update
I can see that the ${env} property is not defined. Liquibase tries to use the src/main/resources/db/config/${env}-data-access.properties file.
What am I doing wrong? How to read a property from the file, so it could be accessible from different maven plugins?
The problem is that "mvn liquibase:update" is a special plugin goal and is not part of the maven life cycle. So it never passes the initialize phase and so the property plugin is not executed.
The following will work
mvn initialize liquibase:update
One solution would be to call liquibase:update in one of the maven lifecylce phases like compile, package ..., but then it would be executed on every build.
Or you use the maven-exec plugin to call "initialize liquibase:update" from maven. Or you create a profile were you bind the liquibase:update to the lifecylce phase initialize and the udate is executed when you call
mvn initialize -Pliquibase
I do not know a better solution to this problem and I could not find a suitable solution for this.
For reference:
Maven lifecycle

Passing arguments to Maven release build

I'm trying to release a library using Maven and perform a site-deploy to sourceforge (I have create an interactive shell first). The release is done by a Jenkins job (using the Maven Release Plugin for Jenkins).
I tried:
-X -e -Dresume=false -Dusername=puce release:prepare release:perform -Darguments="-Dusername=puce"
and
-X -e -Dresume=false -Dusername=puce -Darguments=-Dusername=puce release:prepare release:perform
but both times the job hangs at site:deploy of the first module:
[INFO] --- maven-site-plugin:3.2:deploy (default-deploy) # myproject-parent ---
[INFO] Parent project loaded from repository: myGroupId:myOtherproject-parent:pom:1.0
[INFO] Parent project loaded from repository: myGroupId:myOtherproject-parent:pom:1.0
Using private key: /opt/jenkins/.ssh/id_dsa
When I stop the job, the following gets printed at end:
Password for ${username}#shell.sourceforge.net: channel stopped
which probably means that ${username} wasn't resolved.
How can I resolve the ${username}?
Edit:
Note that the following runs fine:
site-deploy -Psonatype-oss-release -Dusername=puce
Edit 2:
As part of release:perform maven executes the following command:
/usr/share/maven/bin/mvn -s /tmp/release-settings7797889802430474959.xml deploy site-deploy --no-plugin-updates --batch-mode -Psonatype-oss-release -P nexus -f pom.xml
-Dusername=puce doesn't seem to get passed to this maven command...
Also note that help:effective-pom shows the following maven-release-plugin configuration:
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<mavenExecutorId>forked-path</mavenExecutorId>
<useReleaseProfile>false</useReleaseProfile>
<arguments>-Psonatype-oss-release</arguments>
</configuration>
</plugin>
So 'arguments' gets defined and its value seems to reach the embedded maven command instead of the value passed on the command line...
What I've successfully done in the past is as follows:
Define a property in the POM file, e.g.:
<properties>
<release.arguments></release.arguments>
</properties>
Add the POM property to the plugin configuration in the POM file, e.g.;
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<arguments>${release.arguments}</arguments>
...
Pass the argument through the property on the command-line, e.g.:
mvn release:prepare -Drelease.arguments="-N -Prelease"
Hope this helps.
Overriding
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<mavenExecutorId>forked-path</mavenExecutorId>
<useReleaseProfile>false</useReleaseProfile>
<arguments>-Psonatype-oss-release</arguments>
</configuration>
</plugin>
with
<plugin>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<mavenExecutorId>forked-path</mavenExecutorId>
<useReleaseProfile>false</useReleaseProfile>
<arguments>-Psonatype-oss-release -Dusername=${username}</arguments>
</configuration>
</plugin>
in one of the parents did the trick.
It seems to be a bug that the value on the command line doesn't override the value in the POM.
My solution was similar to Sander Verhagen's. I added only line only though.
How I run:
mvn --batch-mode release:prepare -Denvironment=production
My config:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<tag>${artifactId}-${version}-${environment}</tag>
<arguments>-Denvironment=${environment}</arguments>
<releaseProfiles>release</releaseProfiles>
</configuration>
</plugin>
</plugins>
</build>
The difference is that now my submodules use the variable environment and I don't need to define it twice (I.e. -Darguments=-Denvironment=production -Denvironment=production). I also gives me the flexibility of not adding the properties tag.

Categories

Resources