How do I automate the update of SNAPSHOT dependencies to the latest released versions when using maven - maven

I am trying to define a release process for our project.
I was able to use the maven release plugin to accomplish the release but I had to manually update all of our internal SNAPSHOT dependencies to release versions prior to the prepare and then again back to SNAPSHOT versions after the release.
I have used the maven versions plugin and it detects my corporate dependencies that are SNAPSHOT builds and lists the correct release build to use.
I tried the maven release plugin, prepare goal, and complains about the SNAPSHOT versions in my dependencies.
Is there a way to do a release that updates the SNAPSHOT depenedencies to latest released versions and then back to SNAPSHOT versions after the release? Or maybe this is just not the way you are supposed to be using maven with releases and SNAPSHOTS.

When you create a realease with maven: it must be definitive. i.e. once it is created it cannot change anymore (i.e. the sources cannot change and the dependencies cannot change).
So when you create a release of moduleA and moduleA having a dependency on moduleB. moduleB must be released before moduleA is released, and moduleA MUST depends on a released version of moduleB.
One important thing is that you shouldn't go back to SNAPSHOT version. At least as I understand it means :
create moduleB-1.0.0 release
changing dependency to moduleB-1.0.0
create moduleA-1.0.0 release
then change the dependency back to moduleB-1.0.0-SNAPSHOT
It must be clear that once moduleB-1.0.0 exists (i.e. is released): the artifact moduleB-1.0.0-SNAPSHOT shouldn't be used anymore.
Instead of go back to SNAPSHOT should update dependency to next SNAPSHOT version (for instance moduleB-SNAPSHOT-1.0.1)
That being said, releasing a module depending on many SNAPSHOT artifacts is not an easy process, since every dependency must be released prior to releasing your main artifact.
What we have, most of the time, is a main artifact depending on many other artifacts (let's call them the corporate-modules) having the same versionning strategy. And so you can define a property corporate-module-version holding the version used by many dependencies in one place.
The release process is the following:
release every snapshot dependency with version number 1.0.0 (using the maven-release-plugin: after this step all pom.xml of your corporate-module in SCM are 1.0.1-SNAPSHOT) (see important remark at the end of this post to facilitate this step)
manually changing the corporate-module-version property to "1.0.0" in the main artifact (so that all SNAPSHOT dependencies are replaced by just released versions)
commit the modified pom.xml holding the corporate-module-version
with maven-release-plugin: releasing the main artifact (and after that, the new version in the SCM will be something like 1.0.1-SNAPSHOT)
manually changing the corporate-module-version property to "1.0.1-SNAPSHOT" in the main artifact (so that all dependencies are replaced by latest snapshot versions)
Important remark: having a multi-module parent project holding all your corporate modules is a must to perform at once the release of of all corporate modules. To not having too much trouble with the maven-release-plugin and the multi-module parent project be sure to put your parent pom.xml one directory upper all your child pom.xml (it's the designed recommend by maven, but unfortunately, sometimes, eclipse users don't follow it because eclipse don't like hierarchical projects)

Related

Manage dependency version centralized

I've got multiple projects using a certain Dependency of Version XX, if I release a new version, I have to touch every project to change it to version XX.Y.
I've came across an approach to edit my m2 settings <version>${my.version}</version>, to add a parameter and bind it into my POM.xml, but this implicit means, everyuser has to manage their m2 settings when I do a new release.
Is there a way to central (user independant) manage the versions as in SVN, so none has to change anything and it always uses the up2date version, if I release a new version?
In general, the maintainer of every project should decide for themselves if they update the version or not. Updating the version might break things, so they may choose to stay on the older version. Particularly, it is important that the maintainers notice that something has changed, so that tests are run.
For development, though, there are Snapshot versions. A Snapshot dependency always references the newest version, but the -SNAPSHOT indicates this to the maintainer of the project. Snapshot versions should not go to production - the builds are not reproducible.
If artifacts are so tightly coupled that they are build together, think about using multi module projects.
You can use a pattern called "Bill of Material".
I think your question is somehow similar to this question (but not exactly a duplicate), and my answer applies here aswell:
You create a new maven project (the bill of material) that only consists of a pom with dependency management block. Here you declare all your dependencies and their versions. The packaging should be set to pom.
This bill of material (bom) project is now used as parent of all other projects. When using a dependency, only group id and artifact id is specified, the version tag is ommited. In that way, the version will be taken from the bom and you have one central place to manage the versions of the dependencies.
More details with examples are here (in the lower part of the page) or here.

Release Candidate behaving like SNAPSHOT in Maven repository

In development, I can reference the latest version of an artifact as 1.2.3-SNAPSHOT. Now I need the same behaviour for release candidates, i.e. I would like to be able to depend on the latest release candidate (there should also be a procedure for the developer to declare development versions as release candidates).
I am not sure how to implement this behaviour properly. Should I use an additional repository for release candidates and move development versions to this repository if the developer requests it? Or can I somehow define a "second snapshot list", like 1.2.3-RC?
You can get there be re-configure a few things:
use a version range for the dependency
change the updatePolicy for the repository you store the release candidates. see https://maven.apache.org/settings.html (updatePolicy). If you store the artifacts in a maven proxy usually you need to allow to overwrite releases.
Remember in a multi module build that they might upload modules before detecting a failed build (due to mvn deploy being a phase not a goal). You need to verify the complete build is ok before starting to upload artifacts in the maven repository. Or stage them somehow.
Remember this will most certainly prevent your builds being reproducible. Since an RC dependency might change between builds. You would need to change the version range - which is not always an issue. Ranges may work for you.
I've better experience to let developers stay on snapshots but have the CI server set an explicit version (for example using the versions plugin) prior to deployment / releasing for the dependency the artifact uses.

Promoting semantically versioned artifacts when an upstream dependency has changed

I am in the midst of an initiative to convert our build.gradle files to use semantic versions. In addition to using Gradle, we also use Git and are following the Gitflow Workflow. Jenkins is used to build the projects.
Versions for released artifacts follow a MAJOR.MINOR.PATCH format. When declaring dependencies in the build.gradle file, we use dynamic versions, such as 10.0.+ (i.e. take the latest 10.0.PATCH version).
We promote our artifacts from a Release Candidates repository to a Releases repository in Nexus. The repository has its policy set to "Releases". Because of the complexity of the product (200+ projects, with many upstream and downstream dependencies), a lot of the promotion plugins available for Jenkins appear to fall short. We were thinking of having Jenkins build the master branch as a way to rename artifacts (10.0.0-rc.1-abcdefg becomes 10.0.0) and upload them to the correct Nexus repository.
I am unsure of how to handle a situation where an upstream dependency has a patch version incremented. The downstream project - a WAR - is re-built by Jenkins and bundles the new JAR, but the version of the downstream project doesn't change. When an attempt is made to upload to Nexus, it fails because only one artifact can have the same version.
Here is an example:
The Releases Nexus repository has upstream-api versioned at 10.0.0, and downstream-project versioned at 10.0.0
downstream-project depends on 10.0.+ of upstream-api
upstream-api.jar is bundled into the downstream-project.war file
The two artifacts are deployed as part of Release X of the product
When a hotfix branch has been merged into master, the upstream-api version has changed to 10.0.1
The fix means that when deployed, the product is now Release X'
downstream-project stays at 10.0.0, but is re-built because of the change in the upstream dependency
Jenkins fails to upload downstream-project-10.0.0.war to Nexus because it already exists
I could have the old artifact replaced with the new artifact, but then that means that Release X can no longer be deployed from artifacts in Nexus (eg. in the case of a rollback, or needing to replicate an issue on an older release).
How is this typically handled?
How is this typically handled?
I don’t have a universal answer here. I would assume that these are the most “common” possibilities:
Don’t distribute your dependencies with the release and continue to use dependency version declarations such as 10.0.+. The assumption is then that the software will indeed work with any 10.0.x version – at least as far as your users will tolerate it. That usually happens for free software which is distributed in source or in a package system of a Linux distribution. The dependency version declaration is only updated when there is a required improvement in the dependency, i.e., when the change is so important that your users won’t tolerate any earlier version.
Distribute your dependencies with the release and either:
Use a build number in addition to the main/semantic version number of the original code – for example 1.3.4-b3. If I’m not mistaken, then this is often being done for proprietary Windows software.
Increment the main/semantic version number when a dependency changes and make the dependency requirement explicit.
Some more General Thoughts on the Issue
I think the core issue is the dynamic dependency declaration – the 10.0.+ version declaration. What you state with this declaration is that your release will work equally well with any 10.0.x version.
If that is really the case, i.e., the bugs that are fixed by a patch in the dependency are guaranteed to never affect the release, then your release should probably simply not be rebuilt, since its functionality wouldn’t change anyway. The version of the dependency wouldn’t matter, your release could stay with the older dependency version.
More likely, though, the upstream bugfixes will also make a difference in your downstream project, i.e., they will affect the functionality of the release. In that case you should make the “new” dependency explicit in your build.gradle. Since that’s a change to your release artifact, a new release version is due.

Releasing the project with Maven: different release versions of artifacts

I have a maven project with multiple modules. When I release it I just change the versions of the modules from SNAPSHOT to release's version and its ok. This can be done with Maven Release Plugin.
The problem arises because some of the dependencies I have are actually the artifacts, developed by other groups of our programmers. Thus their versions may often change, which is a behaviour opposite to other dependencies, for example hibernate's artifact versions. At the moment of release I would like to use some available versions of that rapidly changing libraries. Probably the last one. May be they will release a new version of their library specially for my release.
Note that their library is a separate Maven project with separate version controlled by them.
All I can do now is just to check manually which version of the that dependency is the last and put it down manually into my POM. Its not that convenient. May be there is a better way to organize it with Maven and TeamCity? Can I update the versions of that other group's artifacts too? Their version should be derived from their Snapshot version, or from the last release they have deployed into the Nexus.
You can use versions-maven-plugin to automate updating external dependencies.
As mentioned, you can use Versions Maven Plugin, and more specifically you need versions:update-properties. As you can read the manual, it
Sets properties to the latest versions of specific artifacts.
The condition is that you work with repository manager (e.g. Artifactory). Maven knows to search this repo for the most updated aritfacts.
Before you run the maven-release-plugin, you run the versions-plugin that updates your dependencies. For example, you run versions:update-properties with the relevant parameters.
If you would like to print latest versions of artifacts, the same versions-plugin is your friend. Have a look and read the link I've sent you above; the relevant command is versions:display-dependency-updates.
If you would like to print selectively, only your artifacts latest versions, you can set their version using a property. for example, if you have dependency JAR X, write in the main pom something like this:
<dependency>
<groupId>myGroup</groupId>
<artifactId>X</artifactId>
<version>${x.version}</version>
</dependency>
<properties>
<x.version>3.1.0.RELEASE</x.version>
</properties>
Then you use versions:display-property-updates -DincludeProperties="x.version"

Maven branch update projects version automating release workflow

I have a difficult case to solve regarding the Maven automated projects versioning, I hope I'll find a proper solution based on your experience and advices.
The problem is like that:
We have a huge mavenized java product which comprise of ~200 very interdependent different projects.
We agreed that each project should be developed independently, so that each of them should have it's own lifecycle.
It's all working fine in the development stage, there is no problem. The problem comes when we are preparing the release for these projects: Because the are so many projects the manual changes are a pain so we decided to find an automated solution to solve the release process.
The prequisites are these:
We all agreed that the release policy from SVN perspective should be like that:
- all development should be performed on SVN trunk, releases should be created and maintained on branches. Each performed release should automatically create a tag.
The policy from MAVEN perspective is like that:
- before releasing a project, we first copy the trunk to a branch in order to have control over projects maintainance on the branched code. The versioning system we choose is: Major.Minor.BuildNumber-SNAPSHOT (e.g. 1.0.0-SNAPSHOT). When branching the code, we want to change the project version number by incrementing the MinorVersion (e.g trunk-1.0.0-SNAPSHOT will become 1.1.0-SNAPSHOT, and 1.0.0-SNAPSHOT will be copied and released on the new created branch)
- when we decide that the project is mature enough in order to be released we are releasing it by using maven-release-plugin (mvn release:clean release:prepare release:perform) so that our project version will be transformed from Major.Minor.BuildVersion-SNAPSHOT (e.g. 1.0.0-SNAPSHOT) to Major.Minor.BuildVersion (e.g. 1.0.0), then will be prepared for the next development iteration like: Major.Minor.BuildVersion+1-SNAPSHOT (e.g. 1.0.1-SNAPSHOT)
The problems we are facing are related to projects versioning.
So, during the development phase on the trunk, all the projects are using the latest SNAPSHOT versions of their dependencies (mvn versions:use-latest-versions -DallowSnapshots=true -DupdateDependencies=true), but when we consider it's time to start the release procedure and prepare to branch the code, there problems start:
we are start branching
parent-pom
(mvn -B release:clean release:branch -DbranchName=${project.artifactId}_${project.version} -Dusername=${username} -Dpassword=${passwd} -Dproject.rel.${groupId}:${projectId}=1.0.0-SNAPSHOT
-Dproject.dev.${groupId}:${projectId}=1.1.0-SNAPSHOT)
copy project from trunk to new created branch, transform pom version on trunk from 1.0.0-SNAPSHOT to 1.1.0-SNAPSHOT
non-dependent projects
(mvn -B release:clean release:branch -DbranchName=${project.artifactId}_${project.version} -Dusername=${username} -Dpassword=${passwd} -Dproject.rel.${groupId}:${projectId}=1.0.0-SNAPSHOT
-Dproject.dev.${groupId}:${projectId}=1.1.0-SNAPSHOT versions:update-parent
-DallowSnapshots=true)
copy project from trunk to new created branch,
transform the trunk pom version 1.0.0-SNAPSHOT become 1.0.1-SNAPSHOT
update parent-pom.version: 1.0.0-SNAPSHOT become 1.1.0-SNAPSHOT
dependent projects:
(mvn -B release:clean release:branch -DbranchName=${project.artifactId}_${project.version} -Dusername=${username} -Dpassword=${passwd} -Dproject.rel.${groupId}:${projectId}=1.0.0-SNAPSHOT
-Dproject.dev.${groupId}:${projectId}=1.1.0-SNAPSHOT versions:update-parent
-DallowSnapshots=true versions:use-latest-versions -DallowSnapshots=true
-DupdateDependencies=true)
copy project from trunk to new created branch
transform pom version on trunk from 1.0.0-SNAPSHOT to 1.1.0-SNAPSHOT
update parent-pom on trunk from 1.0.0-SNAPSHOT to 1.1.0-SNAPSHOT
update the already branched dependency projects from 1.0.0-SNAPSHOT to 1.1.0-SNAPSHOT
The first problem here is that there is no way yet to have an argument to increase the MinorVersion when branch the project, the maven-release-plugin 2.2.2 does not increment the pom MinorVersion on trunk when branching, so that's why we need to use -Dproject.rel.${groupId}:${projectId}=1.0.0-SNAPSHOT
-Dproject.dev.${groupId}:${projectId}=1.1.0-SNAPSHOT arguments and change them manually for every project, so 200 times every time when we preapare for a new release.
I'm wondering if it's not a way to make all described procedure somehow in an automated fashion and to not need to perform all these changes manually all the time.
We've taking account even to modularize this product so that to colapse those 200 project in 100 probably, but this is not acceptable since the idea is to have a fine grained projects versioning and have all the projects with it's own lifecycle, so an aggregator (I mean a classic one) is out of discussion here.
We are using SVN as VCS, Maven as build tool (probably you already figured out about that :) ), and Bamboo as a CI server (actually, instead of "Maven Dependency Processor" feature, Bamboo is not helping me to much regarding the versioning problem).
Do you guys have any idea in order to find a proper solution for this problem, maybe another plugin which would help (versions-maven-plugin does not change versions automatically when branch), maybe another point of view for this, I don't know..., any help or sugestion are welcome.
Thanks!
I try to avoid keeping internal projects versions in the <properties> section of the parent-pom, since every time when I release a project, the <version>${project.version}</version> variable will be switched with the explicit version of the project like:
<properties>
<project_A.version>1.0.0-SNAPSHOT</projectA.version>
</properties>
stored in parent pom, translated in the projects pom like: ${project.version}, will become 1.0.1-SNAPSHOT when release that project, and will overwrite the <project_A.version> version from parent-pom <properties>. So this trick of keeping the projects versions as properties in a centralized location like the parent-pom, is valid as long as you don't release the projects.
This is the question strictly related to the branching question.
Now, if you want I can tell you more about releasing the projects using this <properties> substitution:
Lets's say you want to release your project_A, what will you do with the <projectA.version> stored in the parent pom <properties> which is a -SNAPSHOT version when you start to release the parent pom, right? I mean, in order to release a project, you'll release all its dependencies and its related parent-pom first right? otherwise your project release will fail since is pointing to a -SNAPSHOT version of the parent pom.
Now, you are releasing the parent-pom keeping the -SNAPSHOT version of project_A inside of it's <properties>, next when you'll release the project_A, your project will refer to the new created release version of your parent pom, which parent pom released version is refering to the -SNAPSHOT version of your project_A, still not a problem since your parent pom is keeping the true version of your project_A, until your projectA released version (lets say 1.0.0) will refer to the same parent pom released version which is containing 1.0.0-SNAPSHOT version of your project_A, and now you have a problem already because your parent pom <properties> is keeping a wrong info.
Ofcourse you can hack the parent pom when release it and store the release version of project_A, but this against the rules and I would not agree with that at all, plus that are other scenarios when this "hack" will cause more problems than help.
I'm sorry if this sounds pretty complicated and detailed but I just want to explain as much as possible the real life situation not just theoretical, plus that I also need to keep in mind that I have 200+ projects I need to keep somehow aligned.

Resources