Go の学習がてら actionlint のコードを読んでみる
rhysd/actionlint
GitHub Actions のワークフロー Linter です。
公式提供はされていないので今のところこれくらいしかないはず。
注意事項
Go は公式チュートリアルをちらっと眺めたくらいでコードをまともに読むのは初めてなので調べながら読んでいきます。
間違いがあったらご指摘ください。
起点
ルート直下にずらっとファイルが並んでいるので起点を探します。
*.go がソースファイルで go.mod や go.sum は Go 言語のパッケージ管理システムですかね。
CONTRIBUTING.md にビルドの方法が記載されているようです。
cmd/actionlint ディレクトリをビルドしているようなので main.go を見てみます。
起点はここのようですね。
閑話:エディタ
Visual Studio Code に Go の拡張機能を入れて使用しています。
関数へもジャンプしてくれるのでコードを読む分には問題なさそうです。
GitHub のオンラインエディタでも関数ジャンプくらいはしてくれるのでそちらでも良さそうです。
GoLand でも開いてみたんですがコードをうまく認識してくれていないのか赤線だらけになってしまいました。
再度試してみたら開けました。
actionlint 本体
cmd/actionlint は actionlint.exe 生成用のパッケージだったようなので github.com/rhysd/actionlint
パッケージを追ってみましょう。
パッケージという単位をまだよく分かってないですがこの単位でまとまってる雰囲気?
cmd.Main
へジャンプすると command.go へ飛ばされます。
flags
変数でフラグを処理していたり opts
変数でオプションを管理していたりするようですが読み飛ばしていくと cmd.runLinter
が Linter の処理のようです。
Linter
NewLinter
関数で作られた Linter
クラス(?)が引数などに応じて処理を分岐しているようです。
今のところ func の構文すらよく分かっていませんがそのうち調べます。(何で ( )
が 3 つもあるの?w)
.github/actionlint.yaml の生成
.github/workflows/ 配下を Lint
PR を送りました。
ファイルパスを抽出して LintFiles
へ渡しているようですね。
標準入力から渡された文字列を Lint
渡されたファイルパスを Lint
1 ファイルだけのときは LintFile
関数を呼んでいるようです。
Linter.check
Lint
, LintFiles
, LintFile
のいずれでも l.check
を呼び出しているのでここが実際のチェック処理でしょうか。
この関数は並列で呼び出されるのでスレッドセーフではないといけない旨が書かれていますね。
YAML のパース
パーサーは go-yaml/yaml みたいです。
Visitor
ルールを Visitor
クラスへ渡して処理。
判定結果のエラー情報は all
変数へ。
出力
エラー情報をフィルター&ソート。
パス情報を付加。
返り値で返してプリント。
Exit code
最終的にはエラーがあれば exit 1 を返します。
感想
ここまでが全体の流れ。
初見でもなんとなく読めるくらい読みやすいですね。
後は個別のルールを見ていけば全部把握できそうです。
ただ 1 文字変数は(Go の慣習なのかもしれませんが)画面外までたどらないといけなくてリーダブルコードのスコープが十分に短ければ良いというのに反しているように思えました。(中身なんだっけ?というのを何回かやったし、この記事のように引用したときに読めない)
err や fmt のような短縮も読みづらいと感じました。
Go 学習
調べながら読んでいきますとか書いてたけど全然調べなかった。
なんとなく覚えたこと。
- モジュールは
package
- package の読み込みは
import()
- 変数は
:=
- 関数は
func
- クラスは
type Linter struct {}
- null は
nil
- if は
if err != nil {}
- 配列は
rules := []Rule{}
- foreach は
for _, rule := range rules {}
-
_
は受け取るけど不使用 - enum は
const ()
1 文字変数はエディタの Sticky Scroll を有効にすることで読めるようになりそう。