How to use Maven Release Plugin with Multiple Maven Projects - java

I'm using Maven 3.
I have multiple maven projects, namely: the 'data model', the 'service', and the 'presentation', split into 3 different projects. They are configured separately (ie. not using maven parent pom).
I have maven release plugin setup on my project correctly, such that when I run mvn release:clean release:prepare release:perform on each individual project, it updates the project version (ie: from 3.4.5-SNAPSHOT to 3.4.5) as well as all the other things.
The problem here is, 'presentation' is dependent on 'service' is dependent on 'data model', and I refer to the projects in the pom files with the version number.
While I develop, say for example I would refer to 'service' in 'presentation' as 3.4.5-SNAPSHOT. But during deploy, I have to release 'service' to change the version to 3.4.5, then I have to update my version reference of 'service' in 'presentation', before I can run a release on 'presentation'.
Is there an automated way of doing this such that I don't need to update the reference of dependent projects during release?
What I have so from thanks to below comments: Updated: 25/03/2013
Run maven with:
versions:use-releases -Dmessage="update from snapshot to release" scm:checkin release:clean release:prepare release:perform
Outcome: version updated, but release build failed.

The Versions Maven Plugin may help you to achieve requirement, especially the goal versions:use-releases. You may be interested in the goal versions:use-next-releases and versions:use-latest-releases as well.
Side Note:
Normally, the good practice is define them as a Maven Multiple Module( here and here). This allow us to manage the version easier as the following example.
The parent
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
.....
<modules>
<module>my-model</module>
<module>my-service</module>
<module>my-ui</module>
</modules>
The my-model
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>my-model</artifactId>
The my-service
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>my-service</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>my-model</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
The my-ui
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>my-ui</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>my-service</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
Regarding to the above example when we release, the related version will be updated based on the parent version automatically.

Related

Spring boot multi module maven projects without repository

I have multiple spring boot projects, every project is independent and has its own CICD pipeline.
These projects need some common classes, I have created a separate project with common classes.
Parent
pom.xml (with packaging)
lib-project
pom.xml
project-1
pom.xml
project-2
pom.xml
I can build project easily from the parent directory, it builds all the projects
parent$ mvn clean package
it generates all the jar files and put them in their respective target folder of projects
My problem is I can't initiate this at the parent level, this has to be initiated from within each project from its own pipeline.
and
I cannot use any local or remote repository, to put the dependent jar in m2 using mvn clean install and then refer to it as dependency
I want to build it from the relavent project directory
parent/project-1$ mvn clean package
it shows following error:
Could not resolve dependencies for project com.test.multiple:project-1:jar:0.0.1-SNAPSHOT: Could not find artifact com.test.multiple:lib-project:jar:0.0.1-SNAPSHOT
My expectation stepwise on compilation of project-1
Check if there is a dependency for project-1
Go to ../lib-project
Compile and build it in target folder (or anywhere relative to our project)
Add this generated jar to "project-1" dependency
Compile and build the "project-1" jar file.
Parent Pom Configurations
<project ...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test.multiple</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>lib-project</module>
<module>project-1</module>
</modules>
</project>
** Lib project pom **
<project ...>
<parent>
<groupId>com.test.multiple</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.test.multiple</groupId>
<artifactId>lib-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>lib-project</name>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Project-1 pom
<project ...>
<parent>
<groupId>com.test.multiple</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.test.multiple</groupId>
<artifactId>project-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>project-1</name>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.test.multiple</groupId>
<artifactId>lib-project</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I have multiple spring boot projects, every project is independent and has its own CICD pipeline.
These projects need some common classes, I have created a separate project with common classes.
Congratulations, your projects are not independent any more!
Given the definitions above, here are the dependencies:
lib-project depends on parent;
project-1 depends on parent;
project-1 depends on lib-project.
Please check Introduction to the POM and Guide to Working with Multiple Modules for the discussion on the dependencies in Maven projects.
I cannot use any local or remote repository, to put the dependent jar in m2 using mvn clean install and then refer to it as dependency
Given this limitation, and dependencies listed above, the POMs and source files of all the projects have to be present on the disk for build purposes. The build process has to start from the parent folder. The build process has to build all modules at once.
Also, please consider using mvn clean verify instead of mvn clean install to avoid populating the local repository with the artifacts you are building.
A maven project isn't designed to build its dependencies on demand. However, jenkins can be configured to build downstream projects when changes are pushed to an upstream dependency.
I have also worked around this by using the -pl option on a parent pom in the relevant jenkinsfile to build a subset of the child projects
Jenkinsfile
clone parent project
mvn clean package -pl core,deployable

