Versioning Docker images with Gradle and Git

In this blog post I’m going to show you how to configure Gradle to version Docker images using Git information. You can use similar approach for versioning different artifacts (jar, war, etc.). We will be using:

If you prefer reading code than text you can skip reading and go straight to GitHub:
https://github.com/rgrebski/gradle-git-docker-versioning

Gradle configuration

Most of the work needs to be done in build.gradle file:

Dependencies and plugins

Let’s define all the dependencies, plugins and their repositories (build.gradle):

buildscript {
ext {
springBootVersion = '2.0.0.M1'
}
repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
classpath "se.transmode.gradle:gradle-docker:1.2"
}
}
plugins {
id 'com.palantir.git-version' version '0.7.3'
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: "docker"
apply plugin: "com.palantir.git-version"
group "pl.stepwise"
version gitVersion()
sourceCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
maven { url "http://dl.bintray.com/dmahapatro/plugins" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
}

Versioning

I am using com.palantir.git-version plugin to get version info from git (the plugin uses git describe to determine version info), it must be defined in plugins block (incubating!) and it adds gitVersion() and versionDetails() methods to the build script. You can use gitVersion() to obtain app version, or you can create your own method if you want something more sophisticated. You can use versionDetails() which provides you all the git information needed to generate version, here is a simple gradle task that prints version details:

task showVersion {
doLast {
println "\nCurrent version: ${gitVersion()}\n"
        def details = versionDetails()
println "last tag : ${details.lastTag}"
println "commit distance : ${details.commitDistance}"
println "hash : ${details.gitHash}"
println "branch name : ${details.branchName}"
println "is clean tag : ${details.isCleanTag}"
}
}

Seting version to static files (using ReplaceTokens)

In my sample application I’m having application.properties file with following content:

application.version=@appVersion@

@appVersion@ is going to be replaced by Gradle during processResources phase, all you need is to add following code to your build.gradle:

processResources {
filter(ReplaceTokens, tokens:[appVersion: gitVersion()])
}

Having that you can easily read the version from properties in Spring and expose it in Spring Boot Actuator info resource.
To read current version in Spring you can use @ConfigurationProperties:

@Configuration
@ConfigurationProperties(prefix = "application")
public class VersionConfig {
    @NotNull
private String version;
    //getter and setter here
}

And now you can append application version to /application/info (notice that Spring Boot 2 uses /application to group actuator resources) using InfoContributor:

@Bean
public InfoContributor versionInfoContributor(VersionConfig versionConfig) {
return builder -> {
builder.withDetail("version", versionConfig.getVersion());
};
}

Building Docker image

I am using Gradle-Docker plugin to build Docker image, it allows you to define “Dockerfile” in Gradle (or mix Dockerfile with Gradle groovy code):

task buildDocker(type: Docker, dependsOn: build) {
push = project.findProperty(‘push’)?.toBoolean() ?: false
    baseImage "java:8"
maintainer 'Radek Grebski <radoslaw.grebski@stepwise.pl>'
applicationName = jar.baseName
tagVersion = gitVersion()
tag = "rgrebski/gradle-git-docker-versioning"
addFile(jar.archivePath, 'app.jar')
runCommand("sh -c 'touch /app.jar'")
exposePort(8080)
entryPoint([ "sh", "-c", 'java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar' ])
    doFirst {
copy {
from jar
into stageDir
}
}
}

Now you can run either docker image or VersionApplication from your IDE and go to:
http://localhost:8080/application/info (notice that Spring Boot 2 uses /application to group actuator endpoints)

You should see something like:

{
"version": "v.0.1.0-1-g1e46e49"
}

Version v.0.1.0–1-g1e46e49 means:
v.0.1.0 -> last tag
1 -> number of commits since the last tag
g1e46e49 -> hash of the last commit

If we moved back to the commit tagged with ‘v.0.1.0’ the generated version would be ‘v.0.1.0’