地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Go】GolangCI-LintをGHAに組み込む

GolangCI-Lintとは

GolangCI-Lint とは、 Golang の Linter を一元管理するためのツールです。Goはliter一つとってもたくさんあってそれを組み合わせることでCIの信頼度を上げるという珍しい形を推奨しています。そのためこのような一元管理ツールが便利になってきます。

golangci-lint.run

インストール方法

$ docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.31.0 golangci-lint run -v

macLinuxなら以下でもインストール可能です。

$ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.31.0

# mac
$ brew install golangci-lint

実行してみる

Usage

色々オプションはありますが取りあずrunだけ使えば良さそうです。CI組み込みの場合はcacheを使ったり。configとかlintersは基本的には全て後述するファイルで指定する方が良いと思うので言及しません。

golangci-lint -h
Smart, fast linters runner. Run it in cloud for every GitHub pull request on https://golangci.com

Usage:
  golangci-lint [flags]
  golangci-lint [command]

Available Commands:
  cache       Cache control and information
  completion  Output completion script
  config      Config
  help        Help
  linters     List current linters configuration
  run         Run this tool in cloud on every github pull request in https://golangci.com for free (public repos)
  version     Version

Flags:
      --color string              Use color when printing; can be 'always', 'auto', or 'never' (default "auto")
  -j, --concurrency int           Concurrency (default NumCPU) (default 8)
      --cpu-profile-path string   Path to CPU profile output file
  -h, --help                      help for golangci-lint
      --mem-profile-path string   Path to memory profile output file
      --trace-path string         Path to trace output file
  -v, --verbose                   verbose output
      --version                   Print version

Use "golangci-lint [command] --help" for more information about a command.

実行

lintに引っかかるようなコードを書いておき以下を実行しました。linq.goの108行目のsignalのチャネルにバッファーがないという指摘が出てきました。括弧書きでエラーを発見した Linter の名前も出力されます。出力だけでは理解しづらい指摘もこれを元にぐぐることが可能です。

level=info msg="[config_reader] Config search paths: [./ /app / /root]"
level=info msg="[lintersdb] Active 10 linters: [deadcode errcheck gosimple govet ineffassign staticcheck structcheck typecheck unused varcheck]"
level=info msg="[loader] Go packages loading at mode 575 (types_sizes|compiled_files|deps|exports_file|files|imports|name) took 2.2593314s"
level=info msg="[runner/filename_unadjuster] Pre-built 0 adjustments in 2.4586ms"
level=info msg="[linters context/goanalysis] analyzers took 4.9483931s with top 10 stages: buildir: 3.9208345s, inspect: 310.9361ms, ctrlflow: 215.3187ms, fact_deprecated: 194.2855ms, printf: 145.8805ms, fact_purity: 138.1187ms, isgenerated: 2.8345ms, ineffassign: 2.6892ms, unmarshal: 376.9µs, SA4020: 375.1µs"
level=info msg="[linters context/goanalysis] analyzers took 26.3209ms with top 10 stages: buildir: 24.6488ms, U1000: 1.6721ms"
level=info msg="[runner] Processors filtering stat (out/in): autogenerated_exclude: 1/1, exclude-rules: 1/1, uniq_by_line: 1/1, diff: 1/1, max_per_file_from_linter: 1/1, path_shortener: 1/1, skip_dirs: 1/1, exclude: 1/1, max_same_issues: 1/1, max_from_linter: 1/1, severity-rules: 1/1, cgo: 1/1, filename_unadjuster: 1/1, path_prettifier: 1/1, identifier_marker: 1/1, skip_files: 1/1, nolint: 1/1, source_code: 1/1, path_prefixer: 1/1, sort_results: 1/1"
level=info msg="[runner] processing took 4.9446ms with stages: nolint: 1.8015ms, autogenerated_exclude: 1.0542ms, source_code: 925.1µs, identifier_marker: 298.3µs, exclude: 276µs, cgo: 212.6µs, sort_results: 59.5µs, filename_unadjuster: 57.7µs, skip_dirs: 51.8µs, severity-rules: 51.1µs, path_prettifier: 25.8µs, skip_files: 16.9µs, max_per_file_from_linter: 16.9µs, max_same_issues: 15.8µs, uniq_by_line: 15.8µs, path_shortener: 14.1µs, max_from_linter: 13.9µs, exclude-rules: 12.7µs, diff: 12.5µs, path_prefixer: 12.4µs"
linq.go:108:16: SA1017: the channel used with signal.Notify should be buffered (staticcheck)
    signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
                  ^
level=info msg="[runner] linters took 3.3437197s with stages: goanalysis_metalinter: 3.2339981s, unused: 103.3664ms"
level=info msg="File cache stats: 1 entries of total size 3.5KiB"
level=info msg="Memory: 58 samples, avg is 150.8MB, max is 274.3MB"
level=info msg="Execution took 5.6239488s"

設定ファイル .golangci.yml

pythonとか他言語の開発ツール同様ドットファイルで構成を定義しておくことで使いたいlinterや無視したい無視したくないルールを書いておくことができます。実行に以下のようなファイルを置いておくことで反映されます。

  • .golangci.yml
  • .golangci.yaml
  • .golangci.toml
  • .golangci.json

golangci-lint.run