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”.

 

Advertisement

6 comments

  1. Royale · May 4, 2012

    We use continuum for our continous integration builds and there you can use continuum’s build number in that place.

  2. Anonymous · May 7, 2012

    Stop using maven

  3. svanespen · May 9, 2012

    It seems your real issue is using version ranges.

    A a rule of thumb, isn’t it better to specify clearly on which version you depend on ?
    This would give you so much more flexibility in your version number format (and you can still use properties & inheritance for easy version updates)

    A valid exception would be using ranges for dependencies of public frameworks in order to make the job of the dependency resolver easier.

    And, btw, Maven is brilliant !

    • jamesbetteley · May 9, 2012

      Yes, it’s much better to explicitly reference a particular version of a dependency, but unfortunately, at the time of the build happening, I don’t know the version number of the dependency. This is all because the builds are in a continuous delivery pipeline. Let’s say the build depends on the successful completion of another build (or even an earlier stage of the same pipeline). So when build A finishes, build B starts (and depends on build A). We need to somehow inject the version number that build A has produced, into the pom for build B. Since there’s no easy way of doing this, version ranges are the best bet.
      There are many workarounds, and I like the look if the versions-maven-plugin. If I get it to work for me, I’ll post something here.

      • svanespen · May 9, 2012

        Ok.

        If you’re using Hudson/Jenkins, I think a combination of free-style project and post-build actions ‘Trigger parametrized build on other projects’ could help.

        One or more steps of your job might use the version-maven-plugin. Values would come from job parameters.

        Good luck.

  4. kvmnupewb@gmail.com · January 21, 2014

    appreciate discussing!. “Nothing put in at home towards unwilling. ” by means of Nikki Giovanni..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s