Managing your project version with gradle

In a previous post I explained how we versioned our project poms.

After giving up on dinamically setting the version with maven, I decided to bite the bullet and try to switch a relatively small project to gradle as a proof of concept.

Most of the conversions from maven to gradle were quite straightforward. I had a small bump with izpack, but it all worked out after a couple hours of internet searching.

The interesting part lies with the dynamic calculation of the project version’s based on the state of the git repository.

In our build.gradle we can define the version for the main project and its subprojects with a call to a function:

allprojects{
   version = calculateVersion()
}

In this function we make use of git describe to calculate our version:

//major and minor are mandatory
def evalVersion (strVer) {
   def(v1, v2, v3) = strVer.tokenize('.')
   v1 = v1 ?: 0
   v2 = v2 ?: 0
   return [v1, v2, v3]
}

def calculateVersion() {

        def longVersionName = "git -C ${rootDir} describe --tags --long".execute().text.trim()
        logger.info("longVersionName = $longVersionName")
        def longVersionNameT = longVersionName.tokenize('-')
        def fullVersionTag, milestone, versionBuild, gitSha
        if (longVersionNameT.size() > 3) {
           (fullVersionTag, milestone, versionBuild, gitSha) = longVersionName.tokenize('-')
        } else {
           (fullVersionTag, versionBuild, gitSha) = longVersionName.tokenize('-')
        }

        def(versionMajor, versionMinor, versionPatch) = evalVersion(fullVersionTag)

        def branch = "git -C ${rootDir} symbolic-ref --short -q HEAD".execute().text.trim()

        //if there is no tag...
        if ((versionBuild != "0") && (branch != 'master')) versionMinor = versionMinor.toInteger() +1

        def versionPatchStr = versionPatch ? "." + versionPatch : ""
        def versionBuildStr = (versionBuild == "0") ? "" : "-g"+versionBuild

        def versionName =""

        // ok for develop, feature and master
        versionName = "$versionMajor.${versionMinor}${versionPatchStr}${versionBuildStr}"

        def fbmatch = branch =~ /feature\/(.+)/
        if (fbmatch) {
            def lista = fbmatch[0][1].tokenize('-')
            versionName += "-FB_" +lista[0] + "-" + lista[1]
        }

        if (branch != 'master') {
            versionName += "-SNAPSHOT"
        }

        def rbmatch = branch =~ /release\/(.+)/
        if (rbmatch) {
            (versionMajor, versionMinor, versionPatch) = evalVersion(rbmatch[0][1])
            versionPatchStr = versionPatch ? "." + versionPatch : ""
            versionName = "$versionMajor.${versionMinor}${versionPatchStr}-RC${versionBuild}"
        }

        def hbmatch = branch =~ /hotfix\/(.+)/
        if (hbmatch) {
            (versionMajor, versionMinor, versionPatch) = evalVersion(hbmatch[0][1])
            versionPatchStr = versionPatch ? "." + versionPatch : "";
            versionName = "$versionMajor.${versionMinor}${versionPatchStr}-HF${versionBuild}"
        }

        return versionName
}

The idea behind this function is to calculate dynamically the version, based on which git branch we’re on and what’s in the closest git tag to our current commit:

  • The previous git tag should be in the format: tagMajor.tagMinor[.tagPatch]
  • “-gG”: from git describe, G is the number of commits until the last tag. If G=0, it will not be part of the version name.
  • develop branch: tagMajor.tagMinor+1[.tagPatch][-gG]-SNAPSHOT -> 1.1.0-SNAPSHOT or 1.1.0-g8-SNAPSHOT
  • feature/XXXX-N-… branch: tagMajor.tagMinor+1[.tagPatch][-gG]-FB_XXXX-N-SNAPSHOT -> 1.1-g2-FB_KESL-2-SNAPSHOT
  • release/x.y.z branch: x.y.z-RC[G]
  • hotfix/x.y.z branch: x.y.z-HF[G]
  • master branch: tagMajor.tagMinor[.tagPatch][-gG]

As you can see, you can complicate the version calculation as much as you want. This is only an example I used a couple years back.

I’ve seen recently a reference to nebula-release-plugin, and I’d like to try it out in order to remove my custom version calculation. I will post about my experience with it soon.

One thought on “Managing your project version with gradle

Leave a comment