How do I manage version numbers with modularized Maven projects?

I have a fairly typical plugin architecture that looks something like this (just larger):
project
core
data
main
ui
The parent project has a version number defined, is packaged as a pom and defines modules in it's pom.xml:
<groupId>group</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
...
<modules>
<module>core</module>
<module>data</module>
<module>main</module>
<module>ui</module>
</modules>
All of the sub-modules have many references to the parent's version number everywhere. Here is the an example of what the main module looks like to give you an idea:
<parent>
<groupId>group</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>group</groupId>
<artifactId>project.main</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>group</groupId>
<artifactId>group.core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>group</groupId>
<artifactId>group.data</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>group</groupId>
<artifactId>group.ui</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
We're getting tired of having to change the version number over, and over, and over with each release in every parent block, in every artifact block, and in every dependency block for each and every module. On a few occasions, someone used search/replace which hit other files and messed up the build. We tried using properties, but that doesn't work inside the parent definitions for some nonsensical reason.
The version number defined in the parent is the only place we care to manage. We don't even need the sub-modules to even HAVE versions (or artifacts, for that matter). We can do this in our other Ant projects. We can do this in our other Gradle projects. I can't imagine this being impossible in Maven, so I am guessing we are missing something.
How can we define the project's version number in one place, and have that used in all of the parent, artifact, and dependency sections in our modules?
Version maven plugin offers the possibility of changing the subprojects version in one shot. After including the plugin:
mvn versions:set -DnewVersion=<your version>
And if everything is correct:
mvn versions:commit

Module dependency vs artifactory

We have maven aggregated pom project as below
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.abc</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>module-1</module>
<module>module-2</module>
<module>module-n</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.xyz<groupId>
<artifactId>framework</artifactId>
<version>1.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xyz</groupId>
<artifactId>dao</artifactId>
<version>1.1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
module-2 has dependency of module-1
AND module-n has dependency of module-1 & module-2.
The maven reactor can resolve all inter-module dependency (build order is module-1, module-2, module-n).
Some shared components from com.xyz is also used by the modules (e.g. framework). They are retrieved from the remote artifactory server, while the inter-module dependency artifacts (e.g. module-1.jar) are retrieved locally during maven build.
My question is what is the best way to associate the dependencies. By module or by the artifacts stored in artifactory server? This example has both usage. I could not figure out under which circumstance we should
1) group all inter-dependent modules under the same parent pom OR
2) always pull the depending artifacts from remote artifactory repo and let each of the module built independently
Any pros and cons? Sorry for my poor English. I hope my question is clear. Thank you!
The rule of thumb is:
Do you always build the jars at the same time? Then they should form a multi-module project.

Maven issue to build one module using revision property

