SBT including the version number in a program

12.3k views Asked by At

I want a program I'm building to be able to report its own version at runtime (e.g. scala myprog.jar --version). Traditionally in a maven project, I'd use resource filtering (pom.xml -> file.properties -> read value at runtime). I know there's sbt-filter-plugin to emulate this functionality, but I'm curious if there's a more standard / preferred / clever way of doing this in SBT.

tl;dr how can I read the version number defined in build.sbt at runtime?

4

There are 4 answers

7
yǝsʞǝla On BEST ANSWER

Update...

https://github.com/ritschwumm/xsbt-reflect (mentioned above) is Obsolete, but there is this cool SBT release tool that can automatically manage versions and more: https://github.com/sbt/sbt-release.

Alternatively, if you want a quick fix you can get version from manifest like this:

val version: String = getClass.getPackage.getImplementationVersion

This value will be equal to version setting in your project which you set either in build.sbt or Build.scala.

Another Update ...

Buildinfo SBT plugin can generate a class with version number based on build.sbt:

/** This object was generated by sbt-buildinfo. */
case object BuildInfo {
  /** The value is "helloworld". */
  val name: String = "helloworld"
  /** The value is "0.1-SNAPSHOT". */
  val version: String = "0.1-SNAPSHOT"
  /** The value is "2.10.3". */
  val scalaVersion: String = "2.10.3"
  /** The value is "0.13.2". */
  val sbtVersion: String = "0.13.2"
  override val toString: String = "name: %s, version: %s, scalaVersion: %s, sbtVersion: %s" format (name, version, scalaVersion, sbtVersion)
}

See the docs on how to enable it here: https://github.com/sbt/sbt-buildinfo/.

0
Michael Ekstrand On

Use the xsbt-reflect plugin. It will generate a source file that contains, among other things, the project version number.

1
Tvaroh On

In general, without any plugins, you can do something like this:

sourceGenerators in Compile += Def.task {
  val file = (sourceManaged in Compile).value / "foo" / "bar" / "BuildInfo.scala"

  IO.write(
    file,
    s"""package foo.bar
       |object BuildInfo {
       |  val Version = "${version.value}"
       |}""".stripMargin
  )

  Seq(file)
}.taskValue

And then do with foo.bar.BuildInfo.Version constant whatever you like.

Or more general:

def generateBuildInfo(packageName: String,
                      objectName: String = "BuildInfo"): Setting[_] =
  sourceGenerators in Compile += Def.task {
    val file =
      packageName
        .split('.')
        .foldLeft((sourceManaged in Compile).value)(_ / _) / s"$objectName.scala"

    IO.write(
      file,
      s"""package $packageName
         |object $objectName {
         |  val Version = "${version.value}"
         |}""".stripMargin
    )

    Seq(file)
  }.taskValue

Example:

settings(generateBuildInfo("foo.bar"))

You can even change this to pass object properties as a Map[String, String] and generate the object appropriately.

1
akauppi On

I ended up making the build system (I use a Makefile on top of sbt) prepare a src/main/resources/version.txt file for Scala to read.

In the Makefile:

$(RESOURCES_VERSION): build.sbt
    grep "^version := " $< | cut -f2 -d\" > $@

In Scala:

val version: String = {
  val src = Source.fromURL( getClass.getResource("/version.txt") )
  src.getLines.next   // just take the first line 
}

This works for me.

It's curious that such a needed feature (I would think) is not easily available in Scala. A very simple sbt plugin just for this would be welcome.