For all artifacts we build on our projects (.war
files, packaged installers,
single .jar
archives, etc.) we always want to include precise and descriptive
information about the build: time stamps, version number, commit hash and
whether it’s a final/pre/internal release.
We include all build information inside the artifacts themselves for programmatic consumption (e.g. for showing the current build version at the bottom of a some web pages or “about” screens) and also for humans: to know exactly what build each artifact is in, for reporting and reproducing defects, for troubleshooting dependency issues and so forth. Even the naming of some artifacts (like, RPM packages) depend on build information.
Initial approach
We are using Maven for many of our projects. We started using the existing
buildnumber-maven-plugin
to extract build information from git; unfortunately, it does not provide all we
need. So, we later started cooking simple groovy scripts (via
gmaven-plugin)
which called git describe
and other git
commands to obtain the information
we wanted and set it as project properties.
This approach worked for awhile. However, the script started to get complicated and was not easy to reuse across projects.
Our current solution
With that in mind, I wrote buildversion-plugin: a simple Maven plugin that provides the functionality we need. It extracts build info from the current git branch, including timestamp, commit hash, tag name and number of commits since the last tag.
The problem with git-describe
We initially relied on calling git describe
to obtain a descriptive version
number, which includes the most recent tag and the number of commits since such
tag.
Unfortunately, the logic behind git describe
searches for the closest tag back
in history following all parent commits on merges. This means it may select
tags you originally put on another branch. So, if you are working on a
development branch and merge back a fix made on a release branch, calling git
describe
on the development branch may shield a description that includes a tag
you placed on the release branch.
Other people
run into the same problem. There’s
been a
discussion on GIT’s mailing list
about git describe
’s logic and the need for adding a --first-parent
option. And there’s even a
working patch to add --first-parent
.
Until git describe
accepts a --first-parent
argument, this plugin implements
its own logic, which basically leverages git log --first-parent
and traverses
the history on the current “line of development”, parsing the tag names and counting
the number of commits as it goes.
Don’t repeat yourself
One of the reasons why we started writing this plugin was to obtain the version
number from git in order to “inject” it into the Maven project. That is, we
wanted to stop having to maintain the version number inside the pom.xml
’s
given that the information was already managed by git. We couldn’t (yet?)
achieve this: apparently, Maven reads the version from the pom before invoking
the plugins; so, even after we set the version number most of Maven’s operations
continue using the version originally set in the pom.xml
.
Notes about the implementation
It’s a really simple plugin. However, I coded it in Clojure as an exercise and to prove its Java “interoperability”. Luckily, Hugo Duncan did all of the hard work already, so it was quite simple.
I hope the plugin is useful for others. If you try it, let us now if you find issues or have ideas to improve it.
Acknowledgment: thanks to José Rozanec who implemented the first prototype trying to inject the project version. He’s also the first one to seriously test the current buildversion-plugin.