为GitLab集成reviewdog

reviewdog

背景

最近在推进项目的CI/CD的标准化流程,CD当前使用运维提供的上线平台基本解决了,主要是偏向开发侧的CI,公司没有提供统一化的方案,代码都在gitlab上,而gitlab提供了CI服务,因此很自然的需要将项目接入GitLab CI。

最开始是在新的项目上加上了CI,标配了静态检测+单元测试,每次MR合并前跑一次,跑过了对上线的信心也能提升不少,自然也希望推动到自己负责的其他的项目里。

但对于一些遗留的老项目,涉及到的工作就比较多了,以我们的一些老项目为例,在很长的时间里都没有使用静态检查,全局变量,无效变量,代码格式各种warning满天飞,几万行的代码一下子改完所有warning比较困难;另外项目里也没有单元测试,模块的封装做的不好,有一些胖函数复杂度非常高,难以测试,但是直接全部推倒重构也不太现实。

考虑再三决定采用渐进式修改的方式,针对静态代码检查,每次检查改动的部分; 针对单元测试覆盖,也是涉及的代码处有机会就进行小范围的模块化重构并补充上单元测试用例。

在推进静态检查渐进式推进的过程中,发现有一点比较痛苦,静态检查有黑白名单,由于我们的检查的范围其实在不断的扩大,每次都要手动的维护这个skip的黑名单,很容易忘记。

因此希望有工具可以仅检查MR提交的代码中是否符合规范,而不是对项目里所有的代码进行检查。在做了很长时间的调研后,终于发现了有一个工具可以符合我的需求,它就是reviewdog.

reviewdog介绍

reviewdog 是一款能够自动化的检测 ( Pull / Merge Request) 里一些语法和格式错误并提交CR评论的工具。 它支持各种CI工具,目前支持以下平台的CI

  • GitHub Actions
  • Travis CI
  • Circle CI
  • GitLab CI
  • Bitbucket Pipelines
  • Common (Jenkins, local, etc…)

开始试用

安装

$ curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh | sh -s

环境变量

本地运行需要准备相关的环境变量, 实际在gitlab上跑CI时,只需指定 REVIEWDOG_GITLAB_API_TOKEN 即可

export REVIEWDOG_GITLAB_API_TOKEN=${ACCESS_TOKEN}
export CI_PROJECT_NAMESPACE=${NAMESAPCE}
export CI_PROJECT_NAME=${PROJECT_NAME}
export CI_COMMIT_SHA=${SHA}
export GITLAB_API=${API}

由于gitlab已经为我们预定义一些环境变量,见 https://docs.gitlab.com/ee/ci/variables/predefined_variables.html 可以看下自己的gitlab版本是否支持这些环境变量,在运行CI的时候,只需要在项目中指定 REVIEWDOG_GITLAB_API_TOKEN 这个环境变量, 这需用账号创建一个reviewdog的 ACCESS TOKEN

reviewdog会使用这个token,调用gitlab的接口对 merge request 进行评论,而评论人就是这个token的用户,实际使用时,建议申请专门的账号来干这个事情。

创建TOKEN

登录gitlab 点击右上角,选择 Settings → Access Tokens,填写名称和Token过期时间,Scopes里勾选api之后点击创建access token,页面会刷新,产生一个Access Token. 注意这个token需要保存好,页面刷新后就看不到了

image

image

项目中配置CI变量

有了上面的token后, 可以在项目中添加环境变量了,打开项目主页,点击左下角Settings,展开后可以看到CI/CD子菜单(如果看不到说明权限不够,需要Maintainer角色), 点击后找到 Variables 展开,输入key为 REVIEWDOG_GITLAB_API_TOKEN, value为上面创建的ACCESS TOKEN, 记得开启Masked,防止job log里泄漏敏感数据。 image image

测试

404报错

这里选用了一个基于openresty开发的服务进行测试,使用luacheck进行静态检查,执行如下命令,得到输出

$ luacheck src/ test/01-unit | reviewdog -f=luacheck -reporter=gitlab-mr-discussion -filter-mode=nofilter
reviewdog: GET https://${GITLAB_API}/api/v4/projects/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/merge_requests: 404 {error: 404 Not Found}

reviewdog报错404, 提示找不到merge_requests, 手动替换成projectID可以访问mr信息,怀疑公司gitlab api做了访问限制,询问IT得到了肯定的回复,明确不开放, 没办法,只能自己想办法使用projectID绕过了。

gitlab 预定义了projectID的环境变量 CI_PROJECT_ID, 看了reviewdog的代码,发现projectID都是通过owner+repo的方式拼接起来的,换成从环境变量获取 CI_PROJECT_ID 来访问GitLab的接口应该不难,于是fork了一份进行了修改, 修改完后,checkout代码,重新编译

$ git clone https://github.com/Gerrard-YNWA/reviewdog.git reviewdog-fork
$ cd reviewdog-fork/
$ CGO_ENABLED=0 && go build -ldflags "-s -w " ./cmd/reviewdog/

format不支持luacheck

使用自己修改后的版本再次执行命令,还是报错

$ luacheck src/ test/01-unit | /path/reviewdog-fork/reviewdog -f=luacheck -reporter=gitlab-mr-discussion -filter-mode=nofilter
reviewdog: fail to create parser. use either -f or -efm: "luacheck" is not supported. consider to add new errorformat to https://github.com/reviewdog/errorformat

这次报错信息说不支持luacheck format, 需要考虑去 errorformat 添加新的errorformat,于是提交了个 PR

集成至.gitlab-ci.yml

目前用自己修改过的版本,手动执行不再报错了。将命令合入CI,stage中加入reviewdog步骤,仅在MR时触发

reviewdog:
  only:
    - merge_requests
  stage: reviewdog
  tags:
    - lua
  script:
    - set +o pipefail
    - luacheck --formatter=plain --config=.reviewdog-luacheckrc src/ test/ | reviewdog -f=luacheck -name=luacheck -reporter=gitlab-mr-discussion

调试时还踩了一个gitlab-ci的坑,由于luacheck检测到代码中存在warning, 执行完退出的状态码为1,gitlab检查返回每次都报 ERROR: Job failed: exit status 1 查了半天发现是因为 pipefail 的问题

gitlab 跑 CI时使用了 set -o pipefail 的方式,只要有任何一个命令失败,整个管道操作都视为失败,这是一种比较安全的方式,但是在这里我们并不需要。这就和bash默认的只检查管道操作最后一个命令的返回值就不同了

因此每次手动bash下执行都是ok的,但是一上gitlab 执行就失败的现象,需要加一条命令,使其和bash行为一致。

效果

在GitLab创建了一个测试MR, 其中包含了一些luacheck可以检测出来的warning, 可以看到无论是新增的行还是修改已有的行, reviewdog 都能够正确找到warning的位置并添加上相应的评论, 最后上一下效果图。

image image image


wechat
微信扫一扫,订阅我的博客动态^_^