2

What are the strategies to embed a unique version number in a Spring application?

I've got an app using Spring Boot and Spring Web.

Its matured enough that I want to version it and see it displayed on screen at run time.

Mark Juszczec
  • 85
  • 1
  • 2
  • 7
  • What sort of version number do you want to include? Git commit hash? Git tag? Maven project version? Gradle project version? Something else? – Andy Wilkinson Jan 13 '16 at 21:54
  • any number that will uniquely identify this app as having been built from this pile of source. its an svn archive so the svn revision would be fine – Mark Juszczec Jan 13 '16 at 22:45

3 Answers3

5

I believe what you are looking for is generating this version number during build time (Usually by build tools like Ant, Maven or Gradle) as part of their build task chain.

I believe a quite common approach is to either put the version number into the Manifest.mf of the produced JAR and then read it, or create a file that is part of the produced JAR that can be read by your application.

Another solution would be just using Spring Boot's banner customization options described here: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-banner However, this will only allow you to change spring-boot banner.

I also believe that Spring Boot exposes product version that is set in Manifest.MF of your application. To achieve this you will need to make sure Implementation-Version attribute of the manifest is set.

Custom solution for access anywhere in the code

Lets assume you would like to have a version.properties file in your src/main/resources that contains your version information. It will contain placeholders instead of actual values so that these placeholders can be expanded during build time.

version=${prodVersion}
build=${prodBuild}
timestamp=${buildTimestamp}

Now that you have a file like this you need to fill it with actual data. I use Gradle so there I would make sure that processResources task which is automatically running for builds is expanding resources. Something like this should do the trick in the build.gradle file for Git-based code:

import org.codehaus.groovy.runtime.*
import org.eclipse.jgit.api.*

def getGitBranchCommit() {
    try {
        def git = Git.open(project.file(project.getRootProject().getProjectDir()));
        def repo = git.getRepository();
        def id = repo.resolve(repo.getFullBranch());
        return id.abbreviate(7).name()
    } catch (IOException ex) {
       return "UNKNOWN"
    }

}

processResources {
    filesMatching("**/version.properties") {
        expand (
            "prodVersion": version,
            "prodBuild": getGitBranchCommit(),
            "buildTimestamp": DateGroovyMethods.format(new Date(), 'yyyy-MM-dd HH:mm') 
        )
    }
}

processResources.outputs.upToDateWhen{ false }

In the code about the following is happening:

  1. We defined a function that can take a build number out of the VCS (in this case Git). The commit hash is limited to 7 characters.
  2. We configure the processResources task to process version.properties file and fill it with our variables. prodVersion is taken from Gradle project version. It's usually set as version in gradle.properties file (part of the general build setup).
  3. As a last step we ensure that it's always updated (Gradle has some mechanics to detect if files ened to be processed

Considering you are on SVN, you will need to have a getSvnBranchCommit() method instead. You could for instance use SVNKit or similar for this.

The last thing that is missing now is reading of the file for use in your application.

This could be achieved by simply reading a classpath resource and parsing it into java.util.Properties. You could take it one step further and for instance create accessor methods specifically for each field, e.g getVersion(), getBuild(), etc.

Hope this helps a bit (even though may not be 100% applicable straight off)

Alexej Kubarev
  • 853
  • 8
  • 14
3

Maven can be used to track the version number, e.g.:

<!-- pom.xml -->
<version>2.0.3</version>

Spring Boot can refer to the version, and expose it via REST using Actuator:

# application.properties
endpoints.info.enabled=true
info.app.version=@project.version@

Then use Ajax to render the version in the browser, for example using Polymer iron-ajax:

<!-- about-page.html -->
<iron-ajax auto url="/info" last-response="{{info}}"></iron-ajax>
Application version is: [[info.app.version]]

This will then show in the browser as:

Application version is: 2.0.3
AlexO
  • 1,311
  • 12
  • 18
  • This answer took me in the right direction! I also needed this in my pom.xml: ` src/main/resources true ` – skel625 Apr 24 '20 at 07:13
1

I'm sure you've probably figured something out since this is an older question, but here's what I just did and it looks good. (Getting it into the banner requires you to duplicate a lot).

I'd recommend switching to git (it's a great SVN client too), and then using this in your build.gradle:

// https://github.com/n0mer/gradle-git-properties
plugins {
  id "com.gorylenko.gradle-git-properties" version "1.4.17"
}
// http://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
springBoot {
    buildInfo()  // create  META-INF/build-info.properties
}
bootRun.dependsOn = [assemble]

And this in your SpringBoot application:

@Resource
GitProperties props;

@Resource
BuildProperties props2;

Or this way to expose those properties into the standard spring environment:

@SpringBootApplication
@PropertySources({
    @PropertySource("classpath:git.properties"),
    @PropertySource("classpath:META-INF/build-info.properties")
})
public class MySpringBootApplication {

and then referencing the individual properties as needed.

@Value("${git.branch}")
String gitBranch;

@Value("${build.time}")
String buildTime;
Scott Carlson
  • 3,764
  • 1
  • 17
  • 11