scala-steward を個人レポジトリの GitHub Actions で動作させられた記録
はじめに
scala-steward を GitHub Actions から実行し、
自分のレポジトリに対してライブラリ更新ができるようにできたので、
その時の内容を記載します。
設定方法がよくわからなかったり、設定項目が何が必要かがわかりにくかったりしたので
それについても残しておきたかった所存です。
作った scala-steward を使うための GitHub Actions の設定レポジトリは以下です
scala-steward とは
Scala プロジェクトが依存するライブラリがバージョンアップリリースが存在していると、更新するためのPRを自動生成してくれるシステムです。
対抗というか、類似のツールでは Renovate や dependabot などがあります。
モチベーション
なぜ scala-steward か
他にもコンペのツールがある中で scala-steward を使ったかというと、大きくは以下の2点です。
- 他言語での開発している自前レポジトリでは Renovate, dependabot を使っているので scala-steward をつかってみたかった
- 多くの有名Scalaプロジェクトで使われているので興味があった
以下の記事によると、Renovate でも結構いけるらしいのですが、
やっぱり scala-steward を使ってみたかったので自分の環境下で動かせるようにしました。
GitHub Actions で動かす理由
実はわざわざ自分で実行環境を用意しないでも scala-steward を使う方法があります*1。
scala-steward の公式が動作する環境を用意してくれていて、
対象レポジトリ一覧に自分の管理するScalaプロジェクトのリポジトリを追加すれば動かすことが可能です
repos/repos-github.md at main · scala-steward-org/repos · GitHub
この方法のネックとしては「更新リクエストを送ってマージしてもらう必要がある」、「自分の作業用レポジトリを追加してもらうのが恥ずかしい」というのがあります。
なので自分で気兼ねなく使える環境が欲しかったため、GitHub Actions での環境を用意しました。
GitHub Actions を使う場合は以下のテンプレートを使わせてもらいます。
設定方法
前提条件
今回は以下の環境で設定することを前提になっています
設定に必要なこと
設定に必要な作業は以下
- GitHub App を生成します
- GitHub App の秘密鍵を生成します
- scala-steward 実行する専用のレポジトリを GitHub に作成します
- レポジトリの設定の
secrets
に以下の登録します
- GitHub Actions の workflow を作成します
- scala-steward の実行対象のレポジトリを決定する設定ファイルの作成
- GitHub Actions のジョブを有効化します
設定手順
GitHub App を生成
GitHub App の生成するページから「New GitHub App」のボタンをクリックして、
今回使うようの App を作成します。
設定した項目は以下にしてました
- GitHub App name
- 好きな名前でいいです。今回は「keyno63-scala-steward」とかにしました。
- Homepage URL
- 自分の GitHub アカウントのURLを入れてました
- Webhook
- デフォルトでは有効でしたが、今回いらないと思ったのでチェックボックスを外して無効化しました
- Repository permissions
- 「Contents」、「Pull Request」を「Read&Write」にします
- そのほかはデフォルトです。
以上の設定をして、「Create GitHub App」をクリックすると、Appが生成されます。
以下のようになっていれば問題ありません*2。
GitHub App の秘密鍵を生成
App 作成したら、作った App の「Edit」をクリックするか、
https://github.com/settings/apps/<作成したアプリケーション> にアクセスして、
App の編集画面に遷移します。
画面下のほうまでスクロールして、「Private Keys」という項目まで移動します。
「Generate a private key」をクリックして秘密鍵を生成します。
秘密鍵を生成出来たら、.pem ファイルが自動でダウンロードされます。
後で使うのでおいておいてください。
scala-steward 実行用レポジトリを生成
GitHub から新規レポジトリを作成します。
ここで作るのは空レポジトリで問題ありません。
必要なファイルは .github/workflows/***.yaml
だけです。これはあとで作るので今は何もなしでもよいです。
secret の設定
レポジトリの設定から secret
を設定します。
先ほど作成したレポジトリの「Settings」、左メニューの「Secrets」をクリックして遷移します。
「New repository secret」ボタンをクリックして Secret
生成画面に遷移します。
もしくはhttps://github.com/<GitHubアカウント名>/<作成したレポジトリ名>/settings/secrets/actions/new
にアクセスしてもらっても大丈夫です。
Name
に後で使う設定名を、Value
には先ほど設定した GitHub App の秘密鍵の中身をコピーして貼り付けてください
自分は「SS_PRIVATE_KEY」という設定名で作成したので以下のようになりました。
同じように Secret
が作成されていれば問題ありません。
GitHub Workflows の作成
GitHub Workflows を作成します。GitHub Actions 用の yaml ファイルを作成します。
以下のように作成して貰えれば大丈夫です*3。
name: CI
on:
schedule:
- cron: '0 0 * * 0'
pull_request:
push:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Generate token
id: generate-token
uses: tibdex/github-app-token@v1
with:
app_id: <作成した app id>
private_key: ${{ secrets.SS_PRIVATE_KEY }}
- name: Launch Scala Steward
uses: scala-steward-org/scala-steward-action@v2
with:
github-token: ${{ steps.generate-token.outputs.token }}
author-name: "<作成した App 名>[bot]"
author-email: "<作成した App の user id>+<作成した App 名>[bot]@users.noreply.github.com"
repos-file: 'repos.md'
実例は以下
補足:app id について
作成した GitHub App の App ID のことです。
GitHub App の編集画面から確認できます。
補足:author-email の取得
GitHub App のユーザー情報取得するAPIから、user id を取得できれば、App用の email が取得できます。
https://api.github.com/users/<作成した App 名>%5Bbot%5D
レスポンスの json の id
の値がわかれば、今回作成したApp名はわかるので、email が作れるというわけです。
対象レポジトリの設定ファイルを作成
workflows の yaml で指定した repos-file
のファイルを作成し、実行対象のレポジトリを指定します。
md ファイル形式で列挙して貰えればいいです。
https://github.com/keyno63/scala-steward-mine/blob/2e31af53b972ef50f2393616b855a4e1dddf66ba/repos.md
GitHub Actions を有効化してPR作成
GitHub Actionsからジョブが実行されて、ライブラリの更新があればPRが自動生成されます。
実際に作成されたPR
https://github.com/keyno63/heroku-scala-app/pull/5
作成した App で修正コミットがされていること、PRが生成されていることがわかります。
ここまでできていれば完成です。
うまくいかなかったこととか、補足とか
補足情報的な項目です。
読まなくても設定は可能なので読み飛ばしてもらっても問題ありません。
うまくいかなかったこと
scala-steward-org/scala-steward-action
の設定に App として動作させるための項目に
github-app-id
、github-app-key
を設定するのがあるのですが、
repos/repos-github.md at main · scala-steward-org/repos · GitHub
これを設定した場合に repos-file
による、特定のレポジトリのみに対する更新ができませんでした。
まだ中身をちゃんと確認していないので原因は不明
補足
GithubApp を作った理由
GitHub App から自分以外が更新した・PRの生成であることがわかるように作成しています。
「自分の活動履歴が実際のものと異なる」、「自分の作業と区別したい」という理由があったのでこの方法を採用しました。
「自分のコミット・PRでも構わない」という人は作成しなくても問題ないかもしれません。
その場合は workflow 中の token 生成は不要です。
代わりにgithub-token
には自分のアカウントの token を sercret に設定し、
author-name
author-email
は自分の GitHub アカウントに紐づいたものを使用して
使ってください。
GitHub Action 中で token の生成について
GitHub App からの PR にするために使用します。bot からのPRであることを識別してもらうため、workflow の中で token を生成してもらっています。
uses: tibdex/github-app-token@v1
の部分があたります。
これをせず、自分の token を secrets に登録、それを利用するとすると、
PRは作成できるのですが、作成者が自分になるという悲しい結果になります。
失敗してしまった例
https://github.com/keyno63/sbt-heroku/pull/4
コミットは App になっていそうだが、PR作成者は自分のアカウントになる。
author-name, author-email について
author-name
author-email
はコミットするときのユーザー情報です。
これも自分の実績と分けたかったので、設定しています。
参考情報
今回の作業にあたり、以下の情報を参考にさせていただきました。
- scala-steward-org/scala-steward-action の README
- 忙しいScala開発者の超時間節約術 by 立野靖博 - YouTube
- rpscala - scala-steward についての LT
- xuwei-k さんの scala-steward に関するブログ
最後に
ずっと興味のあった scala-steward が自分のレポジトリに適応できるようになったので感無量です。とてもうれしかった。
Scala/sbt で設定した依存関係がコンフリクトしてしまったら
概要
Scala/sbt を使っていて、依存関係で追加したライブラリ間で依存関係が衝突してしまったときにどうすればいいかという内容です。
Java/gradle だと自動的に新しいバージョンを使うようしてくれていたのですが、どうも sbt ではそうはいかないらしいということがわかりました。
その時にどうすれば回避できるのかについて記載しています。
事象
自分は scalikejdbc
とakka-stream
を依存関係に追加した時に、scala-parser-combinators
のコンフリクトで発生しました。
lazy val akkaPj = project
.in(file("akkaPj"))
.settings(
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-stream" % "2.6.17",
"org.scalikejdbc" %% "scalikejdbc" % "4.0.+",
)
)
sbt の読み込みを行うと以下のような結果になります。
[error] java.lang.RuntimeException: found version conflict(s) in library dependencies; some are suspected to be binary incompatible:
[error]
[error] * org.scala-lang.modules:scala-parser-combinators_2.13:2.1.0 (early-semver) is selected over 1.1.2
[error] +- org.scalikejdbc:scalikejdbc-core_2.13:4.0.0 (depends on 2.1.0)
[error] +- com.typesafe:ssl-config-core_2.13:0.4.2 (depends on 1.1.2)
ssl-config-core
(akka-stream
の子依存)が scala-parser-combinators-1.1.2
に依存していて、
scalikejdbc
がscala-parser-combinators-2.1.0
に依存しているため、
コンフリクトが発生している状況になります。
対応方法
dependencyOverrides
を sbt で設定することで対応できました。
ここで指定したライブラリをそのバージョンで override することができました。
lazy val akkaPj = project
.in(file("akkaPj"))
.settings(
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-stream" % "2.6.17",
"org.scalikejdbc" %% "scalikejdbc" % "4.0.+",
),
dependencyOverrides += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.0"
)
今回ではscala-parser-combinators-2.1.0
を優先する設定にしています。
以下の sbt の公式マニュアルにも説明されていました。
参考
以下も参考にしました。
ビルドツールのセマンティクスについての説明や検証について書かれて大変勉強になりました。
sbt1.4系からsbt1.5系に移行したいけどうまくいかなかったあなたへ
はじめに
Scala のビルドツール sbt のバージョンアップをするときに途方にくれていたのですが、
実は結構簡単にできる方法があると教えてもらったので、その時のことを記録しています。
特に 1.4 系から 1.5 系に移行するときに大幅な変更があり、その差分変更にてこずった話になります。
同じように 1.4 系から、もしくはそれ以前のバージョンから更新したい場合に参考になるのではと思っています。
sbt バージョンアップ
sbt はバージョンアップに伴って大幅な機能追加・機能変更がされています。
特に sbt 1.5 系から Scala3 のビルド機能が追加されるなど注目の変更もありました。
私もそれにつられて sbt 1.5 を使うようにしているのですが、
古いプロジェクトで sbt 1.4 をつかっていて、更新したときに build.sbt の変更が必要になりました。
具体的には build.sbt で使う in というメソッドが非推奨になっています。
どういう実装のものかというと、以下のような記述のケースです。
version in webpack := "4.43.0",
version in startWebpackDevServer := "3.11.0",
webpackConfigFile in fastOptJS := Some(baseDirectory.value / "webpack" / "webpack-fastopt.config.js"),
webpackConfigFile in fullOptJS := Some(baseDirectory.value / "webpack" / "webpack-opt.config.js"),
webpackConfigFile in Test := Some(baseDirectory.value / "webpack" / "webpack-core.config.js")
この記法の代わりにスラッシュ構文という / を使う必要があるそうです。
設定箇所が複数あると、ひとつずつ変えていくのも大変ですし、どうしようかなと悩んでいたらTwitterで「scalafix を使ってマイグレーションができる」という方法を教えてもらえました。
たぶんこの scalafix rule でマイグレーションできませんか https://t.co/GRZNQgwgLd
— Tatsuno Yasuhiro (@exoego) 2021年11月1日
scalafix は設定方法に従って Scala や sbt のファイルを書き換えてくれる機能です。
sbt プラグインとして使うことが多い印象でしたが、コマンドラインとして実行する方法もあるようです。
sbt 1.4 から sbt 1.5 へ、scalafix を使って移行する方法については以下のブログが詳細に書かれていました。
以上のブログで十分かもしれませんが、もう少し補足させてもらいます。
やることとしては以下
- (入っていない場合は)cs コマンドを入れる*1
- scalafix をインストールする
- scalafix をコマンドへ実行パスを通す
- 前述したブログの内容のコマンドを実行します。
cs コマンドのインストール方法については以下を参考にしてください*2。
cs コマンドを使って、scalafix をインストールします。
cs コマンドからインストールすると、Coursier のホームディレクトリ以下にインストールされてしまうので、コマンドラインから実行できるように実行PATHを設定します*3。
コマンドが通るようになったら、以下のコマンドを、sbt を更新したいプロジェクトのなかで実行します。
>scalafix --rules=https://gist.githubusercontent.com/eed3si9n/57e83f5330592d968ce49f0d5030d4d5/raw/7f576f16a90e432baa49911c9a66204c354947bb/Sbt0_13BuildSyntax.scala *.sbt project/*.scala
以上のコマンドを実行した結果、以下のように書き換えが行われました。
sbt 1.5 を起動すると、エラーや Warning が出力されなくなり、無事に移行することができました。
(webpack / version) := "4.43.0",
(startWebpackDevServer / version) := "3.11.0",
(fastOptJS / webpackConfigFile) := Some(baseDirectory.value / "webpack" / "webpack-fastopt.config.js"),
(fullOptJS / webpackConfigFile) := Some(baseDirectory.value / "webpack" / "webpack-opt.config.js"),
さいごに
Scala は大幅な変更がたびたび入る言語ですが、移行の大変さを軽減するためのツールや仕組みが充実していると感じています。
私の周り*4には「Scalaはメンテが大変だ」「Scala3もリリースされて移行を考えると採用しづらい」という意見を聞くこともあります。
確かに自分もそういう風に感じることがありますが、Scalaでの開発大変は他では得難いことも多くあると感じているので、そこであきらめる人やチームを減ってほしいなと思っています。
こういうツールがある、こういう対応方法が用意されている、ということを多くの人が知ってほしいと思っています。
参考
Gradle で Java のユニットテストを1つのクラス、1つのテストだけ実行する方法
内容
備忘録としての内容です。
Javaで開発している際、ユニットテストを実装して動作確認すると思います。
普段は IDE でテストの実行をすると思いますが、その際はテストの実行を選択すれば自動的に設定して、実際に実行したい単位でテスト実行することができます。
コマンドラインから実行した時にもクラス単位、メソッド単位で実行したいな思ったので、その方法についてになります。
具体的な方法
test 実行時にオプションに「--tests」でテストしたいクラス・メソッドを指定すると実行できます。
クラス単位でテストを実行する場合
packages.ClassName
というTestクラスがある場合、以下のコマンドで実行できます
./gradlew test --tests "packages.ClassName"
メソッド単位でテストを実行する場合
packages.ClassName
というTestクラスに testMethod()
というTestメソッドがある場合、以下のコマンドで実行できます
./gradlew test --tests "packages.ClassName.testMethod"
IntelliJ で Java のビルド時にバージョン関係ではまった時に確認する箇所
概要
小ネタ系
Intellij でJava の開発をしていて、ビルド時にエラーになってしまう、
特にコードの構文が合っているのにエラーになってしまう場合に、
どこをどのように確認・修正するばいいのかについてまとめてみました。
自分は Java17 の preview 機能を使おうと思い、
実装してビルドしようとすると設定不備で以上の事象に遭遇し、
何か所か修正する必要があったので、その内容についてまとめています。
今回の内容は「17(Preview) - Pattern matching for switch」に設定し、
該当機能がビルド・実行ができるようにする設定について記載しています。
環境
確認環境やツールのバージョンについて。
私はWindows を使っているので、以下の環境で確認しました。*1
操作についてはわかる範囲は Mac についても記載してます。
確認する箇所
その1:プロジェクト設定のJava・JDKの設定があっているか確認する
プロジェクト設定のプロジェクト設定に Java や JDK の設定があります。
これが期待する設定になっているか確認します。
プロジェクト設定の開き方は以下
- Windows, Mac 共通
- [File] -> [Project Structure...]を選択
- 「Project Structure」ダイアログが開いて、[Project Settings] -> [Project] を選択します
今回は Java 17 を使いたいので、version 17 のものである「openjdk-17」を選択します。
必要な jdk がインストールされてない場合は下のほうにある Add SDK から追加でダウンロードできます。ダウンロード後に設定してください。
「Project language level」の設定を対象のバージョンに設定します。
今回は「17(Preview) - Pattern matching for switch」を選択し、設定します。
これらの設定が完了したらダイアログの右下の 「Apply」を押して設定反映します。
その2:プロジェクト設定のモジュールにある言語レベルを確認する
プロジェクトのモジュール設定は以下の方法で開きます
- Windows, Mac 共通
- [File] -> [Project Structure...]を選択
- 「Project Structure」ダイアログが開いて、[Project Settings] -> [Modules] を選択します
プロジェクトを選択し、「Sources」タブの中にある「Language level」から設定したい Java のバージョンを選択します。
今回は「17(Preview) - Pattern matching for switch」を選択し、設定します。
設定が完了したら、ダイアログの右下の「Apply」をクリックし、設定を反映します。
その3:ビルドツールのJVM設定が必要な Java バージョンになっているか確認する
ビルドツール側の Java が正しいか確認します。
実行時に使用する設定が間違っていると、IDEから実行した時にエラーになる場合があります。
私は Gradle を使っているので Maven など他のビルドツールを使っている場合は、対象の設定を確認してください。
ビルドツールの設定は以下の手順で開きます。
- Windows
- [File] -> [Settings...]を選択
- 「Settings」ダイアログを開いて、[Build, Execution, Deployment]-> [Build Tools]からプロジェクトで使用しているビルドツールの設定を開く
- Mac
- [IntelliJ IDEA] -> [Preferences...]を選択
- 「Settings」ダイアログを開いて、[Build, Execution, Deployment]-> [Build Tools]からプロジェクトで使用しているビルドツールの設定を開く
ビルドツールの設定を開き、JVMなどの設定が対象の設定になっているか確認します。
Gradleの場合は「Gradle JVM」の設定を確認します。
設定を変更した場合、右下の 「Apply」をクリックし、設定を反映します。
その4:ビルドツールの設定ファイルにJavaバージョン設定が正確にされているか確認する
ビルドツール側の設定ファイルに読み込む Java のソースコードバージョンを設定できる項目があります。
Gradleの場合は sourceCompatibility
、targetCompatibility
がそれです。*2
この設定を確認する理由は、 IntelliJ IDEA はビルドツールで指定した設定を優先するため、この設定がビルドツールの設定ファイル側にあると、いままで設定した項目を上書きしてしまいます。
使いたいバージョンか、それ以上のバージョンになっているか。を確認します。
今回は Java 17 preview 機能を使いたいため、build.gradle
に以下の設定があるか確認します。
sourceCompatibility = '17'
targetCompatibility = '17'
以上の設定が完了したら、ビルドツールの設定ファイルの再読み込みを実行します。
おまけ
本筋と異なりますが、preview 機能使いたい場合の方法についても、ちょっとわかりにくいので書かせてもらいます。
Java の preview 機能と使いたい場合、そのままでは使うことができず、
コンパイル・実行時にオプション引数として --enable-preview
を付与する必要があります。
このオプションを有効にする設定はビルドツールの設定ファイルに追記することもできます。
以下の記述を build.gradle
に記述します。
tasks.withType(JavaCompile) {
options.compilerArgs += "--enable-preview"
}
tasks.withType(Test) {
jvmArgs += "--enable-preview"
}
tasks.withType(JavaExec) {
jvmArgs += '--enable-preview'
}
最後に
IntelliJ で Javaのビルド時に参照される設定を把握するのは難しかったので、今回のエントリーを記載しました。
Java のプロジェクト設定を直すとよい、という情報を参考に設定を変更しても、実行時に失敗してしまい、
設定を再確認すると設定が別のJavaバージョンで上書きされていて「なんでだ?」と思ったら、ビルドツールのsourceCompatibility
が悪さをしていたりと、
動かすまでが大変だったので、そういった同じ罠にはまる人の参考になればと思います。
SpringBoot でログレベルを変更する
概要
SpringBoot でログレベルを変える方法について記載します。
記載した経緯
以下の理由からまとめてみようと思っています。
- ログレベルの設定変更について、何度か説明機会があったこと
- やること自体は複雑ではないため
ログレベルを変更するユースケース・メリット
ログレベルを変更するのは、アプリケーションの動作の経緯を確認するために使用します。
アプリケーションログは普段は必要な情報だけを取得できるよう、特定のレベル以上のログしか出ないようになっています。
SpringBootのデフォルトでは INFO に設定されています。
確認したい動作内容については抑制されたログレベルでしかでない場合があります。
そういった情報を取得するためにログレベルを変更します。
例えば以下
こういう情報が欲しい場合、ログレベルを変更して解析の情報源を取得します。
設定内容
ログレベルの設定変更は以下の2つのどちらかを選択します
- アプリケーションの設定ファイルにログレベルを指定する
- ロギングモジュールの設定でログレベルを指定する
アプリケーション設定ファイルに指定する
application.yaml, application.properties にある設定項目(logging.level.xxx )にログレベルを指定することで変更できます。
root (すべてのモジュール)のログレベルを、DEBUGから出力する場合は以下のように設定ます。
application.yaml の場合
logging:
level:
root: DEBUG
モジュール別にログレベルを指定可能で、level の後にパッケージ名も指定して個別に設定することも可能です。
SpringBootのロギング
SpringBoot のロギングモジュールの設定ファイルから指定することでログレベルを変更する方法もあります。
SpringBoot は Apache Commons Logging を使用しています。
spring-boot-starter-web をビルドツールの依存についてすれば、依存で使えるようになります。
具体的なログ出力の実装としては以下から選択できるようになっています。
今回は一旦デフォルトの Logback の場合について記載しています。
公式ドキュメントでは以下が該当します
Logback
標準のロギング実装モジュール、Logback を使う場合。
logback-spring.xml を resources 以下に置き、中に以下のように記載します。
<?xml version="1.0" encoding="UTF-8" ?>
<configuration >
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-7([%level]) : %m%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
おまけ
設定の優先度について
アプリケーションの設定と、ロギングの設定を両方設定した場合、どちらが優先されるのか。
試した限りでは、以下の結果でした
- 両方設定した場合、アプリケーションの設定のほうが優先される
- 片方のみ設定した場合、指定した設定が有効化される
- 設定がない場合、INFOレベルで出力される
最後に
ログ出力の内容は解析や切り分けに重要なので、知らない方はみれるようになると便利になるかと思っています。
Intellij IDEA で複数画面を開いているときにキーボードショートカットでウィンドウ切り替えしたい
Intellij IDEA で複数画面を開いているときにキーボードショートカットでウィンドウ切り替えしたい
IntelliJ IDEA で複数画面開いているときに、キーボードの入力からのショートカットコマンドで画面切り替えしたい場合どうすればよいかという話です。
IntelliJは1プロジェクト1画面なので、複数のプロジェクトを開きたい場合はウィンドウが多くなりがちになります*1。
画面を切り替えるときに、ディスプレイ上に展開された別プロジェクトのIntelliJの画面をさがしたりするのが手間に感じる場合があります。
これをなんとかコマンドショートカット(キーボードのみで操作する)で出来ないかについて記載しています。
公式の機能ではそのような機能はなさそうでした。
調べたところ、plugin を入れると実現できるようです。
「Frame Switcher」というplugin があるので、IntelliJの設定のプラグインから探してインストールすれば可能になります。
使い方はOSごとにコマンドが異なります。
最後に
短めですが、今回の内容はここまでです。
便利な機能・プラグインについての説明・紹介の内容は以上になります。