Recently we tried to deploy files using jenkins providing ${revision} property for the build ( Maven 3.3.9 ).
It worked OK on json creating 0.0.1-SNAPSHOT for dev builds and 0.0.1-RC for releases, but we have an issue using maven on developer machines.
We have multi-module maven project with version defined in parent and some modules uses others as dependencies. Both build it from jenkins and use maven locally, to integrate with IDEs and run tests before pushing it into repository.
When we try to build a single module, maven does not recognize ${revision}, although it works fine when we mention all modules e.g. mvn clean install -pl appserver, we see
Failed to execute goal on project appserver: Could not resolve dependencies for project com.org:appserver:war:0.0.1-local: Failed to collect dependencies at com.org:my-kinesis-events:jar:0.0.1-local: Failed to read artifact descriptor for com.org:my-kinesis-events:jar:0.0.1-local: Could not transfer artifact com.org:my-parent:pom:${revision} from/to central: Failed to transfer .../repository/maven-central/com/org/my-parent/${revision}/my-parent-${revision}.pom. Error code 500, Server Error -> [Help 1]
We tried to use:
-Drevision=0.0.1-local
<profile>
<id>default-version</id>
<activation>
<property>
<name>!revision</name>
</property>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<revision>0.0.1-local</revision>
<project.version>0.0.1-local</project.version>
</properties>
</profile>
but the only thing that works is a build for parent that that builds the module and all modules it depends on:
mvn clean install -pl appserver,my-kinesis-events,module1,module2,...
Although the above works it requires from the team to define custom run configuration in IDE, each time they need something.
Did somebody also experienced this issue and found the solution?
Parent pom snippet:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.org</groupId>
<artifactId>my-parent</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<name>My Parent module</name>
<modules>
<module>../my-tools</module>
<module>my-kinesis-events</module>
....
</modules>
.....
</project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>my.org</groupId>
<artifactId>my-kinesis-events<</artifactId>
<version>${project.version}</version>
<dependency>
<dependencies>
</dependencyManagement>
Module pom snippet:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>appServer</artifactId>
<parent>
<groupId>com.org</groupId>
<artifactId>my-dsp</artifactId>
<version>${revision}</version>
<relativePath>..</relativePath>
</parent>
<packaging>war</packaging>
<name>AppServerAPI</name>
<description>Application Server</description>
<dependencies>
<dependency>
<groupId>com.org</groupId>
<artifactId>my-openrtb</artifactId>
</dependency>
.....
</dependencies>
....
</project>
These issues have been fixed since Maven 3.5, you need however to use the maven flatten plugin to ensure that all variables are removed from your POM before publishing. Otherwise you end up having POM containing ${revision} has version.
This is neatly explained in the official maven documentation:
https://maven.apache.org/maven-ci-friendly.html#install-deploy

Maven version with a property

