1. gitlab中配置静态代码检查
在Go语言中,可以使用一些第三方工具来进行静态代码扫描,常用的工具包括:
- Go vet:Go语言官方提供的工具,用于检查代码中的常见错误和问题;
- oLint:静态分析工具,可以检查代码中的一些不规范的写法和风格;
- GoMetaLinter:Go语言的多工具静态代码分析器,可以集成多种静态分析工具,例如Go vet、GoLint、gofmt、gocyclo等。其中,GoMetaLinter是一个比较强大的静态代码扫描工具,可以集成多个静态分析工具,并且支持多种输出格式和配置选项。
在GitLab中配置静态代码扫描也比较简单,可以使用.gitlab-ci.yml文件来定义CI/CD流程。以下是一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
stages: - test - scan unit-test: stage: test script: - go test -v ./... static-scan: stage: scan image: golangci/golangci-lint:v1.42.1 script: - golangci-lint run --timeout 5m |
上面的示例定义了两个阶段(stage),分别为test和scan。在test阶段中,使用go test命令运行单元测试。在scan阶段中,使用golangci-lint工具运行静态代码扫描,并将输出结果显示在控制台中。
需要注意的是,上面的示例使用了golangci-lint工具来进行静态代码扫描,因此需要在Docker中安装该工具。在image字段中指定需要使用的Docker镜像,可以选择golangci/golangci-lint或者其他适合自己的镜像。
另外,还需要在项目中添加.gitlab-ci.yml文件,并在GitLab的设置中启用CI/CD流程。在GitLab中,可以通过点击项目设置的CI/CD选项,进入CI/CD设置页面,并在其中添加一个Runner。添加完成后,GitLab会在每次代码提交时自动运行CI/CD流程,并进行单元测试和静态代码扫描。
2. 静态检查
可用于 Go 语言代码分析的工具有很多,比如 golint、gofmt、misspell 等,如果一一引用配置,就会比较烦琐,所以通常我们不会单独地使用它们,而是使用 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 被集成。
这里主要采用golangci-lint,采用其中配置文件定义可以参考文档 https://golangci-lint.run/usage/configuration/ 。
- .golangci.yml
- .golangci.yaml
- .golangci.toml
- .golangci.json
参考文档:《Go 静态代码分析工具 golangci-lint》https://blog.csdn.net/wohu1104/article/details/113751501
在.golangci.yml中,主要分为几个部分,run/output/linters-settings/linters/issues/severity这6部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# Options for analysis running. run: # See the dedicated "run" documentation section. option: value # output configuration options output: option: value # All available settings of specific linters. linters-settings: option: value linters: option: value issues: option: value severity: option: value |
2.1. run模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# Options for analysis running. run: # 默认可用并发CPU数量. concurrency: 4 # 静态分析超时时间, e.g. 30s, 5m. # Default: 1m timeout: 5m # 至少一个错误出现时 # 退出代码默认为1 issues-exit-code: 2 # 是否包含测试文件 # 默认是true tests: false # 所有linters采用的构建标签 # 默认空列表 []. build-tags: - mytag # 要跳过的目录,其中问题不会被报告,可以采用正则方式匹配。 # 默认值为空列表 # 但是缺省dirs将被跳过,而不依赖于该选项的值(参见skip-dirs-use-default)。"/"将被当前操作系统文件路径分隔符取代,以便在Windows上正常工作。 skip-dirs: - src/external_libs - autogenerated_by_my_lib # Default: true skip-dirs-use-default: false # 设置不需要检查的go源码文件,支持正则匹配,这里建议包括:_test.go。 # 默认值为空列表 # 但是不需要包含所有自动生成的文件, "/"将被当前操作系统文件路径分隔符取代,以便在Windows上正常工作。 skip-files: - ".*\\.my\\.go$" - lib/bad.go - ^.*\.(pb|y)\.go$ # 定义Go版本限制。#从go1.18开始主要与泛型支持有关。#默认值:使用Go版本。mod文件,回退到env var ' GOVERSION ',回退到1.18 go: '1.19' |
2.2. output模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# output configuration options output: # 输出格式 彩打行号|行号|json|tab|检查格式|代码韧性 # Default: colored-line-number format: json # Print lines of code with issue. print-issued-lines: false # 在问题报告结尾打印linter名称 # Default: true print-linter-name: false # Make issues output unique by line. # Default: true uniq-by-line: false # 输出文件的路径前缀 # Default is no prefix. path-prefix: "" # 对结果排序 sort-results: true |
2.3. linters模块
golangci-lint 的配置比较灵活,比如你可以自定义要启用哪些 linter。golangci-lint 默认启用的 linter,包括这些:
- depguard - 依赖包的校验
- misspell - 拼写错误检查
- gofumpt - 更强格式化检查
- deadcode - 死代码检查
- errcheck - 返回错误是否使用检查
- gosimple - 检查代码是否可以简化
- govet - 代码可疑检查,比如格式化字符串和类型不一致
- ineffassign - 检查是否有未使用的代码
- staticcheck - 静态分析检查
- structcheck - 查找未使用的结构体字段
- typecheck - 类型检查
- unused - 未使用代码检查
- varcheck - 未使用的全局变量和常量检查
1 2 3 4 5 6 7 8 9 10 11 12 13 |
linters: disable-all: true enable: - depguard - typecheck - goimports - gofumpt - govet - misspell - ineffassign - gosimple - unused - errcheck |
3. 静态检查运行
- 对当前目录及子目录下的所有 Go 文件进行静态代码检查
1 2 |
$ golangci-lint run #等效于 golangci-lint run ./... |
- 对指定的 Go 文件或者指定目录下的 Go 文件进行静态代码检查
1 |
$ golangci-lint run dir1 dir2/... dir3/file1.go |
这里需要你注意:上述命令不会检查 dir1 下子目录的 Go 文件,如果想递归地检查一个目录,需要在目录后面追加 /... ,例如:dir2/...
- 根据指定配置文件,进行静态代码检查
1 |
$ golangci-lint run -c .golangci.yaml ./... |
- 运行指定的 linter
可以传入参数 -E/--enable 来使某个 linter 可用,也可以使用 -D/--disable 参数来使某个 linter 不可用。下面的示例仅仅启用了 errcheck linter :
1 |
$ golangci-lint run --no-config --disable-all -E errcheck ./... |
默认情况下,golangci-lint 会从当前目录一层层往上寻找配置文件名 .golangci.yaml、.golangci.toml、.golangci.json 直到根(/ )目录。如果找到,就以找到的配置文件作为本次运行的配置文件,所以为了防止读取到未知的配置文件,可以用 --no-config 参数使 golangci-lint 不读取任何配置文件。
禁止运行指定的 liner:
如果我们想禁用某些 linter,可以使用 -D 选项。
1 |
$ golangci-lint run --no-config -D godot,errcheck |
4. golangci-lint模板实例
//.golangci.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# 官方golangci-lint配置 https://json.schemastore.org/golangci-lint.json # 使用范例: golangci-lint run -c .golangci.yaml ./... #service: # use the fixed version to not introduce new linters unexpectedly # golangci-lint-version: 1.46.2 run: # timeout for analysis, e.g. 30s, 5m, default is 1m timeout: 10m # include test files or not, default is true tests: false # 允许跳过目录开关 default is true. Enables skipping of directories: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ skip-dirs-use-default: true skip-dirs: # 设置要忽略的目录 - util skip-files: # 设置不需要检查的go源码文件,支持正则匹配,这里建议包括:_test.go # Skip autogenerated files. - ^.*\.(pb|y)\.go$ output: #对结果排序 sort-results: true # # 输出格式 彩打行号|行号|json|tab|检查格式|代码韧性 # # Default: colored-line-number # format: json # # Print lines of code with issue. # print-issued-lines: false linters: disable-all: true enable: # TODO by project - depguard - typecheck - gofumpt - govet - misspell - ineffassign - gosimple - unused - errcheck # - depguard - 依赖包的校验 # - typecheck - 类型检查 # - misspell - 拼写错误检查 # - gofumpt - 更强格式化检查 # - deadcode - 死代码检查 # - errcheck - 返回错误是否使用检查 # - gosimple - 检查代码是否可以简化 # - govet - 代码可疑检查,比如格式化字符串和类型不一致 # - ineffassign - 检查是否有未使用的代码 # - staticcheck - 静态分析检查 # - unused - 未使用代码检查 # - varcheck - 未使用的全局变量和常量检查 #- goimports linters-settings: depguard: list-type: blacklist include-go-root: true packages-with-error-message: # TODO by project - sync/atomic: "Use go.uber.org/atomic instead of sync/atomic" - io/ioutil: "Use corresponding 'os' or 'io' functions instead." - regexp: "Use github.com/grafana/regexp instead of regexp" - github.com/stretchr/testify/assert: "Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert" # gofumpt: # extra-rules: true # lang-version: "1.15" #判断go版本 #goimports: # local-prefixes: github.com/prometheus/prometheus issues: # 同文件中最多问题数量限制,0关闭,默认3 max-same-issues: 0 exclude-rules: - path: _test.go linters: - errcheck |
微信赞赏
支付宝赞赏