Thursday, 19 December 2013

Conditional SBT Keys for Jenkins Builds

A little SBT snippet that's proven useful (place this in a file like jenkins-only.sbt alongside your build.sbt):
    // Settings which should only be applied if this SBT is being run by Jenkins

    // Jenkins nodes always have $JENKINS_URL set - that is our telltale:
    lazy val underJenkins:Option[String] = scala.util.Properties.envOrNone("JENKINS_URL")
    def ifUnderJenkins[T](setting: => T):Seq[T] = underJenkins.map ( s=> setting ).toSeq


    // Write a JUnit-format output especially for Jenkins:

    testOptions in Test ++= ifUnderJenkins ( Tests.Argument("junitxml") )

Why: Well in this case, it gives Jenkins the output he/it needs to do pretty "Test Result Trend" graphs and have clickable error messages when tests fail, while simultaneously giving developers the well-structured, detailed test output that SBT gives by default.
How: As mentioned in the code comments, and in the Jenkins documentation, a Jenkins node will have the JENKINS_URL environment variable set, and a dev (probably) won't.
Nice Features:
  • Exploits the fact that an Option[T] can be converted to a zero-or-one-length Seq[T] with toSeq()
  • Parameterized ifUnderJenkins so that any SBT key can be handled conditionally
  • By-name parameter (that's the setting: => T ) means the setting won't even be evaluated unless needed