GolangCI-Lint配置变更实践

GolangCI-Lint配置变更实践

Golang编程中,为了便于调试和代码质量和安全性检查。利用该方法可以在开发周期的早期捕获错误,并且检查团队编程风格,提高一致性。这对团队协作开发特别有用,可以提高开发的效率,保持代码质量和安全性。
本实践所有测试内容都使用以下代码进行测试

go 复制代码
package main
 
import (
    "database/sql"
    "fmt"
    "log"
    "net/http"
    "strings"
 
    _ "github.com/go-sql-driver/mysql"
)
 
var db *sql.DB
 
func main() {
    // 连接到数据库
    var err error
    db, err = sql.Open("mysql", "username:password@tcp(localhost:3306)/mydatabase")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
 
    http.HandleFunc("/search", searchHandler)
    http.ListenAndServe(":8080", nil)
}
 
func searchHandler(w http.ResponseWriter, r *http.Request) {
    query := r.URL.Query().Get("query")
 
    // 构建SQL查询字符串(易受SQL注入攻击)
    sqlQuery := "SELECT name, age FROM users WHERE name = '" + query + "'"
 
    rows, err := db.Query(sqlQuery)
    if err != nil {
        log.Println("Error executing query:", err)
        return
    }
    defer rows.Close()
 
    var name string
    var age int
    for rows.Next() {
        err := rows.Scan(&name, &age)
        if err != nil {
            log.Println("Error scanning row:", err)
            continue
        }
        fmt.Fprintf(w, "Name: %s, Age: %d\n", name, age)
    }
}

概述

开发更全面的linting工具的是golang社区的一个热门开发领域。社区产生了大量的linter模块,每个都有特定的目的。比如:

Unused:用于检查Golang代码中未使用的常量、变量、函数和类型。

Goconst:查找可以被常量替换的重复字符串。

Gocyclo:计算并检查函数的cyclomatic复杂度。

Errcheck:检测Golang代码中无法检查到的错误。

面对这么多的linting模块,开发者必须自己下载每个单独的linter并管理它们的版本。此外,按顺序运行它们中的每一个可能太慢,因此引入了golang ci-lint,这是一个并行运行linters的 Go linters 聚合器,重用Go构建缓存,并缓存分析结果以大大提高后续运行的性能。

出于方便和性能原因,该项目旨在并行聚合和运行多个单独的linter。当安装该程序时,将获得大约48个linter检查器,用户可以继续挑选特定的检查器以适合自己的实际情况和需求。除了能够在开发调试时候在本地运行之外,还可以将linting加入到CI/CD和DevOps流程中,自动的、持续集成的进行检查测试。

安装

使用go install 安装golangci-lint,支持在有golang开发环境的任何操作系统上本地安装。也可以在官方下载特定操作系统下的二进制包安装。

比如在macOS下可以使用brew安装:

bash 复制代码
brew install golangci-lint
brew upgrade golangci-lint

简单用法

安装后,通过以下命令查看版本:

bash 复制代码
golangci-lint version
golangci-lint has version 1.55.1 built with go1.21.3 from 9b20d49 on 2023-10-24T12:38:15Z

可以通过 help linter命令查看当前启用的linter规则,可以看到gosec默认是关闭的:

