可用于 Go
语言代码分析的工具有很多,比如 golint
、gofmt
、misspell
等,如果一一引用配置,就会比较烦琐,所以通常我们不会单独地使用它们,而是使用 golangci-lint
。
官网地址: https://github.com/golangci/golangci-lint
golangci-lint
是一个集成工具,它集成了很多静态代码分析工具,便于我们使用。有以下特点:
golangci-lint
是基于 gometalinter
开发的,但是平均速度要比 gometalinter
快 5 倍。速度快的原因有三个:可以并行检查代码;可以复用 go build
缓存;会缓存分析结果。可配置:支持 YAML
格式的配置文件,让检查更灵活,更可控。IDE
集成:可以集成进多个主流的 IDE
,例如 VS Code
、GNU Emacs
、Sublime Text
、Goland
等。linter
聚合器:1.41.1 版本集成了 76 个 linter
,并且还支持自定义 linter
。最小的误报数:调整了所集成 linter
的默认设置,大幅度减少了误报。良好的输出:输出的结果带有颜色、代码行号和 linter
标识,易于查看和定位。当前更新迭代速度很快,不断有新的 linter
被集成。
1. 安装
如果要使用 golangci-lint
,首先需要安装。因为 golangci-lint
本身就是 Go
语言编写的,所以我们可以从源代码安装它,打开终端,输入如下命令即可安装。
go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.35.2
使用这一命令安装的是 v1.35.2 版本的 golangci-lint
,
如不能成功安装,则使用下面命令:
# binary will be $(go env GOPATH)/bin/golangci-lint
$ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.35.2
golangci/golangci-lint info checking GitHub for tag 'v1.35.2'
golangci/golangci-lint info found version: 1.35.2 for v1.35.2/linux/amd64
golangci/golangci-lint info installed /home/wohu/gocode/bin/golangci-lint
或者参考:https://blog.csdn.net/txl910514/article/details/105880125
如果还是安装失败,采用以下方法,下载源码,执行安装脚本
cd $GOPATH/src/github.com
git clone https://github.com/golangci/golangci-lint.git
cd golangci-lint/
chmod +x install.sh
sh install.sh -b $(go env GOPATH)/bin v1.38.0
安装完成后,在终端输入如下命令,检测是否安装成功。
$ golangci-lint --version
golangci-lint has version 1.35.2 built from 1da5701 on 2021-01-11T02:54:03Z
2. 支持命令和全局选项
可以通过执行 golangci-lint -h
查看其用法,golangci-lint
支持的子命令见下表
此外,golangci-lint
还支持一些全局选项。全局选项是指适用于所有子命令的选项,golangci-lint
支持的全局选项如下:
run
命令执行 golangci-lint
,对代码进行检查,是 golangci-lint
最为核心的一个命令。run
没有子命令,但有很多选项。
golangci-lint run 支持很多命令行选项,可通过golangci-lint run -h查看,这里选择一些比较重要的选项进行介绍,见下表:
cache
命令用来进行缓存控制,并打印缓存的信息。它包含两个子命令:
clean
用来清除 cache
,当我们觉得 cache
的内容异常,或者 cache
占用空间过大时,可以通过golangci-lint cache clean
清除 cache
。status
用来打印 cache
的状态,比如 cache
的存放目录和 cache
的大小,例如:
$ golangci-lint cache status
Dir: /home/colin/.cache/golangci-lint
Size: 773.4KiB
2.3 completion
completion
命令包含 4 个子命令 bash
、fish
、powershell
和 zsh
,分别用来输出这四种环境的自动补全脚本。
$ golangci-lint completion bash > ~/.golangci-lint.bash
$ echo "source '$HOME/.golangci-lint.bash'" >> ~/.bashrc
$ source ~/.bashrc
执行完上面的命令,键入如下命令,即可自动补全子命令:
$ golangci-lint comp<TAB>
2.4 config
config
命令可以打印当前使用的配置文件路径,例如:
$ golangci-lint config path
.golangci.yaml
2.5 linters
linters
命令可以打印出所支持的 linter
,并将这些 linter
分成两类,分别是配置为启用的 和配置为禁用的,例如:
$ golangci-lint linters
Enabled by your configuration linters:
...
deadcode: Finds unused code [fast: true, auto-fix: false]
...
Disabled by your configuration linters:
exportloopref: checks for pointers to enclosing loop variables [fast: true, auto-fix: false]
...
3. 配置
支持两种配置方式,分别是命令行选项和配置文件。
如果bool/string/int
的选项同时在命令行选项和配置文件中被指定,命令行的选项就会覆盖配置文件中的选项。如果是 slice
类型的选项,则命令行和配置中的配置会进行合并。
默认的配置文件名为 .golangci.yaml
、.golangci.toml
、.golangci.json
,可以通过 -c
选项指定配置文件名。通过配置文件,可以实现下面几类功能:
*_test.go
文件等。配置需要忽略的文件和文件夹。配置启用哪些 linter
,禁用哪些 linter
。配置输出格式。有些 linter
支持一些配置项,这些配置项可以在配置文件中配置。配置符合指定正则规则的文件可以忽略的 linter
。设置错误严重级别,像日志一样,检查错误也是有严重级别的。
更详细的配置内容,你可以参考 configuration。
golangci-lint
的配置比较灵活,比如你可以自定义要启用哪些 linter
。golangci-lint
默认启用的 linter
,包括这些:
小提示:
golangci-lint
支持的更多linter
,可以在终端中输入golangci-lint linters
命令查看,并且可以看到每个linter
的说明。
如果要修改默认启用的 linter
,就需要对 golangci-lint
进行配置。即在项目根目录下新建一个名字为 .golangci.yml
的文件,这就是 golangci-lint
的配置文件。在运行代码规范检查的时候,golangci-lint
会自动使用它。假设我只启用 unused
检查,可以这样配置:
.golangci.yml
linters:
disable-all: true
enable:
- unused
在团队多人协作开发中,有一个固定的 golangci-lint
版本是非常重要的,这样大家就可以基于同样的标准检查代码。要配置 golangci-lint
使用的版本也比较简单,在配置文件中添加如下代码即可:
service:
golangci-lint-version: 1.32.2 # use the fixed version to not introduce new linters unexpectedly
此外,你还可以针对每个启用的 linter
进行配置,比如要设置拼写检测的语言为 US
,可以使用如下代码设置:
linters-settings:
misspell:
locale: US
golangci-lint
的配置比较多,你自己可以灵活配置。关于 golangci-lint
的更多配置可以参考官方文档,这里我给出一个常用的配置,代码如下:
配置文件 .golangci.yml
linters-settings:
golint:
min-confidence: 0
misspell:
locale: US
linters:
disable-all: true
enable:
- typecheck
- goimports
- misspell
- govet
- golint
- ineffassign
- gosimple
- deadcode
- structcheck
- unused
- errcheck
service:
golangci-lint-version: 1.32.2 # use the fixed version to not introduce new linters unexpectedly
比较重要的配置
run:
skip-dirs: # 设置要忽略的目录
- util
- .*~
- api/swagger/docs
skip-files: # 设置不需要检查的go源码文件,支持正则匹配,这里建议包括:_test.go
- ".*\.my\.go$"
- _test.go
linters-settings:
errcheck:
check-type-assertions: true # 这里建议设置为true,如果确实不需要检查,可以写成`num, _ := strconv.Atoi(numStr)`
check-blank: false
gci:
# 将以`github.com/marmotedu/iam`开头的包放在第三方包后面
local-prefixes: github.com/marmotedu/iam
godox:
keywords: # 建议设置为BUG、FIXME、OPTIMIZE、HACK
- BUG
- FIXME
- OPTIMIZE
- HACK
goimports:
# 设置哪些包放在第三方包后面,可以设置多个包,逗号隔开
local-prefixes: github.com/marmotedu/iam
gomoddirectives: # 设置允许在go.mod中replace的包
replace-local: true
replace-allow-list:
- github.com/coreos/etcd
- google.golang.org/grpc
- github.com/marmotedu/api
- github.com/marmotedu/component-base
- github.com/marmotedu/marmotedu-sdk-go
gomodguard: # 下面是根据需要选择可以使用的包和版本,建议设置
allowed:
modules:
- gorm.io/gorm
- gorm.io/driver/mysql
- k8s.io/klog
domains: # List of allowed module domains
- google.golang.org
- gopkg.in
- golang.org
- github.com
- go.uber.org
blocked:
modules:
- github.com/pkg/errors:
recommendations:
- github.com/marmotedu/errors
reason: "`github.com/marmotedu/errors` is the log package used by marmotedu projects."
versions:
- github.com/MakeNowJust/heredoc:
version: "> 2.0.9"
reason: "use the latest version"
local_replace_directives: false
lll:
line-length: 240 # 这里可以设置为240,240一般是够用的
importas: # 设置包的alias,根据需要设置
jwt: github.com/appleboy/gin-jwt/v2
metav1: github.com/marmotedu/component-base/pkg/meta/v1
需要注意的是,golangci-lint
不建议使用 enable-all: true
选项,为了尽可能使用最全的 linters
,我们可以使用以下配置:
linters:
disable-all: true
enable: # enable下列出 <期望的所有linters>
- typecheck
- ...
4. 运行
常用的使用方法:
对当前目录及子目录下的所有 Go 文件进行静态代码检查$ golangci-lint run
等效于 golangci-lint run ./...
$ golangci-lint run dir1 dir2/... dir3/file1.go
这里需要你注意:上述命令不会检查 dir1
下子目录的 Go
文件,如果想递归地检查一个目录,需要在目录后面追加 /...
,例如:dir2/...
$ golangci-lint run -c .golangci.yaml ./...
运行指定的 linter:
可以传入参数 -E/--enable
来使某个 linter
可用,也可以使用 -D/--disable
参数来使某个 linter
不可用。下面的示例仅仅启用了 errcheck linter
:
$ golangci-lint run --no-config --disable-all -E errcheck ./...
默认情况下,golangci-lint
会从当前目录一层层往上寻找配置文件名 .golangci.yaml
、.golangci.toml
、.golangci.json
直到根(/
)目录。如果找到,就以找到的配置文件作为本次运行的配置文件,所以为了防止读取到未知的配置文件,可以用 --no-config
参数使 golangci-lint
不读取任何配置文件。
如果我们想禁用某些
linter
,可以使用 -D
选项。
$ golangci-lint run --no-config -D godot,errcheck
安装成功 golangci-lint
后,就可以使用它进行代码检查了,示例代码
package main
import "os"
const name string = "wohu"
func main() {
os.Mkdir("demo_test", 0755)
}
运行命令:
wohu@ubuntu:~/gocode/src$ golangci-lint run demo.go
demo.go:5:7: `name` is unused (deadcode)
const name string = "wohu"
^
demo.go:7:13: Error return value of `os.Mkdir` is not checked (errcheck)
os.Mkdir("demo_test", 0755)
^
通过代码检测结果可以看到,两个代码规范问题都被检测出来了。检测出问题后,你就可以修复它们,让代码更加符合规范。
5. 减少误报golangci-lint
也提供了一些途径,我建议你使用下面这三种:
在命令行中添加 -e
参数,或者在配置文件的 issues.exclude
部分设置要排除的检查错误。你也可以使用 issues.exclude-rules
来配置哪些文件忽略哪些 linter
。
通过 run.skip-dirs
、run.skip-files
或者 issues.exclude-rules
配置项,来忽略指定目录下的所有 Go
文件,或者指定的 Go
文件。
通过在 Go
源码文件中添加 //nolint
注释,来忽略指定的代码行。
nolint
用法:
linter
的检查
var bad_name int //nolint
忽略某一行指定 linter 的检查,可以指定多个 linter,用逗号 , 隔开。
var bad_name int //nolint:golint,unused
忽略某个代码块的检查。
//nolint
func allIssuesInThisFunctionAreExcluded() *string {
// ...
}
//nolint:govet
var (
a int
b int
)
忽略某个文件的指定 linter 检查在
package xx
上面一行添加 //nolint
注释。
//nolint:unparam
package pkg
...
在使用 nolint
的过程中,有 3 个地方需要你注意。
nolint
,你就需要在 //nolint
后面添加 nolint
的原因 // xxxx
。其次,你使用的应该是 //nolint
而不是 // nolint
。因为根据 Go
的规范,需要程序读取的注释 //
后面不应该有空格。最后,如果要忽略所有 linter
,可以用 //nolint
;如果要忽略某个指定的 linter
,可以用 //nolint:,
,。
6. 使用技巧
6.1 按目录修改
如果你第一次检查你的代码,一定会有很多错误。为了减轻修改的压力,可以按目录检查代码并修改。这样可以有效减少失败条数,减轻修改压力。
当然,如果错误太多,一时半会儿改不完,那么你可以使用 --new-from-rev
选项,只检查新增的 代码,例如:
$ golangci-lint run --new-from-rev=HEAD~1
6.2 按文件修改
如果有很多检查错误,涉及很多文件,建议先修改一个文件,这样就不用来回切换文件。可以通过 grep 过滤出某个文件的检查失败项,例如:
$ golangci-lint run ./...|grep pkg/storage/redis_cluster.go
pkg/storage/redis_cluster.go:16:2: "github.com/go-redis/redis/v7" imported but not used (typecheck)
pkg/storage/redis_cluster.go:82:28: undeclared name: `redis` (typecheck)
pkg/storage/redis_cluster.go:86:14: undeclared name: `redis` (typecheck)
...
6.3 调整每行最大字符数
在项目开发中,为了易于阅读代码,通常会将变量名 / 函数 / 常量等命名得有意义,这样很可能导致每行的代码长度过长,很容易超过 lll linter
设置的默认最大长度 80。这里建议将 linters-setting.lll.line-length
设置为 120/240。
golangci-lint
集成了很多 linters
,可以通过命令 golangci-lint linters
查看,这些 linter
分为两类,一类是默认启用的,另一类是默认禁用的。每个 linter
都有两个属性:
fast
:true/false
,如果为 true
,说明该 linter
可以缓存类型信息,支持快速检查。因为第一次缓存了这些信息,所以后续的运行会非常快。auto-fix
:true/false
,如果为 true
说明该 linter
支持自动修复发现的错误;如果为 false
说明不支持自动修复。
如果配置了 golangci-lint
配置文件,则可以通过命令 golangci-lint help linters
查看在当前配置下启用和禁用了哪些 linter
。golangci-lint
也支持自定义 linter
插件,具体你可以参考 New linters
在使用 golangci-lint
的时候,我们要尽可能多的使用 linter
。使用的 linter
越多,说明检查越严格,意味着代码越规范,质量越高。如果时间和精力允许,建议打开 golangci-lint
提供的所有 linter
。
在 /
目录下存放通用的 golangci-lint
配置文件,可以让你不用为每一个项目都配置 golangci-lint
。当你需要为某个项目单独配置 golangci-lint
时,只需在该项目根目录下增加一个项目级别的 golangci-lint
配置文件即可。
代码检查一定要集成到 CI
流程中,效果才会更好,这样开发者提交代码的时候,CI
就会自动检查代码,及时发现问题并进行修正。
不管你是使用 Jenkins
,还是 Gitlab CI
,或者 Github Action
,都可以通过 Makefile
的方式运行 golangci-lint
。现在我在项目根目录下创建一个 Makefile
文件,并添加如下代码:
getdeps:
@mkdir -p ${GOPATH}/bin
@which golangci-lint 1>/dev/null || (echo "Installing golangci-lint" && go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.32.2)
lint:
@echo "Running $@ check"
@GO111MODULE=on ${GOPATH}/bin/golangci-lint cache clean
@GO111MODULE=on ${GOPATH}/bin/golangci-lint run --timeout=5m --config ./.golangci.yml
verifiers: getdeps lint
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)