Version Aware Play Framework Application

Since we’re operating in continuous deployment mode, it’s important to us to know the current application version and to link it with its code snapshot. This helps us to pinpoint problems, bad versions, and compatibility issues and to keep track of server-side analytics events. On our internal admin tools, we can then introspect our server and quickly understand what version we are at and when we compiled and pushed that version.

To do that, we have our application distribution (zip) file tagged with the build time, git branch and commit hash. We also persist that information inside the distribution package using the code below, which we added to Play’s Build.scala:

import org.joda.time.{DateTime, DateTimeZone, LocalDate, LocalTime}
import org.joda.time.format.DateTimeFormat
...
val BUILD_DATETIME_FORMAT = DateTimeFormat.forPattern("yyyyMMdd-HHmm")
  .withLocale(Locale.ENGLISH)
  .withZone(DateTimeZone.forID("America/Los_Angeles"))
val buildTime = BUILD_DATETIME_FORMAT.print(new DateTime(DateTimeZone.forID("America/Los_Angeles")))
val appVersion = "%s-%s-%s".format(buildTime,
  "git rev-parse --abbrev-ref HEAD".!!.trim, "git rev-parse --short HEAD".!!.trim)
val PT = DateTimeZone.forID("America/Los_Angeles")
val now = DateTimeFormat.forPattern("E, dd MMM yyyy HH:mm:ss Z")
  .withLocale(Locale.ENGLISH).withZone(PT).print(new DateTime(PT))
 
def writeToFile(fileName: String, value: String) = {
  val file = new PrintWriter(new File(fileName))
  try { file.print(value) } finally { file.close() }
}
 
writeToFile("conf/app_version.txt", appVersion)
writeToFile("conf/app_compilation_date.txt", now)

And this simple application runtime code reads it:

lazy val currentVersion: ServiceVersion = current.mode match {
  case Mode.Test = ServiceVersion("Test mode service")
  case _ = ServiceVersion(io.Source.fromURL(Play.resource("app_version.txt").get).mkString)
}
 
lazy val compilationTime: DateTime = current.mode match {
  case Mode.Test = currentDateTime
  case _ =
    val timeStr = io.Source.fromURL(Play.resource("app_compilation_date.txt").get).mkString
    DateTimeFormat.forPattern("E, dd MMM yyyy HH:mm:ss Z")
        .withLocale(Locale.ENGLISH)
        .withZone(zones.PT).parseDateTime(timeStr)
}

We wrote this post while working on Kifi — tools that help people outsmart information overload together. Learn more.

4 comments
markwaddle
markwaddle

I am new to Scala and SBT. Can you elaborate a bit on where you placed the code in the Build.scala file so that is executed at build time? Thanks!