Persisting property values in a POM on a release - maven

I have a Maven project that builds a plugin for a third-party system. The third party system requires version numbers to be in the format: YYYYMMDDNN where NN is a build number, and the date should correspond to the release date of the project. We'll call this the "external version". At build time, we use the maven.build.timestamp to set this value, and the maven-release-plugin to filter this value into our sources appropriately.
We also have an internal semantic versioning number scheme, which we use for the ${project.version}.
When we do a release, the maven-release-plugin appropriately transforms the project.version to remove SNAPSHOT, tags it in git, and so on. Is there a way to also "fix" the YYYYMMDDNN version in the at the same time, so that future builds of that release are identical?

You could use the release plugin's preparationGoals to edit the pom.xml locking down the property, and then use completionGoals to unlock it afterwards.
The changes you make in those goals will be committed, and in fact an aim of mine is to provide a goal on the versions maven plugin to lock down ranges and unlock them again for use in the above two steps so that version ranges become almost useable... Just avent had the time, but I did add the completion goals release phase.

Related

How to change POM version in CI build?

I'm probably approaching the problem all wrong, but here goes...
We want to implement a development -> releases/x.y.z -> master workflow using Gitlab and Nexus. The artifacts should be labelled x.y.z-SNAPSHOT, x.y.z-rc and x.y.z respectively.
In the ci-build.yml, I have tried to modify the POM depending on the current branch so as to create the correctly labelled artifacts. The problem is obviously that the change will be one commit ahead of the current build commit and the POM used in the build has the original version.
e.g.
a release branch is created from development
the POM has 2.3.4-SNAPSHOT and, during the ci-build, is modified to 2.3.4-rc and is committed and pushed to git
the subsequent build and deploy actions are executed but this deploys a 2.3.4-SNAPSHOT package to Nexus and not 2.3.4-rc as wanted
My question here is the following:
Can I modify the POM and use the updated POM in all following stages of the ci-build?
(I don't feel that this is the correct procedure, but it is what my team-leader has requested so I'm trying to implement it...)
My solution was to avoid commits altogether and use the strategy described in https://maven.apache.org/maven-ci-friendly.html.
This defines a new property, revision, which can be set using a maven parameter, -Drevision=x.y.z-SUFFIX. The POM version is set from this variable.
The build-ci reads project/properties/revision to extract the POM version and alters the version as appropriate depending on the current branch.
Using this approach I can achieve the required results without adding any extra commits as Maven can execute its goals using the version provided externally.

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.

Maven and snapshots?

I'm working on a rapid project, of which, I'm directly working on a module that is continuously changing. Others have a direct dependency on the module, and as such, I stubbed out the public interface and deployed it to our local Nexus repository as 0.0-SNAPSHOT for use.
Now that I've almost completed my first iteration of the module, I've attempted to redeploy the updated artifact. Reading about snapshots, others claim that a snapshot should represent the current head trunk. Is this true?
Maven automatically increments my snapshot version upon redeploy - so, going from 0.0-SNAPSHOT, I'm still at 0.0-SNAPSHOT, only, it's iteration 3 or 4 of the same snapshot. When should I roll over to 0.1-SNAPSHOT? Is there a plugin I can use to automate the version change, instead of manually editing my pom?
After integration testing and the deployment of our first system release, 1.0-RELEASE, how should my module progress? Should I move my module to 1.0-SNAPSHOT and continue thereon? Is there a methodology one should follow, or is it left to the discretion of the developer?
The X.Y.Z-SNAPSHOT notation identifies temporary versions leading up to release X.Y.Z, so you usually do not move from X.Y.Z-SNAPSHOT to X.Y.Z+1-SNAPSHOT unless you release X.Y.Z. If you adhere to this convention the maven-release-plugin may help you with the full release process.
Note that the most common Maven convention uses 3-number release identifiers without any suffix (i.e. no -RELEASE). Suffixes are usually used to distinguish variants of the same release.
Maven is all about conventions, so there's little chance you'll go very far without reading about it: This book is a good starting point.
For updating your POM version without manually updating, you may take a look at Maven Release plugin (Although I wrote myself a little script to do the POM update as I find Release plugin don't fit that good in my work flow)
It then come to your version number issue. It is more a release procedure issue. Normally a planned release is denoted by increment of Major or Minor version in the version number. SNAPSHOT version denote that certain release is in progress. For example, I will prefer doing something like this for your case:
Assume I am planning to release first iteration as 0.1, then I will make my head trunk in SCM (e.g. trunk in SVN) with 0.1-SNAPSHOT as version. Which denotes that all development is in fact contributing to release of version 0.1. Upon finish, I'll update the POM version from 0.1-SNAPSHOT to 0.1, perform an actual release of version 0.1 (including release branching, tagging, deploying the artifact), and then change the POM version to SNAPSHOT of next planned release (for example, 0.2-SNAPSHOT).
Similarly, after releasing 1.0 (or 1.0-RELEASE in your example), POM version in head trunk should then be updated to snapshot of your next release version, for example, 1.1-SNAPSHOT.
Just bear in mind that there should no longer be SNAPSHOTs of certain version, if that version is actually released.
Understand the way maven interprets SNAPSHOTS is to clear any doubt you can have.
Extract from http://books.sonatype.com/mvnref-book/reference/pom-relationships-sect-pom-syntax.html
For example, if your project has a version of “1.0-SNAPSHOT” and you deploy this project’s artifacts to a Maven repository, Maven would expand this version to “1.0-20080207-230803-1” if you were to deploy a release at 11:08 PM on February 7th, 2008 UTC
First, Let me suggest to stick on maven conventions and change your version to 0.1 as maven archetype:generate propose.
So SNAPSHOT helps others to stay up-to-date easily with your active project. On every compilation, their projects will check new releases of SNAPSHOTS dependencies (based on that pseudo-datetime-version they have on its .m2 directory).
When you finish work on 0.1-SNAPSHOT you deploy an 0.1 and start a 0.2-SNAPSHOT or 1.0-SNAPSHOT

Resources