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)
}
Post comment as twitter logo facebook logo
Sort: Newest | Oldest
eishay 5 pts

We do it in the settings method. Look for "override def settings = ..."

 

The RSS feed is http://eng.42go.com/feed/

markwaddle 5 pts

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!

Nice post. I've did something related to continuous deployments and module versions for apps using play 1.2.4. You can find it here: http://yodayouseek.blogspot.ro/2012/02/continuous-integration-ci-with-jenkins.html.