こんにちは。Tomoyuki(@tomoyuki65)です。
Go言語(Golang)には標準のformatter(go fmt)やlint(go vet)が使えるようになっていますが、実務では他にも定番のライブラリがよく使われたりします。
その際に各種定番ライブラリをまとめて使えるようにする「統合Lintツール」として、「golangci-lint」というのがあり、これを使うと便利です。
この記事では、そんなgolangci-lintの使い方についてご紹介します。
Go言語(Golang)golangci-lintの使い方|おすすめformatter・lintの設定方法
まずはDockerで開発環境を構築するため、以下のコマンドを実行して各種ファイルを作成します。
$ mkdir go-golangci-lint && cd go-golangci-lint
$ mkdir src && touch src/main.go
$ touch Dockerfile compose.yml
次に作成したファイルをそれぞれ以下のように記述します。
・「Dockerfile」
FROM golang:1.26-alpine3.23
# インストール可能なパッケージ一覧の更新
RUN apk update && \
apk upgrade && \
# パッケージのインストール(--no-cacheでキャッシュ削除)
apk add --no-cache \
curl
WORKDIR /go/src
COPY ./src .
# go.modがあれば依存関係をインストール
RUN if [ -f ./go.mod ]; then \
go install; \
fi
# 開発用のライブラリをインストール
RUN curl -sSfL https://golangci-lint.run/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.12.2
EXPOSE 8080
※今回はGoのバージョン「1.26」、golangci-lintのバージョンは「v2.12.2」を使います。またgolangci-lintのインストールにはcurlコマンドが必要です。
・「compose.yml」
services:
go-dev:
container_name: go-script
build:
context: .
dockerfile: ./Dockerfile
volumes:
- ./src:/go/src
ports:
- "8080:8080"
tty: true
stdin_open: true
・「src/main.go」
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World !!")
}
次に以下のコマンドを実行し、Dockerコンテナのビルドを行います。
$ docker compose build --no-cache
次に以下のコマンドを実行し、goの初期化を行います。
$ docker compose run --rm go-dev go mod init go-golangci-lint
次に以下のコマンドを実行し、スクリプトを実行して試します。
$ docker compose run --rm go-dev go run main.go
コマンド実行後、「Hello World !!」が出力されればOKです。

golangci-lintの設定
次にgolangci-lintの設定をするため、以下のコマンドを実行して設定用のファイルを作成します。
$ touch src/.golangci.yml
次に作成したファイルを以下のように記述します。
・「src/.golangci.yml」
version: "2"
run:
# タイムアウト設定
timeout: 5m
formatters:
# 実行するformatterを指定
enable:
- gofumpt
- goimports
linters:
# デフォルト設定を全てOFF
default: none
# 実行するlintを指定
enable:
- govet
- staticcheck
- gosec
※最小構成で試します。
・goimports:import整理 + 不足import自動追加
・govet:Go標準の静的コード解析
・staticcheck:高性能静的コード解析
・gosec:セキュリティ問題を検出する静的コード解析
golangci-lintを試す
次にフォーマット修正や静的コード解析でのエラーを試すため、ファイル「src/main.go」を以下のように修正します。
package main
import (
"fmt"
)
func main() {
x := []int{1, 2, 3}
for _, v := range x {
fmt.Sprintf("%d", v)
}
}
次に以下のコマンドを実行し、エラーが出ることを確認します。
$ docker compose run --rm go-dev golangci-lint run ./...
※詳細を確認したい場合はオプション「-v」を付けて実行して下さい。
実行後、以下のようにエラーが表示されればOKです。

次に以下のコマンドを実行し、フォーマット修正を行います。
$ docker compose run --rm go-dev golangci-lint fmt ./...
実行後、ファイル「src/main.go」のフォーマットが以下のように修正されればOKです。

次に再度以下のコマンドを実行し、結果を確認します。
$ docker compose run --rm go-dev golangci-lint run ./...
実行後、以下のようにフォーマットのエラーが解消すればOKです。

