golangci-lint@静的解析¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. golangci-lintとは¶
Goの様々な静的解析ツールをまとめて実行できる。
02. CIへの導入¶
GitLab CI¶
variables:
GO_VERSION: "<Goのバージョン>"
# golangci-lintのイメージレイヤーから、使用しているGoバージョンを確認する必要がある
# @see https://hub.docker.com/layers/golangci/golangci-lint/v1.50-alpine/images/sha256-9f44001cd4ce1e9749f2f1fb63adb76787b7dfcc77cb7b54e65e74ddac4132d8?context=explore
GOLANGCI_LINT: "<golangci-lintのバージョン>"
stages:
- build
- test
go_build:
stage: build
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/golang:${GO_VERSION}
script:
# バージョンを確認する
- go version
- go mod tidy
go_lint:
stage: test
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/golangci/golangci-lint:<必要なGoのバージョンを含むイメージ>-alpine
script:
- go version
# 有効化している静的解析の一覧を表示する
# GitLab CIでは色が無効になってしまうため、有効化する
- golangci-lint linters --color always
# 静的解析を実行する
# GitLab CIでは色が無効になってしまうため、有効化する
- golangci-lint run --color always --timeout 5m
03. .golangci.yml¶
run¶
# 実行のオプションを設定する
run:
concurrency: 4
timeout: 5m
issues-exit-code: 2
# testファイルがあるか否かを設定する
tests: false
build-tags:
- mytag
skip-dirs:
- src/external_libs
- autogenerated_by_my_lib
skip-dirs-use-default: false
skip-files:
- .*\.my\.go$
- lib/bad.go
modules-download-mode: readonly
allow-parallel-runners: false
allow-serial-runners: true
print-resources-usage: true
# Goのバージョンを指定する
go: 1.20
output¶
# 結果の出力形式を設定する
output:
format: json
print-issued-lines: false
print-linter-name: false
uniq-by-line: false
path-prefix: ""
sort-results: true
linters-settings¶
# 使用するリンターにオプションを設定する
linters-settings:
# staticcheckにオプションを設定する
staticcheck:
go: 1.20
checks: [ "all" ]
...
custom:
example:
path: /path/to/example.so
description: This is an example usage of a plugin linter.
original-url: github.com/golangci/example-linter
linters¶
# 使用するリンターを選ぶ
linters:
disable-all: false
enable:
...
- gofmt
- gosec
- govet
# staticcheckを使用する
- staticcheck
...
enable-all: false
disable:
- golint
...
presets:
- bugs
- comment
- complexity
- error
- format
- import
- metalinter
- module
- performance
- sql
- style
- test
- unused
fast: true
issues¶
# 検証するルールを設定する
issues:
exclude:
- abcdef
exclude-rules:
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- path-except: _test\.go
linters:
- forbidigo
- path: internal/hmac/
text: weak cryptographic primitive
linters:
- gosec
- linters:
- staticcheck
text: "SA9003:"
- linters:
- lll
source: "^//go:generate "
exclude-use-default: false
exclude-case-sensitive: false
include:
- EXC0001
- EXC0002
- EXC0003
- EXC0004
- EXC0005
- EXC0006
- EXC0007
- EXC0008
- EXC0009
- EXC0010
- EXC0011
- EXC0012
- EXC0013
- EXC0014
- EXC0015
max-issues-per-linter: 0
max-same-issues: 0
new: true
new-from-rev: HEAD
new-from-patch: path/to/patch/file
fix: true
whole-files: true
severity¶
# 重要度を設定する
severity:
default-severity: error
case-sensitive: true
rules:
- linters:
- dupl
severity: info
04. コマンド¶
グローバル¶
▼ --color¶
コマンドの実行結果に色をつける。
CIによっては、実行時に色がなくなってしまうが、always
を有効化すると色がつくようになる。
$ golangci-lint linters --color always
run¶
▼ --go¶
Goのバージョンを指定して実行する。
$ golangci-lint run --go <バージョン>
▼ --config¶
設定ファイルを指定する。
$ golangci-lint run --config .golangci.yml
linters¶
有効/無効になっている解析の一覧を取得できる。
$ golangci-lint linters
# Enabled by your configuration 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 your configuration linters:
asasalint: check for pass []any as any in variadic func(...any) [fast: false, auto-fix: false]
asciicheck: checks that all code identifiers does not have non-ASCII symbols in the name [fast: true, auto-fix: false]
...
05. コメントアウト¶
静的解析の無視¶
▼ プロジェクト全体¶
linters-settings:
staticcheck:
checks:
- all
# マイナスをつけると無視できる
- "-SA1000"
- "-SA1004"
▼ 特定のパス¶
issues:
exclude-rules:
- path-except: '(.+)_test\.go'
linters:
- staticcheck
▼ 特定のファイル¶
//nolint:staticcheck
package pkg
▼ 特定のコード¶
コメントアウトのコードに対して、指定した番号の静的解析を無視する。
注意点として、各ツールの用意しているignoreコメントではなく、golangci-lint専用のコメントである。
特定の番号 (例:SA1019
) を無視することは難しそう。
package grpc
import (
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/filters"
"google.golang.org/grpc"
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
)
// ChainUnaryServerInterceptor gRPCサーバー側の計装に必要なUnaryServerInterceptorをチェインする
// NOTE:
// このミドルウェアを実行すると、リクエストを単位としてスパンを自動的に開始/終了できる
func ChainUnaryServerInterceptor(opts ...otelgrpc.Option) grpc.ServerOption {
return grpc.ChainUnaryInterceptor(
grpc_recovery.UnaryServerInterceptor(),
//nolint:staticcheck // NewServerHandlerが推奨となっているが、実装時点 (2027/07/02) のバージョンではNewServerHandlerはオプションが少ないため、止むを得ず非推奨のUnaryServerInterceptorを使う
otelgrpc.UnaryServerInterceptor(
append(opts, []otelgrpc.Option{
InterceptorFilterHealthCheck(),
}...)...,
),
)
}
// ChainStreamServerInterceptor gRPCサーバー側の計装に必要なStreamServerInterceptorをチェインする
// NOTE:
// このミドルウェアを実行すると、リクエストを単位としてスパンを自動的に開始/終了できる
func ChainStreamServerInterceptor(opts ...otelgrpc.Option) grpc.ServerOption {
return grpc.ChainStreamInterceptor(
grpc_recovery.StreamServerInterceptor(),
//nolint:staticcheck // NewServerHandlerが推奨となっているが、実装時点 (2027/07/02) のバージョンではNewServerHandlerはオプションが少ないため、止むを得ず非推奨のStreamServerInterceptorを使う
otelgrpc.StreamServerInterceptor(
append(opts, []otelgrpc.Option{
InterceptorFilterHealthCheck(),
}...)...,
),
)
}
// InterceptorFilterHealthCheck ヘルスチェックパスではスパンを作成しない
func InterceptorFilterHealthCheck() otelgrpc.Option {
//nolint:staticcheck // gRPCのstats handlerが推奨となっているが、実装時点 (2027/07/02) のバージョンではstats handlerはオプションが少ないため、止むを得ず非推奨のWithInterceptorFilterを使う
return otelgrpc.WithInterceptorFilter(filters.Not(filters.HealthCheck()))
}