Scalaで書いたWebアプリケーションのレスポンスにデプロイされているGitコミットのSHA1を含める

WebアプリケーションのレスポンスヘッダにGitのsha1を含めておくと、デプロイに失敗していて古いバージョンだった (そのせいでおかしかった) ということに気がつきやすくなって多少便利。

Perl (PSGI) だと、 `git rev-parse HEAD > VERSION` などしておいて Plack::Middleware でファイルの内容を読んで `Plack::Util::header_set` と `Plack::Util::response_cb` で用が済むけれど、Scalaコンパイル時にいろいろできそうな気がしたので調べた。

sbt-buildinfoでビルド情報をcase objectに出力する

sbt-buildinfoというsbtプラグインを使うとプロジェクト名やバージョンなどの情報を含むcase objectのコードを生成してくれる。

Usageより:

lazy val root = (project in file(".")).
  enablePlugins(BuildInfoPlugin).
  settings(
    buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion),
    buildInfoPackage := "hello"
  )
GitHub - sbt/sbt-buildinfo: I know this because build.sbt knows this.

`build.sbt` にこう書いておくと `hello.BuildInfo` に `name` や `version` が埋められたcase objectを定義するコードが出力される。

sbt-gitでGitのコミット情報をプロジェクトのバージョン文字列にする

sbt-gitというsbtプラグインを使うとプロジェクトのバージョン文字列をGitのコミット情報から生成することができる。

`git describe` を使うようにするとか、自分でsha1を加工する (e.g. 先頭8文字だけを使う) ことができるので使い勝手がよい。

タグは使っていないのでsha1の先頭8文字を埋めるようにしている。

lazy val root = (project in file(".")).
  enablePlugins(GitVersioning).
  settings(
    git.formattedShaVersion := git.gitHeadCommit.value map { sha =>
      sha.substring(0, 8)
    }
  )

Playのレスポンスを加工してバージョンを含める

Action.async { implicit request =>
  val result = ???
  result.withHeaders("x-version" -> app.BuildInfo.version)
}

こういうかんじ。