Put build number into Grails WAR manifest blog home

Posted Thursday, 29-Mar-2012 by Ingo Karkat; updated 05-Dec-2014

For troubleshooting during development and testing, it is helpful to include the exact build number in one's web application. I use the BgInfo tool from the excellent Sysinternals Suite to embed the version information into the desktop background of my virtual machines, so that the version I'm working with is immediately visible after logging in, but that's not the topic of this post.

The problem is, though Maven automatically puts a buildNumber property into generated JAR and WAR files (and there are even pretty nice ways to get Maven to embed the working copy's version number, too), the grails-maven-plugin 1.3.4 blatantly ignores many Maven conventions, and this is no exception.

What I want is this line in META-INF/MANIFEST.MF:

Implementation-Title: MyWebapp
Implementation-Version: 1.00.100-SNAPSHOT
Implementation-Build: DEVHOST_r1337_15-Mar-2012_14:02

But apparently Grails so far only puts in the first two entries. Fortunately, after browsing the Grails sources and finding a relevant discussion, I was able to achieve this through the following snippet, which should be placed into scripts/_Events.groovy inside your web app's source tree.

eventCreateWarStart = { warName, stagingDir ->
    String buildNumber = System.getProperty('buildNumber')
    if (buildNumber)
    {
        String manifestFile = "$stagingDir/META-INF/MANIFEST.MF"

        ant.manifest(file: manifestFile, mode: "update") {
            section(name: "Grails Application") {
                attribute(name: "Implementation-Build", value: buildNumber)
            }
        }
    }
}

Unfortunately, you still cannot use stuff like the Maven Build Number plugin, because it sets the build number as a Maven property, which the embedded Grails build cannot access. The only setting that makes it across the Maven ↔ Grails divide is a Java System Property (because Maven and Grails share the same JVM). Therefore, you have to pass in the build number when invoking Maven through the command-line:

$ mvn -DbuildNumber=nnnn install

That's fine for me, since I have a Maven wrapper in place, anyway, and this one now creates a build number including the build host, Subversion revision number of the working copy, date and time through a little batch script svn-timestamp.cmd:

set revision=???
for /F "delims=" %%r in ('svn info --non-interactive %* 2^>NUL ^| sed -ne "s/^Revision: //p"') do set revision=%%r
echo.%COMPUTERNAME%_r%revision%_%DATE%_%TIME:~0,-6%

Ingo Karkat, 29-Mar-2012

Addendum

This unfortunately broke when upgrading from Grails 1.3.4 to 2.3.7. In Grails 2, the Grails Maven plugin forks a separate JVM to run Grails, and that unfortunately doesn't inherit the Java properties passed into the Maven one. The MAVEN-177 issue asks for automatic inheritance of those, but so far they've only introduced the possibility to manually specify JVM arguments via a <forkedVmArgs> tag in the Maven POM (example).

To fix our passing of the build number, add the following to your Grails projects' POMs:

  <build>
    <plugins>
      <plugin>
        <groupId>org.grails</groupId>
        <artifactId>grails-maven-plugin</artifactId>
        <configuration>
          <fork>true</fork>
          <forkedVmArgs>
            <forkedVmArg>-DbuildNumber=${buildNumber}</forkedVmArg>
          </forkedVmArgs>
        </configuration>
        ...

Ingo Karkat, 05-Dec-2014

ingo's blog is licensed under Attribution-ShareAlike 4.0 International

blog comments powered by Disqus