I have this multi-module project.
In the beginning of each build I would like to run some bat file.
So i did the following:
<profile>
<id>deploy-db</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
<inherited>false</inherited>
</execution>
</executions>
<configuration>
<executable>../database/schemas/import_databases.bat</executable>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
when i run the mvn verify -Pdeploy-db from the root I get this script executed over and over again in each of my modules.
I want it to be executed only once, in the root module.
What is there that I am missing ?
Thanks
I might be mistaken but when you add a plugin to the <pluginManagement> section each and every sub-module inherits it and "runs" it.
I think that you should move you exec-maven-plugin and its <execution> to the normal <plugins> section.
So the issue you're having is that you're trying to do something in the parent POM. That's not how parent poms are designed in maven (i.e. not "the maven way"). You should only perform actions in "leaf node" poms, the parents are just for aggregation and putting shared behavior that should be reused in each child.
So the simple answer at how to call your script is to analyze the dependencies between your children to determine which needs to happen first (and impose dependency if necessary to enforce this), then add the plugin to that child. If it doesn't fit well in that child for some reason, you can make another child that just performs this action.
On a side note, never reference relative file paths in maven. You're using "../database/schemas/import_databases.bat". If import_databases.bat isn't inside the project directory then assuming it's in the parent directory is asking for a mess. You should instead use something like "${basedir}/src/main/scripts/import_databases.bat"
Related
In my parent POM, I defined a dependency plugin with phase prepare-package inside <pluginManagement><plugins>.
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${version.plugin.resources}</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>${version.plugin.dependency}</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${classpathDir}</outputDirectory>
<includeScope>runtime</includeScope>
<excludeClassifiers>${dependencyClassifiers}</excludeClassifiers>
</configuration>
</execution>
</executions>
</plugin>
In my child POM, I didn't specify any dependency plugin. It didn't get executed. I have to put this in <plugins> to get it to trigger:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
The Maven goals I'm using are clean install.
My question is, why do I have to explicitly specify maven-dependency-plugin again in my child POM?
Other plugins like maven-jar-plugin, maven-resource-plugin, maven-compiler-plugin are running even though I didn't re-declare them in my POM. Why is it inconsistent?
dependency's phase was configured as prepare-package, which is before package phase in the Maven lifecycle, hence I presume it should have been "executed in the order given up to the point of the one specified". But it isn't, why?
Thanks in advance to anyone who is able to help with my enquiries! :)
The section <pluginManagement> is used to share plugin configurations between this project and child projects. Plugins are only executed if they are defined in <plugins>. See this answer for more information.
However, some plugins don't need to be defined in <plugins>. This applies to plugins of the built-in lifecycle binding like maven-jar-plugin, maven-resource-plugin and maven-compiler-plugin.
My Spring Boot project has build description:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.18.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.app.MainClass</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
I want my JAR file name to be app-1.0-SNAPSHOT.jar in one branch and 1.0-RELEASE.jar in another, controlled by Jenkins (using some kind of mvn settings or JVM argument such as -D..
Can I do this?
So simple, In one branch, you have pom.xml with
<build>
<finalName>app-1.0-SNAPSHOT</finalName>
</build>
In other branch, you have pom.xml with
<build>
<finalName>1.0-RELEASE</finalName>
</build>
You can propagate the version of the project to your build name like this:
<build>
<finalName>app-${project.version}</finalName>
</build>
or the version of your parent project if you have one:
<build>
<finalName>app-${parent.version}</finalName>
</build>
Then you would keep track of you project version rather than the build name.
However, note that managing the build verson in SCM using branches is a pain in the neck and error prone. It is rather recommanded that your code repository woud be agnostic of your build version.
A possible alternative would be to use some release management tool, like maven release plugin, or even more simple maven version.
Example:
Here I'll give and example using maven verion.
Say you're using SCM tool (it could be git) and a build factory (like Jenkins or any other tool). Say you have a job to build and deploy snapshots and another one for releases.
In the snapshot job, you can set-up a pre-build task with the following maven target:
versions:set -DnewVersion=app-1.0-SNAPSHOT
and the following in the release job:
versions:set -DnewVersion=app-1.0-RELEASE
Now doing this is OK, because you are only doing it locally and never have to manage the build version in your code.
Now, you can tag your (release) version after having applied maven version and build successfuly (hopefuly including unit, integration and functional tests). This way you may keep track exactly of the code that has been deployed on each release.
Tip!! Space is money! Do yourself a favour: clean your snapshot repository regularly. Creating a job that does so every once in a while shouldn't be to difficult.
You can specify the artefact-name with the maven boot plugin:
In this case, it will be NewJarName.jar
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<finalName>NewJarName</finalName>
</configuration>
</execution>
</executions>
</plugin>
I have a multi-module maven project with parent POM. One child of project is customized for different environments by profiles and parent pom also build needed modules depending on selected environment (profile).
I want to prevent building (read as "to run mvn package" in child module) customized child project without profile activated, because there is no "generic" or "default" version for environment. Another words, I want to force developer to use environment-dependent profile.
Is it possible to do so?
Maven Enforcer is made just for this requirement. Simply add the required profiles.
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>enforce-all-profiles-are-activated</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireActiveProfile>
<profiles>first,second</profiles>
</requireActiveProfile>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
I noticed an unexpected behavior. I have an aggregation POM for the purposes of aggregated goals execution.
When I execute the build task, the modules included in aggregation POM have their javadoc generated. The javadoc generation is defined in parent POM (not the same as aggregation POM) like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
The child module has its own POM, in which an aspectJ plugin is defined like this: (this is how the build tag actually looks like as a whole in the child POM:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.6</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<complianceLevel>1.7</complianceLevel>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
</dependencies>
</plugin>
</plugins>
</build>
Now, when I run the aggregation build, it generates javadocs with Java 1.8 (there is no mention about which java to use in aggregation POM):
Constructing Javadoc information...
Standard Doclet version 1.8.0
Building tree for all the packages and classes...
...
12 errors
16 warnings
But when I run build just on the child module, it will use Java 1.7.0_45
Constructing Javadoc information...
Standard Doclet version 1.7.0_45
Building tree for all the packages and classes...
...
2 warnings
Why this inconsistency? I would expect that the build should work the same. Am I doing something wrong? How does one configure the aggregation build to use the configuration of the child module (with its POM), which to me seems the way which should be default.
My assumption is that aggregation build is the same thing as running "install" goal on each child module manually as if on a seperate project. Is this assumption wrong? (seems like it is, since this behaviour) If yes, what is actually happening?
If information are missing (parts of pom configurations) please comment.
In a multi-module project, how can you specify that you want to execute a plugin goal in all the child-modules, but not on the parent project? There is <pluginManagement>, but that only defines the configuration for the execution -- the child modules would still need to reference the plugin to get the goal executed:
[...] However, this only configures plugins that are actually referenced within the plugins element in the children. (POM Reference)
Any other way to achieve this?
UPDATE: I've tried this according to Pascal's advice:
<!-- ... -->
<packaging>pom</packaging>
<modules>
<module>child</module>
</modules>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- ... -->
This will still generate a .jar for the parent project, even though the jar goal is bound to the integration-test phase.
According to the Default Lifecycle Bindings, the bindings for a packaging pom are:
Default Lifecycle Bindings - Packaging
pom
package site:attach-descriptor
install install:install
deploy deploy:deploy
So if your parent POM has a <packaging>pom<packaging> (this should be the case as pointed out in a comment) and if you bind your plugins to other phases than those above (see the Lifecycle Reference for a comprehensive list), they won't be executed during the build of the parent POM.
(EDIT: My initial answer is just wrong. If you bind a plugin goal to a particular phase, it will be triggered during that phase, regardless of the packaging of the project. The Default Lifecycle Bindings don't have anything to do with that, they are just default lifecycle bindings. All what matters is if the phase to which the plugin is bound is part of the build lifecyle.)
As you pointed out, you can use the pluginManagement in the parent pom for the configuration of the plugin but if you really want to execute a plugin goal in children modules and not in the parent (you might have good reasons to do this but most of time, plugins won't have much effet on a module with a pom packaging that doesn't have any content), you'll have to reference plugins in the plugins element in the children.
Applied to your example, the parent pom.xml could define the following specifications:
<project>
<packaging>pom</packaging>
...
<modules>
<module>child</module>
</modules>
...
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>my-execution-id</id>
<phase>integration-test</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</pluginManagement>
</build>
...
</project>
And in every child pom.xml, only the following is required:
<project>
...
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
</plugins>
...
</build>
</project>
The described solution with plugin management is certainly correct, but in certain cases it does not fit. Suppose you would like to run several jar:jar goals in the child module each configured with its own settings (configuration) per execution. Or in general, when you don't want to force child poms to explicitly trigger the plugin(s).
In this case the solution that worked for me was to define the executions in the parent pom under a specific profile, and have it activated only in child poms for example by checking for existence of some file or property:
<profile>
<id>generate-dc</id>
<activation>
<file>
<exists>src/main/assembly/some.xml</exists>
</file>
</activation>
Then plugins won't be executed in the parent, but will be executed in all children if those contain the file, or set some property.
I had a similar requirement to run some plugins in the child but not the parent POM. i achieved this by stating <skip>true</skip> in the parent POM.
The parent pom entry is below:
<plugin>
<groupId>eviware</groupId>
<artifactId>maven-soapui-plugin</artifactId>
<version>4.0.0</version>
<inherited>false</inherited>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
</dependency>
</dependencies>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
The child project pom entry is below
<plugins>
<plugin>
<groupId>eviware</groupId>
<artifactId>maven-soapui-plugin</artifactId>
<version>4.0.0</version>
<configuration>
<settingsFile>site-service-web/src/test/soapui/soapui-settings.xml</settingsFile>
<projectFile>site-service-web/src/test/soapui/PodifiSite-soapui-project.xml</projectFile>
<outputFolder>site-service-web/target/surefire-reports</outputFolder>
<junitReport>true</junitReport>
<exportwAll>true</exportwAll>
<printReport>true</printReport>
</configuration>
</plugin>
</plugins>
This below config worked for me. Add the plugin in both the parent and child pom.
Parent :
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<inherited>true</inherited>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
Child
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<inherited>false</inherited>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
</build>
I tried the answer from Pascal but it did not work for me. The plugins referenced in the child pom did not execute, I'm assuming because they did not have a build phase binding.
The post here describes a solution that works by binding the plugins to execution ids and build phases: How to override default binding to phase of a Maven plugin
I'd recommend that to anyone else trying to get this working.
Use <inherited>false</inherited> under the plugins section in the parent project.
Plese refer to this page for more information.