次にファイル「src/main.go」を以下のように修正します。
package main
import (
"fmt"
)
func main() {
x := []int{1, 2, 3}
for _, v := range x {
fmt.Printf("%d\n", v)
}
}
次に再度以下のコマンドを実行し、結果を確認します。
$ docker compose run --rm go-dev golangci-lint run ./...
実行後、以下のように静的コード解析のエラーが解消すればOKです。

最後に以下のコマンドを実行し、スクリプトを試します。
$ docker compose run --rm go-dev go run main.go
実行後、以下のように表示されればOKです。

利用可能なformatterやlintを確認する方法
以下のコマンドを実行し、利用可能なformatterやlintを確認することが可能です。
・利用可能なformatterを確認
$ docker compose run --rm go-dev golangci-lint formatters
実行結果例

※Enabled by your configuration formattersにあるのが有効なもので、Disabled by your configuration formattersにあるのが無効になっているものです。
・利用可能なlintを確認
$ docker compose run --rm go-dev golangci-lint linters
実行結果例


※Enabled by your configuration lintersにあるのが有効なもので、Disabled by your configuration lintersにあるのが無効になっているものです。
その他の利用可能なformatter一覧
| formatter名 | 説明 |
|---|---|
| gci | import順序やグループを整理する formatter |
| gofmt | Go標準のコード整形を行う |
| golines | 長い行を自動で折り返して整形する |
| swaggo | swaggo コメント形式を整形・検証する |
その他の利用可能なlint一覧
| lint名 | 説明 |
|---|---|
| arangolint | ArangoDB client のベストプラクティスを検証する |
| asasalint | []any の誤った variadic 渡しを検出する |
| asciicheck | 非ASCII識別子を検出する |
| bidichk | 危険なUnicode文字列を検出する |
| bodyclose | HTTPレスポンスの Close 忘れを検出する |
| canonicalheader | HTTPヘッダー名を正規形式に統一する |
| clickhouselint | ClickHouse driver の誤用を検出する |
| containedctx | struct内の context.Context 保持を検出する |
| contextcheck | context.Context の伝播漏れを検出する |
| copyloopvar | loop変数コピーの事故を検出する |
| cyclop | 循環複雑度をチェックする |
| decorder | 宣言順序をチェックする |
| depguard | 禁止 package import を制御する |
| dogsled | blank identifier 多用を検出する |
| dupl | 重複コードを検出する |
| dupword | 重複単語を検出する |
| durationcheck | duration の誤演算を検出する |
| embeddedstructfieldcheck | embedded field 配置をチェックする |
| err113 | error handling の規約違反を検出する |
| errcheck | error戻り値の未確認を検出する |
| errchkjson | json encode/decode 問題を検出する |
| errname | error命名規則を検証する |
| errorlint | error wrapping 問題を検出する |
| exhaustive | switch網羅漏れを検出する |
| exhaustruct | struct初期化漏れを検出する |
| exptostd | x/exp から stdlib 置換可能箇所を検出する |
| fatcontext | 不要な context ネストを検出する |
| forbidigo | 禁止 identifier を検出する |
| forcetypeassert | panicしうる型アサーションを検出する |
| funcorder | 関数順序をチェックする |
| funlen | 長すぎる関数を検出する |
| ginkgolinter | ginkgo/gomega の misuse を検出する |
| gocheckcompilerdirectives | //go: directive の不正を検出する |
| gochecknoglobals | グローバル変数使用を検出する |
| gochecknoinits | init関数使用を検出する |
| gochecksumtype | sum type の exhaustiveness を検証する |
| gocognit | 認知的複雑度をチェックする |
| goconst | 定数化可能な重複文字列を検出する |
| gocritic | バグ・性能・スタイル問題を広く検出する |
| gocyclo | 循環複雑度を測定する |
| godoclint | GoDocコメント規約を検証する |
| godot | コメント末尾ピリオドを検証する |
| godox | TODO/FIXME コメントを検出する |
| goheader | ファイルヘッダーを検証する |
| gomoddirectives | go.mod directive を検証する |
| gomodguard_v2 | 依存 module 制限を行う |
| goprintffuncname | printf系関数命名を検証する |
| gosmopolitan | i18n/l10n anti-pattern を検出する |
| grouper | 式グループ化を分析する |
| iface | interface乱用を検出する |
| importas | import alias を統一する |
| inamedparam | interface の unnamed parameter を検出する |
| ineffassign | 無意味な代入を検出する |
| interfacebloat | 巨大interfaceを検出する |
| intrange | integer range 化可能な loop を検出する |
| iotamixing | iota混在 const を検出する |
| ireturn | interface返却乱用を検出する |
| lll | 長すぎる行を検出する |
| loggercheck | logger key/value ミスを検出する |
| maintidx | 保守性指数を測定する |
| makezero | slice初期化ミスを検出する |
| mirror | bytes/string mirror misuse を検出する |
| misspell | 英単語スペルミスを検出する |
| mnd | マジックナンバーを検出する |
| modernize | modern Go 書き方を提案する |
| musttag | struct tag 漏れを検出する |
| nakedret | 長い naked return を検出する |
| nestif | 深い if ネストを検出する |
| nilerr | err確認後の nil返却バグを検出する |
| nilnesserr | 異常な nil error 判定を検出する |
| nilnil | nil,nil の曖昧返却を検出する |
| nlreturn | return前空行を統一する |
| noctx | context.Context 未使用を検出する |
| noinlineerr | inline error handling を禁止する |
| nolintlint | nolint misuse を検出する |
| nonamedreturns | named return を禁止する |
| nosprintfhostport | Sprintf host:port misuse を検出する |
| paralleltest | t.Parallel() 忘れを検出する |
| perfsprint | fmt.Sprintf の低速利用を検出する |
| prealloc | slice事前確保漏れを検出する |
| predeclared | 組み込み識別子 shadowing を検出する |
| promlinter | Prometheus metrics 命名を検証する |
| protogetter | proto getter 未使用を検出する |
| reassign | package変数再代入を検出する |
| recvcheck | receiver type 一貫性を検証する |
| revive | Goスタイル・品質を広くチェックする |
| rowserrcheck | rows.Err() 未確認を検出する |
| sloglint | log/slog の使い方を統一する |
| spancheck | OpenTelemetry span misuse を検出する |
| sqlclosecheck | DB Rows/Stmt の Close漏れを検出する |
| tagalign | struct tag 整列を行う |
| tagliatelle | struct tag 命名規則を検証する |
| testableexamples | Example test 実行可能性を検証する |
| testifylint | testify misuse を検出する |
| testpackage | 別 package test を強制する |
| thelper | t.Helper() 忘れを検出する |
| tparallel | 誤った t.Parallel() 使用を検出する |
| unconvert | 不要な型変換を検出する |
| unparam | 未使用引数を検出する |
| unqueryvet | SELECT * 使用を検出する |
| unused | 未使用コードを検出する |
| usestdlibvars | 標準ライブラリ定数利用を推奨する |
| usetesting | testing package misuse を検出する |
| varnamelen | 変数名長さをチェックする |
| wastedassign | 無駄な代入を検出する |
| whitespace | 不要空行を整理する |
| wrapcheck | 外部 error wrapping 漏れを検出する |
| wsl_v5 | 空行スタイルを統一する |
| zerologlint | zerolog misuse を検出する |
| gomodguard | 依存 module 制限を行う(deprecated) |
| wsl | 空行スタイルを統一する(deprecated) |
※数が多いですが、基本的には上記で試した最小構成でも十分なので、もし追加したいものがあれば別途確認して少しずつ導入するようにして下さい。
最後に
今回はgolangci-lintの使い方についてご紹介しました。
私も今まで「go fmt」や「staticcheck」を個別に使っていましたが、次からはgolangci-lintに統一していこうと思います。
Go言語のformatterやlintを利用する際におすすめのライブラリなので、よければぜひ参考にしてみて下さい。


コメント