【Go言語】golangci-lintの使い方

## はじめに

Goでは [golangci-lint](https://github.com/golangci/golangci-lint) というリンターに`gofmt`, `goimports`, `govet`など100以上のリンターが入っている。

https://golangci-lint.run

## インストール

### バイナリ

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

### brew

```sh
brew install golangci-lint
brew upgrade golangci-lint
```

最新リリースがbrew似ない時は`brew tap`からインストールする。

```sh
brew tap golangci/tap
brew install golangci/tap/golangci-lint
```

:::note warn
`go install`でインストールするのは非推奨
:::

その他は、[Install | golangci-lint](https://golangci-lint.run/welcome/install/#local-installation)　を参考にしてください。

## 使用方法

### バージョン確認

```shell-session
$ golangci-lint --version
golangci-lint has version 1.59.1 built with go1.22.3 from 1a55854a on 2024-06-09T18:08:33Z
```

### 実行

以下のコマンドで実行できる。`./...`は省略可能。

```sh
golangci-lint run
```

:::note warn
go workspaceを使用している場合は`go list -f '{{.Dir}}/...' -m | xargs golangci-lint run`としてください。
:::


ファイルやディレクトリも指定できる。

```sh
golangci-lint run dir1 dir2/...
golangci-lint run file1.go
```

特定のlinterだけチェックする場合は、以下のようにする(以下の例では、`errcheck`を指定)

```sh
golangci-lint run --disable-all -E errcheck
```

### デバッグ

`-v`をつけると、詳細を出力できる。

```shell-session
$ golangci-lint run -v
INFO golangci-lint has version 1.59.1 built with go1.22.3 from 1a55854a on 2024-06-09T18:08:33Z 
INFO [config_reader] Config search paths: [./ /workspace / /home/vscode] 
      ・・・・・v
INFO File cache stats: 0 entries of total size 0B 
INFO Memory: 3 samples, avg is 30.8MB, max is 38.8MB 
INFO Execution took 150.923458ms
```

また、環境変数`GL_DEBUG`を指定して、より詳細なデバッグができる。指定できる値は、[logutils.go](https://github.com/golangci/golangci-lint/blob/master/pkg/logutils/logutils.go) に記載されています。

```sh
GL_DEBUG="loader,gocritic" golangci-lint run
```

### 有効なリンターの確認

どのリンターが有効になっているかは、`golangci-lint help linters`で確認できる。`Enabled by default linters`に現在有効になっているリンターが出力される。`Disabled by default linters`に無効なリンターが出力される。

以下は設定

```shell-session
$ golangci-lint help linters
Enabled by default linters:
errcheck: errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
gosimple: Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
govet: Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes. [fast: false, auto-fix: false]
ineffassign: Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
staticcheck: It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false]
unused: Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]

Disabled by default linters:
asasalint: check for pass []any as any in variadic func(...any) [fast: false, auto-fix: false]
        ・・・・・・
```

ちなみに、以下のリンクからからgolangci-lintで使用可能なリンターの一覧は確認できる。また、`deadcode`や`structcheck`など廃止されたリンターも確認できます。

<https://golangci-lint.run/usage/linters/>

[golangci-lint に搭載されている linter を学ぶ](https://zenn.dev/sanpo_shiho/books/61bc1e1a30bf27/viewer/642fe9) に幾つかのエラーの説明が記載されていたが、内容が古かったので注意してください。

### 設定ファイル

デフォルトで以下の設定ファイルを探しに行く。

* `.golangci.yml`
* `.golangci.yaml`
* `.golangci.toml`
* `.golangci.json`

設定ファイルを指定したい場合は、`-c`をつける。

以下は、`.golangci.toml`の例です。

```.golangci.toml
[linters]
disable-all = true
enable = [
  "unparam",
  "govet",
  "gci",
  "typecheck",
  "unused",
  "gosimple",
  "ineffassign",
  "staticcheck",
]

```

調べてみると、超厳格な場合のベストプラクティス例がありました。(detailsタグ内でgist埋め込めないんですね...)
[Golden config for golangci-lint](https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322#file-golangci-yml)

### VSCodeの設定

```.vscode/settings.json
{
  "go.lintTool": "golangci-lint",
  "go.lintFlags": ["--config=${workspaceFolder}/.golangci.toml", "--fast"]
}
```

:::note warn
`--fast`を設定しないとエディタが落ちる場合があるので注意。
ただし、`--fast`をつけるとVSCodeのコード上にエラーがたまに出てこないときがあります。
:::

VSCode以外の設定方法は、[Integrations](https://golangci-lint.run/welcome/integrations/) を参考にしてください。


## Github Action

### golangci/golangci-lint-action

https://github.com/golangci/golangci-lint-action

以下のように書くと動く。

```yml
  - uses: actions/checkout@v4
  - uses: actions/setup-go@v5
    with:
      go-version-file: go.mod
  - name: golangci-lint
    uses: golangci/golangci-lint-action@v6
```

### reviewdog/action-golangci-lint@v2

https://github.com/reviewdog/action-golangci-lint

reviewdogのgolangci-lint版。Lintで落ちた箇所に自動でレビューをしてくれる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/a01424c2-4867-bd92-6a88-1c2aa0676266.png)


自分は以下のようにしてます。


```yml
  - uses: actions/checkout@v4
  - name: Check lint
    uses: reviewdog/action-golangci-lint@v2
    with:
      go_version_file: go.mod
      github_token: ${{ secrets.github_token }}
      reporter: github-pr-review # PRにコメント
      level: error 
      filter_mode: nofilter # 変更箇所以外でエラーが出てもアノテーションをつけてくれる
      golangci_lint_flags: "--config=.golangci.toml"
      fail_on_error: true　 # lintでエラーが出たら失敗にする 
```

levelをerrorにすることで、マージできないようにすることが可能です。

:::note warn
`reviewdog/action-golangci-lint@v2`に`actions/setup-go`と`actions/cache`が入っているので事前に実行する必要はないです。
:::


# スライド

<script defer class="speakerdeck-embed" data-id="b755002341e14981b84d93c9d40c3271" data-ratio="1.7777777777777777" src="//speakerdeck.com/assets/embed.js"></script>