golangci-lint: Golang 快速 lint 工具

发布时间: 更新时间: 总字数:1176 阅读时间:3m 作者: IP上海 分享 网址

golangci-lint 支持并行运行 lint、缓存、YAML 配置,且支持与主流集成开发环境集成,并包含一百多个 lint 程序

介绍

  • 非常快:并行运行筛选器,重用 Go 构建缓存并缓存分析结果
  • 基于 YAML 的配置
  • 与 VS Code、Sublime Text、GoLand、GNU Emacs、Vim 和 GitHub Actions 集成
  • 内置大量 linters,无需安装
  • 内置默认设置,误报率最低
  • 带有颜色、源代码行和标记标识符的漂亮输出

安装

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

golangci-lint --version

# mac
brew install golangci-lint
brew upgrade golangci-lint

# Linux
直接到 https://github.com/golangci/golangci-lint/releases 下载二进制包

# go
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.1

# Docker
docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.59.1 golangci-lint run -v

help

golangci-lint --help ...
$ golangci-lint --help
Smart, fast linters runner.

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

Available Commands:
  cache       Cache control and information
  completion  Generate the autocompletion script for the specified shell
  config      Config file information
  custom      Build a version of golangci-lint with custom linters
  help        Help
  linters     List current linters configuration
  run         Run the linters
  version     Version

Flags:
      --color string   Use color when printing; can be 'always', 'auto', or 'never' (default "auto")
  -h, --help           Help for a command
  -v, --verbose        Verbose output
      --version        Print version

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

vscode 集成配置

  • 推荐 settings
"go.lintTool": "golangci-lint",
"go.lintFlags": [
  "--fast"
]

常用命令

golangci-lint run
# disable all, enable errcheck
golangci-lint run --disable-all -E errcheck

golangci-lint help linters

配置

  • 参考
  • 默认加载以下名字的配置文件
.golangci.yml
.golangci.yaml
.golangci.toml
.golangci.json

排除代码检查

var bad_name int //nolint
var bad_name int //nolint:golint,unused

//nolint
func allIssuesInThisFunctionAreExcluded() *string {
  // ...
}

//nolint:govet
var (
  a int
  b int
)

# 整个文件生效
//nolint:unparam
package pkg

示例一

.golangci.yaml ...
run:
  deadline: 12m
  timeout: 10m
  go: '1.21'

linters:
  enable:
  - depguard
  - godot
  - gofumpt
  - goimports
  - revive
  - whitespace

issues:
  exclude-rules:
  - path: _test.go
    linters:
    - errcheck

linters-settings:
  depguard:
    rules:
      Main:
        deny:
        - pkg: sync/atomic
          desc: Use go.uber.org/atomic instead of sync/atomic
        - pkg: github.com/stretchr/testify/assert
          desc: Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert
        - pkg: github.com/pkg/errors
          desc: Use fmt.Errorf instead
  errcheck:
    exclude-functions:
    - (hash.Hash).Write
  goimports:
    local-prefixes: github.com/xiexianbin/go-echo-demo
  gofumpt:
    extra-rules: true
  misspell:
    locale: US
  revive:
    rules:
    # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return
    - name: unexported-return
      severity: warning
      disabled: true

示例二

.golangci.yaml ...
# https://golangci-lint.run/usage/quick-start/
run:
  timeout: 12m
  skip-dirs:
    - dist
    - docs
    - examples
    - hack
    - manifests
    - pkg/client
    - sdks
    - ui
    - vendor
  skip-files:
    - server/static/files.go
  build-tags:
    - api
    - cli
    - cron
    - executor
    - examples
    - corefunctional
    - functional
    - plugins
linters:
  enable:
    - asasalint
    - bidichk
    - bodyclose
    - errcheck
    - exportloopref
    - goimports
    # only minor issues
    # - errorlint
    # seems to have bugs in recent version, also slow
    # - gci
    - gosec
    - gosimple
    - govet
    - ineffassign
    - misspell
    - nakedret
    - nosprintfhostport
    - reassign
    - rowserrcheck
    - sqlclosecheck
    - staticcheck
    - typecheck
    - unparam
    - unused
linters-settings:
  goimports:
    local-prefixes: github.com/argoproj/argo-workflows/
  gosec:
    includes:
      - G304
      - G307
    excludes:
      # G106: Use of ssh InsecureIgnoreHostKey should be audited
      - G106
      # G402: TLS InsecureSkipVerify set true
      - G402
      # G601: Implicit memory aliasing in for loop.
      - G601
issues:
  exclude-rules:
    - path: server/artifacts/artifact_server_test.go
      text: "response body must be closed"