I have big Maven (Tycho) project witch about 400 plug-ins.
We have specified version of application in each POM file.
Is there a way how to specify the version for all POM:s only on one place?
I would expect some think like:
<properties>
<buildVersion>1.1.2-SNAPSHOT</buildVersion>
</properties>
....
<version>${buildVersion}</version>
We have parent pom.xml:
<modelVersion>4.0.0</modelVersion>
<groupId>company</groupId>
<artifactId>build.parent</artifactId>
<version>1.1.2-SNAPSHOT</version>
<packaging>pom</packaging>
Then in each POM is reference to parent POM:
<parent>
<artifactId>build.parent</artifactId>
<groupId>company</groupId>
<relativePath>../build.parent/pom.xml</relativePath>
<version>1.1.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>company</groupId>
<artifactId>artifact</artifactId>
<version>1.1.2-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
If you have a parent project you can set the version in the parent pom and in the children you can reference sibling libs with the ${project.version} or ${version} properties.
If you want to avoid to repeat the version of the parent in each children: you can do this:
<modelVersion>4.0.0</modelVersion>
<groupId>company</groupId>
<artifactId>build.parent</artifactId>
<version>${my.version}</version>
<packaging>pom</packaging>
<properties>
<my.version>1.1.2-SNAPSHOT</my.version>
</properties>
And then in your children pom you have to do:
<parent>
<artifactId>build.parent</artifactId>
<groupId>company</groupId>
<relativePath>../build.parent/pom.xml</relativePath>
<version>${my.version}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>company</groupId>
<artifactId>artifact</artifactId>
<packaging>eclipse-plugin</packaging>
<dependencies>
<dependency>
<groupId>company</groupId>
<artifactId>otherartifact</artifactId>
<version>${my.version}</version>
or
<version>${project.version}</version>
</dependency>
</dependencies>
hth
The correct answer is this (example version):
In parent pom.xml you should have (not inside properties):
<version>0.0.1-SNAPSHOT</version>
In all child modules you should have:
<parent>
<groupId>com.vvirlan</groupId>
<artifactId>grafiti</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
So it is hardcoded.
Now, to update the version you do this:
mvn versions:set -DnewVersion=0.0.2-SNAPSHOT
mvn versions:commit # Necessary to remove the backup file pom.xml
and all your 400 modules will have the parent version updated.
Using a property for the version generates the following warning:
[WARNING]
[WARNING] Some problems were encountered while building the effective model for xxx.yyy.sandbox:Sandbox:war:0.1.0-SNAPSHOT
[WARNING] 'version' contains an expression but should be a constant. # xxx.yyy.sandbox:Sandbox:${my.version}, C:\Users\xxx\development\gwtsandbox\pom.xml, line 8, column 14
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
If your problem is that you have to change the version in multiple places because you are switching versions, then the correct thing to do is to use the Maven Release Plugin that will do this for you automatically.
See the Maven - Users forum 'version' contains an expression but should be a constant. Better way to add a new version?:
here is why this is a bad plan.
the pom that gets deployed will not have the property value resolved, so
anyone depending on that pom will pick up the dependency as being the string uninterpolated with the ${ } and much hilarity will ensue in your
build process.
in maven 2.1.0 and/or 2.2.0 an attempt was made to deploy poms with
resolved properties... this broke more than expected, which is why those
two versions are not recommended, 2.2.1 being the recommended 2.x version.
With a Maven version of 3.5 or higher, you should be able to use a placeholder (e.g. ${revision}) in the parent section and inside the rest of the POM, you can use ${project.version}.
Actually, you can also omit GAV properties outside of <parent> which are the same, as they will be inherited. The result would look something like this:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>build.parent</artifactId>
<groupId>company</groupId>
<version>${revision}</version> <!-- use placeholder -->
<relativePath>../build.parent</relativePath>
</parent>
<artifactId>artifact</artifactId>
<!-- no 'version', no 'groupId'; inherited from parent -->
<packaging>eclipse-plugin</packaging>
...
</project>
For more information, especially on how to resolve the placeholder during publishing, see Maven CI Friendly Versions | Multi Module Setup.
If you're using Maven 3, one option to work around this problem is to use the versions plugin
http://www.mojohaus.org/versions-maven-plugin/
Specifically the commands,
mvn versions:set -DnewVersion=2.0-RELEASE
mvn versions:commit
This will update the parent and child poms to 2.0-RELEASE. You can run this as a build step before.
Unlike the release plugin, it doesn't try to talk to your source control
I have two recommendation for you
Use CI Friendly Revision for all your artifacts. You can add -Drevision=2.0.1 in .mvn/maven.config file. So basically you define your version only at one location.
For all external dependency create a property in parent file. You can use Apache Camel Parent Pom as reference
I have successfully resolved the issue thus:
In parent pom.xml I have sited the version as usual (not inside properties):
<version>0.0.1-SNAPSHOT</version>
In all child modules I used:
<parent>
<groupId>com.example</groupId>
<artifactId>parent-module</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
Then I changed the parent to:
<version>0.0.2-SNAPSHOT</version>
Now, to update the version I executed in the command line:
mvn -N versions:update-child-modules
The children have been updated automatically to:
<parent>
<groupId>com.example</groupId>
<artifactId>parent-module</artifactId>
<version>0.0.2-SNAPSHOT</version>
</parent>
In other words I have used the versions:update-child-modules goal.
I have found this solution here.
The version of the pom.xml should be valid
<groupId>com.amazonaws.lambda</groupId>
<artifactId>lambda</artifactId>
<version>2.2.4 SNAPSHOT</version>
<packaging>jar</packaging>
This version should not be like 2.2.4. etc

Categories