Sonarqube系列06:基于Sonarqube、GitLab机器代码审查的探索与实践

1. 前言

阅读本篇内容前,请确保已了解:

  • Git 基础用法
  • Sonarqube 代码质量扫描用法及 GitLab 集成相关内容
  • GitLab CI/CD 运行机制、 .gitlab-ci.yml 语法及 GitLab Runner 相关内容

2. 背景

为了满足软件开发中对于不断增长的质量要求,工程师们不断尝试在软件开发生命周期中加入新的流程来提升软件的质量,传统的方式是通过测试工程师开展各种测试来满足要求,随着软件开发思想的发展,逐渐引入代码审查流程。

2.1. 代码审查

代码审查是指除了代码作者之外,其他人检查代码的过程。需要注意,传统意义上的代码审查是依赖其他人进行,即人工代码审查

除了保证代码质量,代码审查也是培养团队工程师文化的一种重要形式。一方面开发者面对审查会更认真思考自己的实现的完整度和成熟度,另一方面如果审查者做过相关内容且有更好的解决方案,也可以在审查过程提出来,做到一定程度的技术分享。在不断迭代过程中发现问题、解决问题、总结经验,有助于团队提高技术追求。

相对的,任何方案都有弊端,代码审查也不例外。审查的执行效果很大程度取决于团队工程师能力的平均水平,这里的能力不光是技术能力,也有责任心、执行力等软性能力。所以,在不同团队中代码审查能发挥作用的大小也会不同。

2.2. 机器代码审查

考虑人工代码审查的稳定性和规范程度,工程师们对于常见的编码样式约束、最佳实践、经验教训总结成编码规则,通过软件的方式自动化的开展代码问题扫描,这就是机器代码审查

相对「人工代码审查」,「机器代码审查」具备可靠的稳定性和标准的规范流程,因此,在常规的软件开发生命周期中,能够有效的改善软件代码质量。随着 CI、CD、DevOps 等软件开发文化的推进,机器代码审查已经成为软件开发中不可缺失的一环。

3. 场景分析

目前基于 Git 的开发流程:

  1. 开发者接到开发任务需求,沟通理解需求
  2. 更新代码,创建分支/使用已有开发分支
  3. 在本地完成编码、调试,提交到 GitLab 仓库
  4. 提交 Merge Request 向目标分支合并,等待项目管理者合并
  5. 项目管理者审查/不审查,合并代码

分析上面的流程,可以看出有两个节点适合进行机器代码审查:

  • 步骤 3 ,开发者提交代码,配合 pre-commit/push-hook 进行检查,检查不通过不允许 commit/push
  • 步骤 4 ,开发者提交 Merge Request ,触发CI构建进行检查,检查不通过不允许merge

这里更偏向于方案 2,一方面因为 pre-commit/push-hook 可以通过 --no-verify 命令绕过,另一方面 Merge Request 是开发者代码流入主干的节点,对于不合并的代码不用触发审查,节省服务器资源。

加入的机器代码审查流程如下图红线所示:

4. 方案实现

结合 Sonarqube 和 GitLab CI/CD 相关功能,方案规划思路如下:

  1. GitLab 上设定项目 Merge Request 关联的 CI 任务执行失败,不能合并
  2. 项目代码添加 .gitlab-ci.yml ,配置当用户提交 Merge Request 时,自动触发 Sonarqube 扫描
  3. Sonarqube 扫描增量代码,并校验代码质量能否通过质量门禁,如不通过返回失败,并通过「Merge Request 评论联动」功能将问题写入 Merge Request 中,方便开发者查看
  4. 开发者解决扫描问题,再次提交、扫描、通过,允许合并入主干代码
  5. 项目管理者手动操作,合并代码

4.1. GitLab 配置

进入 GitLab 对应项目,选择 Settings > General > Merge Requests,勾选红框内容:

4.2. 配置 GitLab CI 任务

在项目根目录添加 .gitlab-ci.yml 文件,写入如下内容:

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
stages:
- merge-check

variables:
SONAR_URL: http://you-sonarqube
SONAR_TOKEN: your-sonarqube-token

merge-check-job:
stage: merge-check
variables:
GIT_STRATEGY: clone
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- git fetch origin ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}:${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
- git fetch origin ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}
- export MAVEN_OPTS="-Xmx2g" &&
mvn clean compile
org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar
-Dsonar.projectName=${CI_PROJECT_NAME}
-Dsonar.projectKey=${CI_PROJECT_NAME}
-Dsonar.projectDescription=${CI_PROJECT_TITLE}
-Dsonar.links.homepage=${CI_PROJECT_URL}
-Dsonar.sourceEncoding=UTF-8
-Dsonar.qualitygate.wait=true
-Dsonar.qualitygate.timeout=300
-Dsonar.host.url=$SONAR_URL
-Dsonar.login=$SONAR_TOKEN
allow_failure: false
tags:
- builddocker
only:
- merge_requests

需要注意:

  • 示例为 Java 项目基于 Maven 的 Scanner 扫描语法和参数,其他编程语言自行替换
  • 关键参数为 sonar.qualitygate.wait,指定为 true 时 CI 任务会根据扫描结果返回成功失败
  • Sonarqube 进行 Merge Request 扫描时,需要源分支、目标分支代码检出,扫描动作前两句的 git fetch 是必须的
  • 设定执行策略为 GIT_STRATEGY: clone ,这样每次都是重新 clone 再 fetch,确保每次分支代码是最新代码,尤其是目标分支
  • Soanrqube 进行 Merge Request 扫描时需要设置 sonar.pullrequest.key 等相关参数,当通过 GitLab CI/CD 来执行时,会自动填充相关参数值,如果需要定制化相关内容,请手动传参,参考这里

4.3. Sonarqube 配置

Sonarqube Project 需要保证两点:

  1. 配置对应的 Project 关联 GitLab 项目,可参考《Sonarqube系列05:GitLab 集成实践》进行操作
  2. 进行 GitLab CI 进行机器扫描前,先对主干分支扫描一次,否则合并扫描会因为无法对比分支而失败

以上配置好后,提交 Merge Request 会发现自动触发扫描,并给出扫描结果。

点击「参考 PR」可以跳转到 GitLab 中的 Merge Request 详情。

同样,在 Merge Request 详情页面可以点击对应问题及报告,快速跳转到 Sonarqube 中查看问题。

5. 总结

通过 Sonarqube 内置与 GitLab 联动功能,配合 GitLab 的合并的流水线要求,可以实现基于开源方案的机器代码审查流程,为项目开发过程中的代码质量提供低成本的保证方案。

目前实践过程中,美中不足的是一部分步骤还需手动操作进行,后续可考虑通过两者 API 进行统一设置,降低使用门槛。

6. 参考资料