示例三

.golangci.yaml ...
run:
  timeout: 5m
  skip-dirs:
    - pkg/client
    - vendor
    - "eventsources/common/naivewatcher"
  skip-files:
    - ".*generated.*"
linters:
  enable:
    - deadcode
   # - depguard
    - dogsled
    - goconst
    - gocritic
    - gofmt
    - goimports
    - goprintffuncname
    - gosimple
    - govet
    - ineffassign
    - misspell
    - nakedret
    - rowserrcheck
    - staticcheck
   # - structcheck
    - typecheck
    - unconvert
    - unused
    - varcheck
    - whitespace

示例四

.golangci.yaml ...
issues:
  exclude:
    - SA1019
    - SA5011
  exclude-rules:
    - path: "(applicationset|cmd|cmpserver|controller|pkg|reposerver|server|test)/"
      text: "require-error:"
      linters:
        - testifylint
    - path: "util/(argo|cache|cert|clusterauth|config|db|dex|git|gpg|grpc|helm|http|io|kube|kustomize|lua|notification|oidc|rbac|security|session|settings|tls|webhook)/"
      text: "require-error:"
      linters:
        - testifylint
  max-issues-per-linter: 0
  max-same-issues: 0
linters:
  enable:
    - errcheck
    - errorlint
    - gocritic
    - gofumpt
    - goimports
    - gosimple
    - govet
    - ineffassign
    - misspell
    - staticcheck
    - testifylint
    - unused
    - whitespace
linters-settings:
  gocritic:
    disabled-checks:
      - appendAssign
      - assignOp  # Keep it disabled for readability
      - badCond
      - commentFormatting
      - exitAfterDefer
      - ifElseChain
      - mapKey
      - singleCaseSwitch
      - typeSwitchVar
  goimports:
    local-prefixes: github.com/argoproj/argo-cd/v2
  testifylint:
    enable-all: true
    disable:
      - error-is-as
      - float-compare
      - go-require
run:
  timeout: 50m

与其他工具集成

Makefile

ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

.PHONY: go/deps
go/deps:
	go mod tidy

# renovate: datasource=go depName=mvdan.cc/gofumpt
GOFUMPT_VERSION := v0.6.0
gofumpt:
ifeq (, $(shell command -v gofumpt >/dev/null))
	go install mvdan.cc/gofumpt@$(GOFUMPT_VERSION)
GOFUMPT=$(GOBIN)/gofumpt
else
GOFUMPT=$(shell command -v gofumpt)
endif

# Rather than running this over and over we recommend running gofumpt on save with your editor.
# Check https://github.com/mvdan/gofumpt#installation for instructions.
.PHONY: go/fmt
go/fmt: gofumpt
	$(GOFUMPT) -l -w $(shell go list -f {{.Dir}} ./... | grep -v gen/proto)

.PHONY: go/lint
go/lint:
	golangci-lint run
.PHONY: go/test
go/test:
	go test $(SANITIZERS) -tags assert -v `go list ./...`

.PHONY: go/bench
go/bench:
	mkdir -pm 777 tmp/
	go test $(SANITIZERS) -run=. -bench=. -benchtime=1x -v `go list ./...` # run benchmark with one iteration to make sure they work

GOLANGCI_LINT_VERSION := v1.59.1
golangci-lint:
ifeq (, $(shell command -v golangci-lint >/dev/null))
	go install github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}
endif

# or
.PHONY: go/lint
go/lint: golangci-lint
	golangci-lint run --fix
  # go mod tidy
	# golangci-lint run --fix --verbose --concurrency 4 --timeout 5m --enable goimports

github actions

name: golangci-lint
on:
  push:
    tags:
      - v*
    branches:
    - main
    - release-*
  pull_request:
    branches:
    - main
    - release-*
  merge_group:
    branches:
    - main

jobs:
  lint:
    name: Go Lint
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

      - name: Set up Go
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: .go-version
          cache: false

      ...

      - name: Install dependencies
        run: make go/deps

      - name: Build
        run: make go/build

      - name: Format
        run: make go/fmt && git diff --exit-code # ':!ui/packages/app/web/build'

      - name: Lint
        run: make go/lint

扩展

gofumpt

gofumptgofmt 的基础上添加了一系列更加严格的格式化规则,并保证对 gofmt 的兼容

  • 安装
go install mvdan.cc/gofumpt@latest
  • vscode 中集成 gofumpt 配置
  "go.useLanguageServer": true,
  "gopls": {
    "formatting.gofumpt": true,
  }

参考

  1. https://golangci-lint.run/
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数