阿猫的博客

阿猫的博客

使用 GitLab 流水线进行 Go 代码静态检查

297
2024-01-30

背景

代码静态检查能检查出很多问题,这些问题可能在测试中也无法发现,只有某些极端条件下会触发,例如死锁、竞争条件,没有处理的 err 等;同时也能检查出代码中的 bad smell,能够优化代码质量,尽量减少技术债务。

思路

对于 Go,有比较现成的工具 golangci-lint。这是一个静态代码检查工具,能够配置多种 lint 规则,执行速度较快,适合在 ci 流程中运行。

接入的过程比较简单,通过 push 或者 merge request 触发 pipeline,然后运行静态代码检查,输出结果。

实操

GitLab CI

要实现在 push 或者 merge request 的时候触发 pipeline,首先需要定义一个 GitLab CI 流程。在项目里新建一个 .gitlab-ci.yml 文件,内容如下:

default:
  image: leslieleung/gitlab-golangci-lint:v0.0.3

stages:
  - lint

workflow:
  rules:
    - if: "$CI_PIPELINE_SOURCE == 'push'

lint:
  stage: lint
  tags:
    - myrunner
  script:
    - export GOPROXY=https://goproxy.cn
    - golangci-lint run > report.xml
  artifacts:
    when: always
    reports:
      junit: report.xml
  allow_failure: true

首先,要求 runner 使用一个 docker 镜像来运行。在 CI 任务中,给 runner 配置环境可能比较麻烦,使用配好需要的软件的 docker 镜像是更好的选择。在这个 docker 镜像中,包含了 go 的运行环境和一个 golangci-lint 二进制文件。

然后定义一个 pipeline 需要运行的 stage(步骤),目前只需要进行一个 lint。接下来定义需要执行 workflow 的场景,使用rules.if,这里我设置了当发生 push 事件,且提交的分支不是 k8s 的自动构建分支时,运行这个 pipeline。

最后是定义每一个 job(步骤)。stage 和上面的 stages 对应,tags 用来标识要用来运行的 runner。重点介绍 script 和 artifacts 两部分。script 是在这个 job 中要运行的命令,因为只是执行代码检查,要运行的命令就比较简单。如果要进行构建等等,也可以在这里执行。artifacts 是一个用来上传上一步 script 产生的构建产物的空间,如果你在上一步构建了二进制之类的文件,可以使用 artifacts 发布产物,会在 pipeline 中产生一个下载页面。这里我们需要的是上一步 lint 出来的结果,因此我们选择artifacts.reports.junit,GitLab 自带了一个可视化 junit 单测结果的界面。

golangci-lint 配置

golangci-lint 自带了非常多的规则,可以根据项目的需要来启用。示例如下:

run:
# 要跳过的目录,根据需要调整
  skip-dirs:
    - tests
    - docs
    - gen
# 当前项目的Go版本
  go: '1.19'
  timeout: 5m
  tests: false
  allow-parallel-runners: true
  modules-download-mode: readonly
  issues-exit-code: 0
output:
  format: junit-xml
linters:
  disable-all: true
  enable:
    - errcheck
    - govet
    - ineffassign
    - unused
    - gosimple
    - staticcheck
    - gocognit
    - nilerr
    - goconst
    - revive

这套配置比较简单,只包含了一些诸如未处理的 err、无效赋值、未使用的变量、过高复杂度等的静态检查,可以根据项目需要进行调整。

最终效果

在左侧 CI/CD -> Pipelines -> Tests 可以看到 lint 的结果,failures 数即为 linter 检测出的问题数。