どうも、かとじゅん(@j5ik2o)です。
Scala製ライブラリでの依存ライブラリ更新と定期リリースをGithub Actionsを使って自動化するようにしたので、以下にその方法をまとめます。
具体的な例を見たい場合は以下のリポジトリを参照してください。
自動化した作業
- 依存ライブラリのバージョンアップのPR作成とマージ
- リリースノートの生成
- JARファイルの公開
ツールの前提条件など
sbt-ci-release
,sbt-scalafix
,sbt-scalafmt
のsbtプラグインは必須としています。CIでリリースするだけならsbt-ci-release
の設定だけでOK- project/plugins.sbt 参照
sbt-ci-release
の設定- git tagに振られたバージョンに基づいてリリースするので
version.sbt
を削除 sbt-release
のリリースプロセスの設定も不要- このあたりのリリースに関する情報も記述。XMLで書いてるとリリース時トラブることがある
- GPGの設定を適切に行う。公開鍵をkeyserverに送信しておく
- GithubのSecretsに、PGP_PASSPHRASE, PGP_SECRETを登録
- GithubのSecretsに、SONATYPE_PASSWORD, SONATYPE_USERNAMEを登録(要Sonatypeアカウント)
- git tagに振られたバージョンに基づいてリリースするので
sbt-scalafix
の設定は以下sbt-scalafmt
の設定は.scalamft.conf
のみです。IntelliJ IDEAにscalafmtのformat on save
があるのでscalafmtOnCompile
は設定していません。- sbtプラグインの詳細は以下参照
build.sbt
にlint
コマンドエイリアスを追加。ここではコードフォーマットのチェックとscalafix
のチェック処理を行います。- build.sbt 参照
- ライブラリの依存関係はproject/Dependecies.scalaに集約
- 依存ライブラリの更新はscala-stewardを使う
- Github Actionsから利用する場合は scala-steward-actionが便利
- 事前にBOT用アカウントでPernal Access Tokenを発行し、GithubのSecretsにCW_SCALA_STEWARD_TOKENを登録(Github Appを使う場合は不要)
用意するGithub Actionsのワークフローは以下です。
- CI
- Snapshot
- Bump Version
- Release
- Scala Steward
CI
CIのワークフローはmainブランチへのpush, pull_requestがトリガーでlintとtestを行います。加えて、pull requestのみ自動的にマージします。
scala-ulid/ci.yml at main · chatwork/scala-ulid · GitHub
自動マージはMergifyを使う方法もありますが、今回はPRを作ったauthorがBOTと同じ名前ならば自動的にマージするようにしています*1。自動マージの条件にauthor以外に変更されたファイルパスを指定する方法もあると思いますが、Github Actionsでうまくやる方法がわかりませんでした…。詳しい方、アドバイスもらえると助かります。
Snapshot
CIが成功したらsbt-ci-release
を使ってスナップショット版のJARを公開します。sbt-ci-release
の場合はタグ以外のコミットで起動した場合は自動的にスナップショット版のJARがデプロイされます。Release版のワークフローとほとんど変わりませんが、依存元のCIワークフローの成否判定やチェックアウトするコミットを合わせるなどの違いがあります。
scala-ulid/snapshot.yml at main · chatwork/scala-ulid · GitHub
Bump Version
sbt-ci-release
ではリリース版のJARをリリースするには、まずはタグを作成する必要があります。sbt-release
の構成ではversion.sbt
にバージョンを保存していましたが、sbt-ci-release
ではversion.sbt
は削除しGit上のタグを利用することになります。このワークフローは手動実行もしくは1日一回自動的に実行されますが、15行目あたりでリリース済みの最新バージョン(タグ)からHEADまでに変更差分がないかチェックし、差分があればバージョンを上げたタグとGithubのリリースを自動的に作成します。
scala-ulid/bump-version.yml at main · chatwork/scala-ulid · GitHub
今回はバージョンを上げるためにmathieudutour/github-tag-action
を利用しています。タグ作成以外にconventional-changelogに対応していてリリースノートを自動生成できます(ただし、コミットメッセージにルールが必要になります。今回はAngularの規約を使いました)
リリースノートのためにコミットメッセージに規約が導入されるデメリットがあるので、一様にオススメできるものではないと思いますが…。
Release
リリース用にタグ作成されるとRelease用のワークフローが起動します。タグがトリガーになる+事前にテストするだけで、Snapshotのワークフローとほとんど違いはありません。
scala-ulid/release.yml at main · chatwork/scala-ulid · GitHub
ハマりどころがあります。Bump Versionでタグを作るとReleaseのワークフローが起動するはずですがGITHUB_TOKENだと起動せず、Personal Access Tokenだと起動します。要注意。
Scala Steward
最後がライブラリ依存関係を更新するPRを作成してくれるScala Stewardです。Scala StewardはScala専用のDependabotみたいなものです。Github Actionsから利用する場合は scala-steward-actionを使うととても簡単に導入できます。
scala-ulid/scala-steward.yml at main · chatwork/scala-ulid · GitHub
Scala Stewardによって作成されたPRはCIのフローがテストします。テストがパスすると自動的にマージされます。
.scala-steward.conf
のコミットメッセージにAngularの規約の一つであるbuild:
を含めているので、Bump Versionのワークフローでリリース対象に含まれますので、依存ライブラリのバージョンアップだけであっても定期的にJARがリリースされるようになります。
https://github.com/chatwork/scala-ulid/blob/main/.scala-steward.conf#L2
FYI: Github ActionsでのScala Stewardの導入に関しては以下のブログ記事も見るとよいです。吉田さんのはGithub Appを使う例です。tibdex/github-app-token
を使うと実行時にトークンが取得できるので、必要なアクションに渡してあげればよいです。前述したPull Requestの自動マージもGithub Appのトークンで実行できます*2。
github.com xuwei-k.hatenablog.com xuwei-k.hatenablog.com scalapedia.com
まとめ
依存ライブラリのバージョンアップについては、Scala StewardがPRを作成→テストがパス→自動マージされます*3。JARファイルの公開とリリースノートの生成についても、一日一回最新のタグからの差分を検出して、新しい変更があれば自動的に実行されます。scala-steward-action
やリリースノートの自動生成については、ライブラリだけでなくアプリケーションでも役に立ちそうです。
ということで、溜まったPRをマージしていいですか?してくださいとか、JARの公開どうやったらいいですか?みたいなめんどくさい話はなくなって、そういう時間を別のことに当てられるようになります。参考になれば幸いです。
*1:BOT用に物理アカウントを一つ用意するか、Github Appを作りそのアプリケーションが実行時にトークンを取得する方法がありますが、今回はBOT用の物理アカウントを使っています
*2:実例はhttps://github.com/j5ik2o/akka-persistence-dynamodbを参考にしてください
*3:Mergifyを使う手もありますが、プライベートリポジトリを考慮するとGithub Actionsのほうがよいかもしれません