Scala Steward 2022年のハイライト

この記事は Scala Advent Calendar 2022 の2日目です。まだポツポツ空きがあるので、Scala を使っている人はぜひ投稿してみてください。

 Scala Steward は、Scala プロジェクトで使われている依存関係の新バージョンを見つけ、プルリクエストを作ってくれるボットアプリです。

ぼくは2021年から Scala Steward のメンテナンスの1人です。2022年は自身でもいくつか変更をしてきましたが、今年もまたコミュニティのみなさまから多大な貢献があり、Scala エコシステムの力強さを感じています。おかげさまでチェンジログはとても長くなりました。その中から、ユーザーにとって特に大きな 8 つを選りすぐってご紹介します。

①複数のライブラリをひとつのプルリクで更新

複数のライブラリの更新をひとつのプルリクエストにまとめられるようになりました(#2714)


pullRequests.grouping = [
  { name = "patches", "title" = "Patch updates", "filter" = [{"version" = "patch"}] },
  { name = "minor_major", "title" = "Minor/major updates", "filter" = [{"version" = "minor"}, {"version" = "major"}] },
  { name = "typelevel", "title" = "Typelevel updates", "filter" = [{"group" = "org.typelevel"}, {"group" = "org.http4s"}] },
  { name = "my_libraries", "filter" = [{"artifact" = "my-library"}, {"artifact" = "my-other-library", "group" = "my-org"}] },
  { name = "all", title = "Dependency updates", "filter" = [{"group" = "*"}] }
]

依存関係をひとつずつ更新したほうが、

  • CI で何か影響がでたときに何が原因か特定、修正しやすい
  • CI でキャッチできなかった予期せぬ影響がでたときに Revert しやすい

という考えもあり、実際に運用するかどうか議論の余地がある機能ではあります。

ですが、Scala/Java のライブラリ更新で影響が出ることは、メジャーバージョンアップを除けばほとんどなく、

  • ボットがドバッとプルリクを送ってくると、レビューがしんどい(ボット疲れ)
  • 多くのプルリクで CI の待ち時間がのびたり、CI の利用コストが上がるので、困っている

ということから望む声が強かった機能です。

同様の問題を感じていた場合は、ぜひご利用を。設定の書き方はこちらの pullRequests.grouping を参照してください。

②新バージョンの更新確認頻度を依存関係ごとに細かく指定できるように

個別の依存関係または何らかのグループごとに、更新の確認頻度(≒プルリクエストの作成頻度)を指定できる(#2515)ようになりました。

たとえば AWS SDK を使って開発していると「うわっ… AWS SDK の更新多すぎ…?」と引くことがあります。ほとんど毎日のように Scala Steward が AWS SDK を更新するプルリクエストを作ってくれると、たとえプルリクのマージを自動化していても「通知うぜぇ…」となることでしょう。

そんなときは「デフォルトは毎週1回は更新確認、AWS SDK は毎月1回、クリティカルなライブラリは即座に」のような設定ができます。


pullRequests.frequency = "@weekly"
dependencyOverrides = [
    {
        dependency = { groupId = "com.amazonaws" },
        pullRequests = { frequency = "@monthly" },
    },
    {
        dependency = { groupId = "example.super-critical" },
        pullRequests = { frequency = "@asap" },
    }
]

設定の書き方はこちらを参照してください。

③動作サポート環境から Java 8 の削除、Java 17 の追加

これまでは LTS である Java 8 と 11 で動作確認していましたが、Java 11 と Java 17 に変更されました(#2779)。 最近、Scala Steward で使っているライブラリがチラホラと Java 8 を切り捨て始めました。Java 8 のために特別な対応をするとメンテナーとして負担があるので、メンテナンスをしやすくするためです。

OSS でどこまで古い環境サポートするかは悩ましい問題です。ただ、Scala Steward の場合はライブラリではなくボットアプリであり、Docker や GitHub Action で使用されることが大半です。ユーザーが Java 11 や 17 の環境を用意するのはカンタンと考えられるので、メンテナー内での議論はスムーズでした。

④依存関係を更新したときのフックの条件が柔軟に

「特定の依存関係が更新された」というイベントをフックして Scala Steward に何らかの処理を実行させられます。このフックの条件で依存関係の groupId や artifactId を省略できるようになりました(#2451)


postUpdateHooks = [{
    command = "sbt protobufGenerate",
    commitMessage = "Regenerated protobuf files",
    groupId = "com.github.sbt",
    artifiactId = "sbt-protobuf"
}, {
    command = "sbt mySuperAwesomeTask",
    commitMessage = "Run something awesome always",
}]

通常は sbt で定義したカスタムコマンドを実行するとよいですが、一応は任意のコマンド(シェルスクリプトなど)を実行できるはずです。ユーザーが指定したフックはすべて firejail というサンドボックスで実行される(#2441) ことに留意してください。

このフックの仕組みは、後述するデフォルト設定でも次のように使われています。


postUpdateHooks = [
  {
    groupId = "com.github.liancheng",
    artifactId = "organize-imports",
    command = ["sbt", "scalafixAll"],
    commitMessage = "OrganizeImports ${nextVersion} で import 文をフォーマットしなおす",
    addToGitBlameIgnoreRevs = true
  },
  {
    groupId = "de.heikoseeberger",
    artifactId = "sbt-header",
    command = ["sbt", "headerCreate"],
    commitMessage = "sbt-header ${nextVersion} でファイルのヘッダーを生成しなおす"
  }
]

⑤デフォルト設定を GitHub レポジトリから参照するように

従来、Scala Steward のデフォルト設定ファイルは Docker イメージやソースに同梱されており、最新バージョンがリリースされてユーザーがバージョンアップするまで、ユーザーの環境には反映されませんでした。

今後はScala Steward の GitHub レポジトリを参照するようになりました(#2337)。これに対応したバージョンを動かしていれば、以降は Steward インスタンスの再起動時にすぐ反映されるようになります。

Scala Steward が提供しているデフォルト設定では、たとえば次のような設定が入っています。

  • Scala や Scala.js の最新版が Maven Repository にアップロードされても、ブログなどでリリースノートが公開されるまで待つ。これにより、プルリクから最新のリリースノートにリンクできる
  • BSL に変更された Akka をデフォルトでは更新しない

このような設定ファイルの参照先は --repo-config というオプションで1つ以上指定できます。組織で使う Scala Steward インスタンスに共通の設定をしたいときに使うとよいでしょう。

⑥GitHub のラベルに対応

GitHub を対象としている場合に、プルリクエストに semver-spec-minor や library-update などのラベルをつけられるようになりました(#2523)。従来はプルリク概要欄にテキストのみで記載していましたが、ラベルをトリガーに Mergify など何らかのツールと連携ができるでしょう。

また、使わないラベルがあるときは除外もできます(#2636)。デフォルトではすべてのラベルがつきますが、 pullRequests.includeMatchedLabels = "(.*semver.*)|(commit-count:n:.*)" といった設定で、指定したものだけにできます。

⑦ .git-blame-ignore-revs に対応

CLI の git では git blame --ignore-revs-file FILE というオプションで「blame 対象から除外するリビジョン(コミットハッシュ)が書かれたファイル」を指定できます。この機能に GitHub が 2022年3月に .git-blame-ignore-revs というファイル名で対応 したのを受けまして、Scala Steward も条件に合うコミットを .git-blame-ignore-revs に追加できる(#2652)ようになりました。

これを使うには、postUpdateHooks のエントリーに addToGitBlameIgnoreRevs = true というフィールドを追加します。


postUpdateHooks = [
  {
    groupId = "com.lightbend.sbt",
    artifactId = "sbt-java-formatter",
    command = ["sbt", "javafmtAll"],
    commitMessage = "sbt-java-formatter ${nextVersion} で .java ファイルをフォーマットしなおす",
    addToGitBlameIgnoreRevs = true
  },

⑧Scala Steward パブリックインスタンスの運用が VirtusLab に移管

もしあなたが Scala の OSS レポジトリを公開している場合は、VirtusLab/scala-steward-repos にプルリクを出すと、パブリックインスタンスがあなたのレポジトリを最新化してくれます。

Scala Steward は GitHub Action で動かせるようになりましたが、OSS の場合はこの方法が一番お手軽でしょう。

パブリックインスタンスは、Scala Steward のクリエイター fthomas さんのご好意で長年提供されていましたが、今年に入り、VirtusLab という会社に移管されました。VirtusLab は ScalaCenter とともに Scala 本体や周辺ツールの開発運用に大きく貢献されています。 OSS クリエイターやメンテナーの燃え尽き症候群が近年エコシステムを揺るがせることがしばしばあるので、 個人に頼らない企業のサポートが入るのはうれしいですね。

補足:Scala Steward を選ぶべき理由

Scala Steward と同種の依存関係更新ボットとして Scala に対応したものに Renovate があります。セットアップのラクさなどは Renovate に軍配が上がるようですが、Scala Steward はライブラリの更新だけではなく、

など、Scala プロジェクトに特化している「ならでは」の機能が多数あります。

メンテナーとしての思い入れもありますが、Scala を長期的にアクティブに利用し続けるプロジェクトでは、まだまだ Scala Steward が良いと思っています。GitHub Action scala-steward-actionの機能やドキュメントも改善され、グンと導入しやすくなっています。

2022年ふりかえって

今年も Scala プロジェクトの運用を助ける大きな便利機能が多数リリースされました。Scala コミュニティのおかげです。

Scala Steward を導入して、2023年も良い Scala 開発者人生をお送りください!