复制代码
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 (megacheck): Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
govet (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false]
ineffassign: Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
staticcheck (megacheck): 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 (megacheck): 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]
asciicheck: Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
bidichk: Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
bodyclose: checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
containedctx: containedctx is a linter that detects struct contained context.Context field [fast: false, auto-fix: false]
contextcheck: check whether the function uses a non-inherited context [fast: false, auto-fix: false]
cyclop: checks function and package cyclomatic complexity [fast: false, auto-fix: false]
deadcode [deprecated]: Finds unused code [fast: false, auto-fix: false]
decorder: check declaration order and count of types, constants, variables and functions [fast: true, auto-fix: false]
depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
dogsled: Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
dupl: Tool for code clone detection [fast: true, auto-fix: false]
dupword: checks for duplicate words in the source code [fast: true, auto-fix: true]
durationcheck: check for two durations multiplied together [fast: false, auto-fix: false]
errchkjson: Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted. [fast: false, auto-fix: false]
errname: Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. [fast: false, auto-fix: false]
errorlint: errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. [fast: false, auto-fix: false]
execinquery: execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds [fast: false, auto-fix: false]
exhaustive: check exhaustiveness of enum switch statements [fast: false, auto-fix: false]
exhaustivestruct [deprecated]: Checks if all struct's fields are initialized [fast: false, auto-fix: false]
exhaustruct: Checks if all structure fields are initialized [fast: false, auto-fix: false]
exportloopref: checks for pointers to enclosing loop variables [fast: false, auto-fix: false]
forbidigo: Forbids identifiers [fast: false, auto-fix: false]
forcetypeassert: finds forced type assertions [fast: true, auto-fix: false]
funlen: Tool for detection of long functions [fast: true, auto-fix: false]
gci: Gci controls Go package import order and makes it always deterministic. [fast: true, auto-fix: false]
ginkgolinter: enforces standards of using ginkgo and gomega [fast: false, auto-fix: false]
gocheckcompilerdirectives: Checks that go compiler directive comments (//go:) are valid. [fast: true, auto-fix: false]
gochecknoglobals: check that no global variables exist [fast: false, auto-fix: false]
gochecknoinits: Checks that no init functions are present in Go code [fast: true, auto-fix: false]
gochecksumtype: Run exhaustiveness checks on Go "sum types" [fast: false, auto-fix: false]
gocognit: Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
goconst: Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
gocritic: Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false]
gocyclo: Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
godot: Check if comments end in a period [fast: true, auto-fix: true]
godox: Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
goerr113: Go linter to check the errors handling expressions [fast: false, auto-fix: false]
gofmt: Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
gofumpt: Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
goheader: Checks is file header matches to pattern [fast: true, auto-fix: false]
goimports: Check import statements are formatted according to the 'goimport' command. Reformat imports in autofix mode. [fast: true, auto-fix: true]
golint [deprecated]: Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes [fast: false, auto-fix: false]
gomnd: An analyzer to detect magic numbers. [fast: true, auto-fix: false]
gomoddirectives: Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
gomodguard: Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false]
goprintffuncname: Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
gosec (gas): Inspects source code for security problems [fast: false, auto-fix: false]
gosmopolitan: Report certain i18n/l10n anti-patterns in your Go codebase [fast: false, auto-fix: false]
grouper: An analyzer to analyze expression groups. [fast: true, auto-fix: false]
ifshort [deprecated]: Checks that your code uses short syntax for if-statements whenever possible [fast: true, auto-fix: false]
importas: Enforces consistent import aliases [fast: false, auto-fix: false]
inamedparam: reports interfaces with unnamed method parameters [fast: true, auto-fix: false]
interfacebloat: A linter that checks the number of methods inside an interface. [fast: true, auto-fix: false]
interfacer [deprecated]: Linter that suggests narrower interface types [fast: false, auto-fix: false]
ireturn: Accept Interfaces, Return Concrete Types [fast: false, auto-fix: false]
lll: Reports long lines [fast: true, auto-fix: false]
loggercheck (logrlint): Checks key value pairs for common logger libraries (kitlog,klog,logr,zap). [fast: false, auto-fix: false]
maintidx: maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
makezero: Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
maligned [deprecated]: Tool to detect Go structs that would take less memory if their fields were sorted [fast: false, auto-fix: false]
mirror: reports wrong mirror patterns of bytes/strings usage [fast: false, auto-fix: false]
misspell: Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
musttag: enforce field tags in (un)marshaled structs [fast: false, auto-fix: false]
nakedret: Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
nestif: Reports deeply nested if statements [fast: true, auto-fix: false]
nilerr: Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false]
nilnil: Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false]
nlreturn: nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false]
noctx: noctx finds sending http request without context.Context [fast: false, auto-fix: false]
nolintlint: Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
nonamedreturns: Reports all named returns [fast: false, auto-fix: false]
nosnakecase [deprecated]: nosnakecase is a linter that detects snake case of variable naming and function name. [fast: true, auto-fix: false]
nosprintfhostport: Checks for misuse of Sprintf to construct a host with port in a URL. [fast: true, auto-fix: false]
paralleltest: paralleltest detects missing usage of t.Parallel() method in your Go test [fast: false, auto-fix: false]
perfsprint: Checks that fmt.Sprintf can be replaced with a faster alternative. [fast: false, auto-fix: false]
prealloc: Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false]
predeclared: find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false]
promlinter: Check Prometheus metrics naming via promlint [fast: true, auto-fix: false]
protogetter: Reports direct reads from proto message fields when getters should be used [fast: false, auto-fix: true]
reassign: Checks that package variables are not reassigned [fast: false, auto-fix: false]
revive: Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false]
rowserrcheck: checks whether Err of rows is checked successfully [fast: false, auto-fix: false]
scopelint [deprecated]: Scopelint checks for unpinned variables in go programs [fast: true, auto-fix: false]
sloglint: ensure consistent code style when using log/slog [fast: false, auto-fix: false]
sqlclosecheck: Checks that sql.Rows and sql.Stmt are closed. [fast: false, auto-fix: false]
structcheck [deprecated]: Finds unused struct fields [fast: false, auto-fix: false]
stylecheck: Stylecheck is a replacement for golint [fast: false, auto-fix: false]
tagalign: check that struct tags are well aligned [fast: true, auto-fix: true]
tagliatelle: Checks the struct tags. [fast: true, auto-fix: false]
tenv: tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 [fast: false, auto-fix: false]
testableexamples: linter checks if examples are testable (have an expected output) [fast: true, auto-fix: false]
testifylint: Checks usage of github.com/stretchr/testify. [fast: false, auto-fix: false]
testpackage: linter that makes you use a separate _test package [fast: true, auto-fix: false]
thelper: thelper detects Go test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false]
tparallel: tparallel detects inappropriate usage of t.Parallel() method in your Go test codes [fast: false, auto-fix: false]
unconvert: Remove unnecessary type conversions [fast: false, auto-fix: false]
unparam: Reports unused function parameters [fast: false, auto-fix: false]
usestdlibvars: A linter that detect the possibility to use variables/constants from the Go standard library. [fast: true, auto-fix: false]
varcheck [deprecated]: Finds unused global variables and constants [fast: false, auto-fix: false]
varnamelen: checks that the length of a variable's name matches its scope [fast: false, auto-fix: false]
wastedassign: wastedassign finds wasted assignment statements. [fast: false, auto-fix: false]
whitespace: Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true]
wrapcheck: Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
wsl: Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false]
zerologlint: Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg`. [fast: false, auto-fix: false]

Linters presets:
bugs: asasalint, asciicheck, bidichk, bodyclose, contextcheck, durationcheck, errcheck, errchkjson, errorlint, exhaustive, exportloopref, gocheckcompilerdirectives, gochecksumtype, gosec, gosmopolitan, govet, loggercheck, makezero, musttag, nilerr, noctx, protogetter, reassign, rowserrcheck, sqlclosecheck, staticcheck, testifylint, zerologlint
comment: dupword, godot, godox, misspell
complexity: cyclop, funlen, gocognit, gocyclo, maintidx, nestif
error: errcheck, errorlint, goerr113, wrapcheck
format: decorder, gci, gofmt, gofumpt, goimports, sloglint, tagalign
import: depguard, gci, goimports, gomodguard
metalinter: gocritic, govet, revive, staticcheck
module: depguard, gomoddirectives, gomodguard
performance: bodyclose, noctx, perfsprint, prealloc
sql: execinquery, rowserrcheck, sqlclosecheck
style: asciicheck, containedctx, decorder, depguard, dogsled, dupl, errname, exhaustruct, forbidigo, forcetypeassert, ginkgolinter, gochecknoglobals, gochecknoinits, goconst, gocritic, godot, godox, goerr113, goheader, gomnd, gomoddirectives, gomodguard, goprintffuncname, gosimple, grouper, importas, inamedparam, interfacebloat, ireturn, lll, loggercheck, makezero, mirror, misspell, musttag, nakedret, nilnil, nlreturn, nolintlint, nonamedreturns, nosprintfhostport, paralleltest, predeclared, promlinter, revive, sloglint, stylecheck, tagalign, tagliatelle, tenv, testpackage, thelper, tparallel, unconvert, usestdlibvars, varnamelen, wastedassign, whitespace, wrapcheck, wsl
test: exhaustruct, paralleltest, testableexamples, testifylint, testpackage, tparallel
unused: ineffassign, unparam, unused

在项目目录的根目录下通过golangci-lint run运行,即可进行linters检查,如果有问题,就会打印对应的错误信息,记录该问题所有上下文,包括问题的简短描述,以及出现问题的文件和行号。

由于默认不开启gosec,所以只能扫描出一条:

bash 复制代码
golangci-lint run
main.go:23:21: Error return value of `http.ListenAndServe` is not checked (errcheck) http.ListenAndServe(":8080", nil)

golangci-lint的报告,默认提供高亮显示,对代码行和标记的标识符都用不同颜色表示,可以方便快捷地获得关键信息。

也可以指定文件和目录检查,其语法如下:

bash 复制代码
golangci-lint run cc1 dir2 dir3/test.go

配置

GolangCI-Lint可以针对不同用例提供灵活多样的配置。可以通过命令行选项或配置文件进行配置。注意命令行参数具有较高优先级,覆盖掉配置文件中的配置项目。基本示例:

bash 复制代码
golangci-lint run --disable-all -E revive -E errcheck -E nilerr -E gosec

可以通过help linters当前情况下预设的规则:

bash 复制代码
golangci-lint help linters | sed -n '/Linters presets:/,$p'
Linters presets:
bugs: asasalint, asciicheck, bidichk, bodyclose, contextcheck, durationcheck, errcheck, errchkjson, errorlint, exhaustive, exportloopref, gocheckcompilerdirectives, gochecksumtype, gosec, gosmopolitan, govet, loggercheck, makezero, musttag, nilerr, noctx, protogetter, reassign, rowserrcheck, sqlclosecheck, staticcheck, testifylint, zerologlint
comment: dupword, godot, godox, misspell
complexity: cyclop, funlen, gocognit, gocyclo, maintidx, nestif
error: errcheck, errorlint, goerr113, wrapcheck
format: decorder, gci, gofmt, gofumpt, goimports, sloglint, tagalign
import: depguard, gci, goimports, gomodguard
metalinter: gocritic, govet, revive, staticcheck
module: depguard, gomoddirectives, gomodguard
performance: bodyclose, noctx, perfsprint, prealloc
sql: execinquery, rowserrcheck, sqlclosecheck
style: asciicheck, containedctx, decorder, depguard, dogsled, dupl, errname, exhaustruct, forbidigo, forcetypeassert, ginkgolinter, gochecknoglobals, gochecknoinits, goconst, gocritic, godot, godox, goerr113, goheader, gomnd, gomoddirectives, gomodguard, goprintffuncname, gosimple, grouper, importas, inamedparam, interfacebloat, ireturn, lll, loggercheck, makezero, mirror, misspell, musttag, nakedret, nilnil, nlreturn, nolintlint, nonamedreturns, nosprintfhostport, paralleltest, predeclared, promlinter, revive, sloglint, stylecheck, tagalign, tagliatelle, tenv, testpackage, thelper, tparallel, unconvert, usestdlibvars, varnamelen, wastedassign, whitespace, wrapcheck, wsl
test: exhaustruct, paralleltest, testableexamples, testifylint, testpackage, tparallel
unused: ineffassign, unparam, unused

可以通过-p 或者-presetor标志来运行预设:

bash 复制代码
golangci-lint run -p bugs -p error

针对项目,可以通过项目配置来进行预设配置特定的linter选项,而这是通过命令行选项无法实现的。配置文件格式可以支持yml、toml或json格式,为了方便建议使用yml格式,即.golangci.yml或.golangci.yaml文件。只需在项目目录的根目录中创建项目特定的配置。程序将自动在要检查的文件的目录中查找它们,并在可以继承查询父目录中的配置。一个典型的.golangci.yml配置如下(注意yml格式的缩进):

yaml 复制代码
linters:
  enable-all: true
  disable:
    - maligned
    - prealloc
  fast: false

配置解释说明:

enable-all: true:这表示启用所有可用的代码检查规则。当设置为true时,将启用所有代码检查规则,这意味着代码检查工具将检查代码中的所有问题。

disable:这是一个列出要禁用的具体代码检查规则的部分。在示例中,禁用了两个规则:maligned 和 prealloc。这意味着代码检查工具不会检查和报告与这两个规则相关的问题。

fast: false:这是一个控制代码检查工具的速度和精度之间权衡的选项。如果设置为false,代码检查工具将更加准确,但可能运行得较慢。如果设置为true,代码检查工具可能牺牲一些准确性以提高速度。

可以明显的看到配置了.golangci.yml 后,扫描结果明显增多:

注释忽略

有时针对个定的linting问题需要临时忽略其显示,可以通过nolint标志或者配置文件中设置忽略项来说实现。

直接执行golangci-lint run -E gosec

linter规则中提示了一个 SQL 注入风险 (G201: SQL string formatting)。

go 复制代码
func searchHandler(w http.ResponseWriter, r *http.Request) {
    dealerId := r.URL.Query().Get("dealerId")
    if dealerId == "" {
        fmt.Fprint(w, "Please provide a search query.")
        return
    }
    table := fmt.Sprintf("risk_investigate_record a join (select max(I_ID) as MAX_ID from risk_investigate_record where ch_dealer_id ='%s' group by I_TOP_REF )b on a.I_ID = b.MAX_ID ", dealerId) //nolint
    rows, err := db.Query(table)
    if err != nil {
        fmt.Fprint(w, "An error occurred.")
        return
    }
    defer rows.Close()
}

通过由//nolint注释,就可以告诉linting检查器忽略对该行的检查。也可以通过//nolint:xxx(比如gosec)忽略特定的linting检查:

除了按照行来忽略,也支持通过代码块(比如函数,{})来设置忽略:

go 复制代码
//nolint
func aFunc() {
}

对整个源文件,可以通过在其开头注释,可以让检查器忽略对该文件的检查:

go 复制代码
//nolint:govet,errcheck
package main

排除规则

可以在配置文件中指定排除规则,以便更精细地控制哪些文件被检查,以及报告哪些问题。例如,可以设置不检查某些测试文件 (_test.go)上运行,或者禁止在项目范围内产生某些错误。

相关推荐
资深web全栈开发14 小时前
并查集(Union-Find)套路详解
leetcode·golang·并查集·unionfind
moxiaoran575316 小时前
Go语言的递归函数
开发语言·后端·golang
朝花不迟暮16 小时前
Go基础-闭包
android·开发语言·golang
西京刀客18 小时前
go语言-切片排序之sort.Slice 和 sort.SliceStable 的区别(数据库分页、内存分页场景注意点)
后端·golang·sort·数据库分页·内存分页
黄昏单车19 小时前
golang语言基础到进阶学习笔记
笔记·golang·go
moxiaoran57531 天前
Go语言结构体
开发语言·后端·golang
Tony Bai2 天前
Cloudflare 2025 年度报告发布——Go 语言再次“屠榜”API 领域,AI 流量激增!
开发语言·人工智能·后端·golang
小徐Chao努力2 天前
Go语言核心知识点底层原理教程【变量、类型与常量】
开发语言·后端·golang
锥锋骚年2 天前
go语言异常处理方案
开发语言·后端·golang
moxiaoran57532 天前
Go语言的map
开发语言·后端·golang