Scala Stewardとは、依存ライブラリのバージョンアップ確認をして、セマンティックバージョニング的にバージョンアップが可能であればプルリクエスト/マージリクエストを作成してくれるサービスです。似たサービスにRenovateがありますが、Scala StewardはScalaに特化したバージョンアップ確認サービスです。
この記事では、Scala StewardをPlayFrameworkサービスに適用した際に追加した設定を紹介します。
背景:sbtによる依存ライブラリの解決について
sbt1.5から、依存ライブラリのバージョン範囲がより厳密になりました。全ての依存ライブラリが必要とするライブラリはメジャーバージョンが揃っている必要があります(例外もあります)。これにより、scala-xmlやscala-parser-combinatorsのライブラリの違いでビルドができないことがあります。
他にもSLF4J/Logbackやjackson-databaindなどの、コンパイル時にはわからないがランタイムでエラーを起こす厄介者もいます。
おさらい:Scala Stewardのignore設定
この様な状況下で、単にScala Stewardを導入してしまうと、依存ライブラリのバージョンを上げると、ビルドエラーだったりランタイムエラーが発生してしまったりします。そこで、実際には特定のバージョンを無視したり、パッチバージョンだけは取得したり(=ピン留め)する必要が出てきます。Scala Stewardでは.scala-steward.conf
というファイルを置くことで、それを実現できます。
updates.pin = [
{ groupId = "org.scala-sbt", artifactId = "sbt", version = "1.7.2" }
]
このファイルは(多分)HOCON形式で書かれます。Scala使いにはお馴染みかと思いますが、「初めて見たよ!」という方は、コメントが書けるJSONとしてとりあえず認識してもらえると良いです。
.scala-steward.conf
には色々な機能があるのですが、はじめにupdates.pin
を使えるようになると便利です。これにより、依存ライブラリの「ピン留め」が利用できる様になります。上に挙げた例は、sbtのバージョンを1.7.2で固定させて、それ以上のバージョンアップを行わない、という指定になります。
なお、.scala-steward.conf
には「ピン留め」以外にもいろんな機能があります。これらは公式ドキュメントを読むのも良いですが、既存プロジェクトの設定を見てみるのが一番手っ取り早かったりもします。
実践:PlayFrameworkにおけるScala Stewardのignore設定
Play2.8は約4年前にリリースされました。そしてPlayはメジャーバージョンの範囲では依存ライブラリのバージョンアップをしない傾向にあります。つまり、依存ライブラリは基本的に4年前のものを採用しており、そのままScala Stewardで依存ライブラリをバージョンアップしてしまうと、Play自体の依存ライブラリとバッティングしてしまって、ビルドエラーになってしまいます(ちなみに、これがplayのバージョンアップの醍醐味だったりもします)。
そこで、Play2.8時点で設定した方が良いignore設定を紹介します。
Play2.8
素のPlay2.8でも設定しておいた方が良いのがsbtのピン留めです。sbtは1.7.3以降からscala-xmlのバージョンとして2系を採用しており、Play2.8とバッティングします。
また、直近でPlay2.9の準備のため、依存ライブラリのバージョンアップが行われました。これらも固定化した方が良いでしょう。
updates.pin = [
{ groupId = "org.scala-sbt", artifactId = "sbt", version = "1.7.2" },
{ groupId = "com.typesafe.sbt", artifactId = "sbt-twirl", version = "1.5." },
{ groupId = "com.typesafe.play", artifactId = "play-json", version = "2.9." },
{ groupId = "com.typesafe.play", artifactId = "play-json-joda", version = "2.9." }
]
Play2.8 + Scoverage
テストカバレッジを取る場合、scalaのバージョンもピン留めする必要があります。
updates.pin = [
{ groupId = "org.scoverage", artifactId = "sbt-scoverage" version = "1.9.3" },
{ groupId = "org.scala-lang", artifactId = "scala-compiler", version = "2.13.8" },
{ groupId = "org.scala-lang", artifactId = "scala-library", version = "2.13.8" },
{ groupId = "org.scala-lang", artifactId = "scala-reflect", version = "2.13.8" }
]
Play2.8 + SLF4J + Logback
SLF4Jは2系を選択できず、2系に依存するLogbackも指定できません。
updates.pin = [
{ groupId = "org.slf4j", artifactId = "slf4j-api", version = "1.7." },
{ groupId = "org.slf4j", artifactId = "jcl-over-slf4j", version = "1.7." },
{ groupId = "org.slf4j", artifactId = "log4j-over-slf4j", version = "1.7." },
{ groupId = "org.slf4j", artifactId = "jul-to-slf4j", version = "1.7." },
{ groupId = "ch.qos.logback", artifactId = "logback-classic", version = "1.2." }
]
Play2.8 + ScalikeJDBC
jackson-databindのバージョンが異なるため、ScalaikeJDBCの最新バージョンを設定できません。
updates.pin = [
{ groupId = "org.scalikejdbc", artifactId = "scalikejdbc", version = "3.5.0" },
{ groupId = "org.scalikejdbc", artifactId = "scalikejdbc-config", version = "3.5.0" },
{ groupId = "org.scalikejdbc", artifactId = "scalikejdbc-play-fixture", version = "2.8.0-scalikejdbc-3.5" },
{ groupId = "org.scalikejdbc", artifactId = "scalikejdbc-play-initializer", version = "2.8.0-scalikejdbc-3.5" },
{ groupId = "org.scalikejdbc", artifactId = "scalikejdbc-syntax-support-macro", version = "3.5.0" }
]
Play2.8 + flyway-play
scala-xmlのバージョンが異なるため、特定のバージョンより上に上げられません。
updates.pin = [
{ groupId = "org.flywaydb", artifactId = "flyway-play", version = "7.25.0" }
]
Play2.9 + flyway-play
Play2.9であっても、最新版にはバージョンアップできません。
updates.pin = [
{ groupId = "org.flywaydb", artifactId = "flyway-play", version = "7.29.0" }
]
Play2.8 + h2
テストに使うDBとしてh2を使う場合、最新に上げてしまうと警告が出まくるのでピン留めします。
updates.pin = [
{ groupId = "com.h2database", artifactId = "h2", version = "2.1.214" }
]
Play2.8 + servlet-api
サーブレットAPIに依存する場合、jackson-databindのバージョンを揃える必要があります。
updates.pin = [
{ groupId = "javax.servlet", artifactId = "javax.servlet-api", version = "3.1.0" }
]
Play2.8 + Scalate
scala-parser-combinatorsのバージョンを揃える必要があります。
updates.pin = [
{ groupId = "org.scalatra.scalate", artifactId = "scalate-core", version = "1.9.6" }
]
補足:scala-xmlについて
scala-xmlについては1系と2系で実際は互換性があるとかないとか。どうしても新しいバージョンを入れたい場合は、依存ライブラリ側のscala-xmlを外して1系に揃える、という手もありかもしれません。ただ、Play2.9がscala-xmlの2系に揃ったので、Play2.9にバージョンアップするのが総合的に見て良い選択肢かもしれません。
まとめ
PlayFrameworkにおけるScala Stewardのignore設定を紹介しました。不必要なバージョンアップ通知がなくなることで、依存ライブラリのバージョンアップの信頼性が上がって、より安全に依存ライブラリのバージョンアップができることでしょう。
以上です。皆さんも良きScalaライフを!