Maven the Version Number Nazi
Maven doesn’t like it when you use different verison numbers to the Maven standard format. Of course it doesn’t. It wouldn’t would it? It’s Maven, and Maven only likes it when you do what it tells you to do. I’m still a bit annoyed with Maven, as you can probably tell.
Don’t get me wrong, I’m not “Maven bashing”, it’s just that this particular problem doesn’t have quite the elegant solution I was looking for. I do appreciate Maven, honestly.
This was the problem:
I wanted to change our versioning system from something like 1.0.0-1234 to something like 1.0.0-1234-01
Why the hell would I want to do that?? I’ll explain…
Our verisoning is like this:
{major}.{minor}.{patch}-{build}
The only problem was, the build number was taken from the Perforce
check-in number, and this number didn’t always change whenever a build
was made, especially if the build was kicked off by an upstream
dependency, or a forced build was triggered. Basically, if the build was
kicked off by anything other than a commit to Perforce, the build would
create an artifact of identical version to the previous build. This, in
theory, shouldn’t be a problem, because it is actually building exactly
the same thing, but I just don’t like it. Anything could happen, any
environmental change could produce a slightly different build to the
previous one.
The problem was that I wasn’t using an incremental counter anywhere in my version numbe. It’s essential to have an incrementing version number in order to ensure that every single build creates a unique identifier, so that no two different builds can appear to be the same build.
My first thought was to append a build counter on the end, like this:
{major}.{minor}.{patch}-{build}-{counter}
And that would have worked fine, if it wasn’t for the fact that we
use version ranges in our dependencies, and we already have plenty of
builds which use the previous versioning system. Maven kept picking up
the builds with the previous version system, even though, in every
possible sense, the new ones had higher version numbers. It made no
sense. That’s when I looked into how maven works out versions. Basically
it says “if you’re using version ranges, and not using the maven
standard versioning format, you might as well forget it”. If it sees
dependencies using the standard format, and ones using the non-standard
maven format, it’ll pick up the standard format ones and basically
ignore the new ones. To get around this you can delete all the old
builds using the standard maven format, and then it’ll work, because
it’ll treat each build version like a string and just get you the latest
in whatever your range is.
Sadly, this isn’t an option for me, as I want to kep the old builds
using the old format. So I tried a few things. I tried putting a string
in as a separator, so it would look like this:
{major}.{minor}.{patch}-{build}rc{counter}
This effectively produces something looking like:
1.0.0-1234rc01
I’m fine with that. Maven, on the other hand, isn’t. I made a build with this version 1.0.0-9999rc01 and used it as a dependency in another build, but the other build still went and got 1.0.0-1234, the OLD build using the standard maven versioning. I mean, you’d think 1.0.0-9999rc01 > 1.0.0-1234 but apparently not.
I was a bit pushed for time so I couldn’t spend forever looking into this, so I’ve basically just appended the build counter directly onto the end of the perforce number. This works ok, but just looks a little ugly.
There’s more information on the Maven versioning rules here.
It seems that you can break the rules no problems, but you’re in
trouble if you use version ranges in your dependencies, and your
dependencies need to live alongside binaries which use the standard
maven versioning system
If anyone has any better solutions I’d like to hear them. And please don’t say “stop using Maven”.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Mladen Girazovski replied on Mon, 2012/05/07 - 7:00am
Let me put it this way: Stop abusing Maven version numbers ;)
Sounds to me like your build/deploy/release process is not really aligned to Maven yet.
Maven has its own versioning scheme, instead of trying to change Mavens way, change your own way :)
Have you had a look at this plugin?
http://mojo.codehaus.org/buildnumber-maven-plugin/
It should do what you want, except for naming the file the way you want, since it would break maven versioning scheme, instead you'll have the build number in your MetaData like MANIFEST etc. pp.
Jörg Buchberger replied on Mon, 2012/05/07 - 8:41am
Hi
if you need to change your version format ...
you might just as well also slightly change your group-ID.
Such a workaround would avoid the conflicts you outlined above.
Cheers
Jörg
Bruce Baron replied on Mon, 2012/05/07 - 12:15pm
Pieter Van Der Meer replied on Mon, 2012/05/07 - 2:13pm
James,
what wonders me is the following from your post:
How can this happen. What you are saying is that you have a non-reproduciable build. If so, why even bother with build numbers. The number has become meaning less. A defect found in build 4321 can not be reproduced, some environment change (which i dont know) introduced this defect...
Just use the standard maven snapshot numbering and you are at the same point.
(btw I endorse the solution with the build number plugin. In general I create a custom manifest including my SCM revision number, timestamp and info about who or what created the artifact).
Pieter
Loren Kratzke replied on Wed, 2012/05/09 - 11:52am
Basically, stop putting metadata (patch numbers and buildIds) in your version numbers. Use the manifest to hold that information and use some other system to report on it.
Furthermore, you pretty much need to do a Maven release with every build based upon your previous posts mentioning that you want every build to be a potential release. Just bite the bullet and release with every build. It is what you want to do anyway. Just do it.
The notion of every build being a potential release is unconventional at best. The Maven montra is convention over configuration.
Curtis Yanko replied on Tue, 2012/05/08 - 7:22am
Pietro Martinelli replied on Thu, 2012/05/10 - 7:28am
What about using a numbering schema like
{major}.{minor}.{patch}-{timestamp} ?
This schema complies with Maven standard schema but can differentiate different build of the same VCS snapshot, if you can pay the price of losing the reference to Perforce check-in number...