Scala 3とsbtでreviewdog使う方法

reviewdogというかなり有名なツールがあって、過去何度かblogにも書いたことあるし、今も普段から使っています。

github.com

とても有名?なはずなので、概要その他の説明は省略するとして、個人的にはScalaや、Scalaに限らないgithubのpull reqでインラインでbotに警告やエラー箇所をコメントさせて使ってることが多いですね。

また、suggestも以下のような感じで任意の言語やファイルで簡単に実現可能です。

xuwei-k.hatenablog.com

さて、大抵の有名な言語では、デフォルトで用意されているもので足りるのですが、自分が知る限り、これ書いてる2024年9月現在、Scala 2では警告やエラーのインラインのコメントが正しく動いても、Scala 3だと動かない気がします。

自分も、それほど深く理解せずにREADMEなどをざっくり読んだ知識だけで書くのですが、reviewdogが利用するフォーマットは複数あり、内部的には

Reviewdog Diagnostic Format

https://github.com/reviewdog/reviewdog/tree/a9298ff2720c4b01a3095ce179a428da9b38c8ba/proto/rdf

と呼ばれる、protoやjson schemaでしっかり定義された独自のものがあり、それとは別にvimのerrorformatというものに変換して、それを利用する方法もあるらしいです。

Scala関連だと、以下にerrorformatの定義が複数あります。

https://github.com/reviewdog/errorformat/blob/1d3280ed6bd4c99964cee62740518a0bc2632535/fmts/scala.go

このblog書いた時点でscalac, sbt, sbt-scalastyle, scalastyleと4種類あります。 しかし、以下のように問題だらけです。 (実は自分が知らないだけで、以下のあたり何か情報あれば教えてください)

  • 最終更新が6年前
  • そもそもscalastyleは実質オワコン
  • そもそもこの4種類は本当に区別する必要あるのか?
  • というかsbt-scalastyleで他の普通のsbtのerrorやwarn出力が動くというか、他だと多分動かないんですが???
  • Scala 2は動くが、Scala 3だと微妙にフォーマット変わってて動かない???

もちろん、こういった問題があるなら、これ自体を改善していくのも1つの方法ではあるのですが、そもそもこれは一旦標準出力に出されたものをまたparseする、という、微妙に面倒というか壊れやすい連携方法になっています。

また、完全に個人的事情というか趣味ですが、golang全く書けないので、issue報告はできてもpull reqできる気がしないというか、これのために自分が頑張るのはコスパがかなり悪いです。

さて、ここで最初の方に触れた

Reviewdog Diagnostic Format

の話に戻ります。Reviewdog Diagnostic Formatでも、vimのerrorformatでもどちらでもなんでもいいのですが、いずれにせよsbtは構造化された状態で警告の情報が取れるので、標準出力のものを頑張ってparseするのではなく、直接sbtのbuildファイル内部、あるいはsbt plugin使って変換すればいいですね??? と思い、それを作りました。

独立して1から作っても良かったのですが、以下のような理由から、以前作った別のsbt pluginに対して機能追加、という形式にしました

  • scalafixの警告も同時に扱いたい
  • multi projectの場合に全自動でaggregateしてから1ファイルに出力したい
    • json lineにも対応してるし、それぞれが1ファイルにロックとりつつというか、atomicに追記する手法も取れたかもしれないが

github.com

これでScala 3でも無事に動くようになりました、めでたしめでたし。

jsonを吐き出すまでをやるだけなので、それをreivewdogのコマンド使って動かす(実際にgithubAPI呼ぶ)、などは別途手動でgithub actionsのyamlに書いたりする必要があります。

また、(Scala 2で)これ使う欠点ですが、警告は出せても、現状エラーを処理することはできません。

(標準出力をparseする方法だと、エラーもbotにインラインのコメントさせることが可能)

(sbtがcompile errorだとcompileタスクでは直接的には値返してくれない気がするが、何か方法あるのだろうか・・・)やりました

Reviewdog Diagnostic Formatに関しては、ひとまず警告をインラインで出せればいいので、完璧に全ては実装してません。 また、そもそもprotoファイルやjson schemaがあるので、どちらかを使ってコード生成をしたほうが確実ですが、それほど互換壊すとも思えないし、工夫しない限りコード生成すると別のライブラリの依存が増える可能性もあり、この程度なら手動で書いてしまったほうがいいか、と思いコード生成はせずに手書きしました。

このsbt-warning-diffに組み込んだもの以外で独立したものを作るかどうか?は未定です。 元々このsbt pluginは警告のdiffを出すために作ったものですが

xuwei-k.hatenablog.com

xuwei-k.hatenablog.com

reviewdog形式のjson吐き出すだけならdiffとか関係ないので、sbt plugin名と機能が若干乖離してきたけどどうしようかなぁ・・・。

追記: reviewdog作者から言及されました、なるほど、よかった

https://x.com/haya14busa/status/1831154819685552440

こういう事例をみるとReviewdog Diagnostic Format は導入してよかったなと思う。sarifはサクッと対応するにはちょっと重いし ちなみにerrorformatの改善にはGo言語の知識はほぼ全くいらないんですが、代わりにもっとしんどいであろう errorformat の知識が必要なのでrdformat対応でよさそう