When I maven deploy a snapshot build such as myproject-1.0-SNAPSHOT maven will helpfully tag the snapshot with the date and the build number - something like myproject-1.0-20160720.182254-6.jar. Is there any way I can control the format of this unique tag?
In particular I'm trying to solve two problems:
I want to know the exact artifact that I just uploaded so that I can pull it into a docker image. There are potentially several builds in parallel for different developers so I need to get the exact version.
I want to tie the snapshot unique ID to the checkin id in git.
Use a concrete version number in the pom, this way you will have predictable builds that you can reuse later on.
And use e.g.:
mvn org.codehaus.mojo:versions-maven-plugin:2.1:set -DnewVersion=1.1 -DgenerateBackupPoms=false
to set the version and do a mvn clean deploy afterwards, this way you will know what version you can use in docker.
Related
I'm trying to learn more about how big project builds are being versioned by developer teams using maven. For example, some projects have versions like: 2.0.0-SNAPSHOT-g57517b7, what that "g57517b7" represents exactly? and is it possible to automate versioning process that increments those number or some kind of build number on maven?
The last part of the version name looks like a current git commit id.
Have a look here Include git commit hash in jar version
I need to ask Nexus 2.x the question:
"What is the latest version of the artifact with the following groupId and artifactId?"
The information is needed in a Windows batch file.
I scanned the usual Maven plugins if there is something like mvn versions:latest-version which is usable outside a Maven project but did not find anything.
My best bet would be to write a Java program that questions the rest interface of Nexus for available artifacts and extracts the desired information from the XML. This would be suboptimal because I need to write, maintain and use another program outside the batch file. Furthermore, an mvn command would be repository independent (Nexus 2.x will not be around forever).
Any ideas?
In our project, we have multiple branches for our main features. As we develop, we want our repository to contain snapshots of the APIs in each branch, so that if a branch depends on another, it can easily get its APIs from the repository. However, we want it to hold multiple snapshot versions, so that if one snapshot breaks something, they can refer to an older snapshot. Our potential naming scheme goes like this
example-1.0-SNAPSHOT-01.jar
example-1.0-SNAPSHOT-02.jar
etc...
Most POM files will use LATEST for the version reference of these snapshot jars.
Anyways, my question is, how exactly does maven determine the LATEST version? Does it go off just the version number (which I think would just be 1.0 for both SNAPSHOT-01 and SNAPSHOT-02) or does it also incorporate a time-stamp?
repository management system (for example nexus) manages snapshots the latest is named as -SNAPSHOT.jar generally and rest of them have timestamp in the file name
I have a web application where we deploy to production whenever a feature is ready, sometimes that can be a couple of times a day, sometimes it can be a couple of weeks between releases.
Currently, we don't increment our version numbers for our project, and everything has been sitting at version 0.0.1-SNAPSHOT for well over a year.
I am wondering what is the Maven way for doing continuous delivery for a web apps. It seems overkill to bump up the version number on every commit, and never bumping the version number like we are doing now, also seems wrong.
What is the recommend best practice for this type of Maven usage?
The problem is actually a two-fold one:
Advancing project version number in individual pom.xml file (and there can be many).
Updating version number in all dependent components to use latest ones of each other.
I recommend the following presentation that discusses the practical realities of doing continuous delivery with Maven:
You tube presentation on CD with Maven
Slides
The key takeaway is each build is a potential release, so don't use snapshots.
This is my summary based on the video linked by Mark O'Connor's answer.
The solution requires a DVCS like git and a CI server like Jenkins.
Don't use snapshot builds in the Continuous Delivery pipeline and don't use the maven release plugin.
Snapshot versions such as 1.0-SNAPSHOT are turned into real versions such as 1.0.buildNumber where the buildNumber is the Jenkins job number.
Algorithm steps:
Jenkins clones the git repo with the source code, and say the source code has version 1.0-SNAPSHOT
Jenkins creates a git branch called 1.0.JENKINS-JOB-NUMBER so the snapshot version is turned into a real version 1.0.124
Jenkins invokes the maven versions plugin to change the version number in the pom.xml files from 1.0-SNAPSHOT to 1.0.JENKINS-JOB-NUMBER
Jenkins invokes mvn install
If the mvn install is a success then Jenkins will commit the branch 1.0.JENKINS-JOB-NUMBER and a real non-snapshot version is created with a proper tag in git to reproduce later. If the mvn install fails then Jenkins will just delete the newly created branch and fail the build.
I highly recommend the video linked from Mark's answer.
Starting from Maven 3.2.1 continuous delivery friendly versions are supported out of the box : https://issues.apache.org/jira/browse/MNG-5576
You can use 3 predefined variables in version:
${changelist}
${revision}
${sha1}
So what you basically do is :
Set your version to e.g. 1.0.0-${revision}. (You can use mvn versions:set to do it quickly and correctly in multi-module project.)
Put a property <revision>SNAPSHOT</revision> for local development.
In your CI environment run mvn clean install -Drevision=${BUILD_NUMBER} or something like this or even mvn clean verify -Drevision=${BUILD_NUMBER}.
You can use for example https://wiki.jenkins-ci.org/display/JENKINS/Version+Number+Plugin to generate interesting build numbers.
Once you find out that the build is stable (e.g. pass acceptance tests) you can push the version to Nexus or other repository. Any unstable builds just go to trash.
There are some great discussions and proposals how to deal with the maven version number and continuous delivery (CD) (I will add them after my part of the answer).
So first my opinion on SNAPSHOT versions. In maven a SNAPSHOT shows that this is currently under development to the specific version before the SNAPSHOT suffix. Because of this, tools like Nexus or the maven-release-plugin has a special treatment for SNAPSHOTS. For Nexus they are stored in a separate repository and its allowed to update multiple artefacts with the same SNAPSHOT release version. So a SNAPSHOT can change without you knowing about it (because you never increment any number in your pom). Because of this I do not recommend to use SNAPSHOT dependencies in a project especially in a CD world since the build is not reliable any more.
SNAPSHOT as project version would be a problem when your project is used by other ones, because of the above reasons.
An other problem of SNAPSHOT for me is that is not really traceable or reproducibly any more. When I see a version 0.0.1-SNAPSHOT in production I need to do some searching to find out when it was build from which revision it was build. When I find a releases of this software on a filesystem I need to have a look at the pom.properties or MANIFEST file to see if this is old garbage or maybe the latest and greatest version.
To avoid the manual change of the version number (especially when you build multiple builds a day) let the Build Server change the number for you. So for development I would go with a
<major>.<minor>-SNAPSHOT
version but when building a new release the Build Server could replace the SNAPSHOT with something more unique and traceable.
For example one of this:
<major>.<minor>-b<buildNumber>
<major>.<minor>-r<scmNumber>
So the major and minor number can be used for marketing issues or to just show that a new great milestone is reached and can be changed manually when ever you want it. And the buildNumber (number from your Continuous Integration server) or the scmNumber (Revision of SUbversion or GIT) make each release unique and traceable. When using the buildNumber or Subversion revision the project versions are even sortable (not with GIT numbers). With the buildNumber or the scmNumber is also kinda easy to see what changes are in this release.
An other example is the versioning of stackoverflow which use
<year>.<month>.<day>.<buildNumber>
And here the missing links:
Versioning in a Pipeline
Continuous Delivery and Maven
DON'T DO THIS!
<Major>.<minor>-<build>
will bite you in the backside because Maven treats anything after a hyphen as LEXICAL. This means version 1 will be lexically higher than 10.
This is bad as if you're asking for the latest version of something in maven, then the above point wins.
The solution is to use a decimal point instead of a hyphen preceding the build number.
DO THIS!
<Major>.<minor>.<build>
It's okay to have SNAPSHOT versions locally, but as part of a build, it's better to use
mvn versions:set -DnewVersion=${major}.${minor}.${build.number}
There are ways to derive the major/minor version from the pom, eg using help:evaluate and pipe to a environment variable before invoking versions:set. This is dirty, but I really scratched my head (and others in my team) to make it simpler, and (at the time) Maven wasn't mature enough to handle this. I believe Maven 2.3.1 might have something that go some way in helping this, so this info may no longer be relevant.
It's okay for a bunch of developers to release on the same major.minor version - but it's always good to be mindful that minor changes are non-breaking and major version changes have some breaking API change, or deprecation of functionality/behaviour.
From a Continuous Delivery perspective every build is potentially releasable, therefore every check-in should create a build.
At my work for web apps we currently use this versioning pattern:
<jenkins build num>-<git-short-hash>
Example: 247-262e37b9.
This is nice because it it gives you a version that is always unique and traceable back to the jenkins build and git revision that produced it.
In Maven 3.2.1+ they finally killed the warnings for using a ${property} as a version so that makes it really easy to build these. Simply change all your poms to use <version>${revision}</version> and build with -Drevision=whatever. The only issue with that is that in your released poms the version will stay at ${revision} in the actual pom file which can cause all sorts of weird issues. To solve this I wrote a simple maven plugin (https://github.com/jeffskj/cd-versions-maven-plugin) which does the variable replacement in the file.
As a starting point you may have a look at Maven: The Complete Reference. Project Versions.
Then there is a good post on versioning strategy.
My problem is that I have written a maven plugin to deploy the artifact to a user specified location. I'm now trying to write another maven plugin to use this deployed artifact, change some things and zip it again.
I want to write the second plugin such that i use the first plugin to get the information for where it was deployed.
I don't know how to access this information from the first plugin.
I would agree with #Barend that if you can afford to make changes before deploy, that could be best strategy.
If you cannot do that, you can follow strategy of a plugin like Maven Release plugin. Maven release plugin runs in two phases where second run needs output of the first run. They manage it by keeping temporary properties file in the project directory which carry the information like tag name, SNAPSHOT version name etc.
You could use the same approach with plugin. Just remember that your plugin will be sort of transactional, where it expects the other goal to have run before it can do its work.
It seems to me that the easiest workaround is to reverse the order in which the plugins run.
Have Plugin B run first, using the known location under target/ to modify the artifact and then run Plugin A, deploying the modified artifact to the configured location.
If that's no option, I suggest you simply duplicate the configuration value (so that both plugins are told about the new location in their <configuration> element). This keeps both plugins independent, which is what Maven assumes them to be.
A last option is to make make Plugin B parse the entire POM and extract the information from Plugin A's <configuration> element, but I really can't recommend this. If you go this way the two plugins are so closely intertwined that they're really just one plugin. This is poor design, violates the principle of least surprise and might cause nasty configuration problems down the line.