代码质量检查(SonarQube)¶
SonarQube 会分析源代码和测试报告, 帮助你发现潜在错误、安全问题与维护成本较高的写法. 本章以 Django 后端为例, 将分析接入 GitLab CI/CD: 测试通过后执行扫描, 质量门禁通过后再构建和部署.
登录并导入项目¶
-
从 SECoder 概览页进入 SonarQube, 点击 Log in with GitLab. 首次使用时先完成 GitLab 的 SECoder 登录.
-
在 SonarQube 的项目页选择 Create Project → From GitLab. 页面提示提供 GitLab Personal Access Token 时, 到 GitLab 的 头像菜单 → Edit profile → Access → Personal access tokens 创建令牌.
当前 GitLab 的入口为 Generate token → Legacy token. 填写名称和到期日期, 权限只勾选 read_api, 创建后立即复制令牌. 该令牌用于读取仓库列表并导入项目.
-
将令牌填写到 SonarQube 的导入页面并保存. 搜索自己的仓库, 核对 See on GitLab 的地址, 勾选后点击 Import.
-
新代码定义选择 Follows the instance’s default, 再点击 Create project. 创建完成后选择 With GitLab CI, 语言选择 Python.
截图中的 django-backend 是演示项目. 配置自己的项目时, 使用自己的仓库和导入后生成的 Project Key.
配置分析令牌¶
在 GitLab CI 引导页点击 Generate a token, 为当前项目生成 Project Analysis Token, 设置名称和合适的有效期. 令牌只用于分析当前项目; 页面只显示一次, 创建后立即复制到 CI/CD 变量中.
进入 GitLab 项目的 Settings → CI/CD → Variables, 添加:
| Key | Value | 设置 |
|---|---|---|
SONAR_HOST_URL |
https://sonar.t.secoder.net |
普通变量 |
SONAR_TOKEN |
刚生成的 SonarQube Project Analysis Token | Masked and hidden, Protected; 关闭变量展开 |
本章只扫描默认分支. 默认分支需要在 Settings → Repository → Branch rules 中设为 Protected, 才能读取 Protected 的分析令牌. 若引导页建议取消 Protect Variable, 以本章的分支规则与变量设置为准.
GitLab PAT 用于导入仓库, SONAR_TOKEN 用于上传分析结果, 部署使用的 TOKEN 则是 Kubernetes API 令牌. 分别保存它们, 到期或轮换后更新对应位置. 截图、仓库和日志中都应隐藏完整凭据.
生成测试报告¶
SonarQube 读取测试工具生成的报告. Django 示例使用 Python 3.11、pytest 和 Coverage.py, 先安装项目依赖, 再执行测试.
在仓库根目录增加 .coveragerc:
1 2 3 4 5 6 7 8 9 10 | |
source = . 使报告中的文件名保留 board/、DjangoHW/ 等目录前缀, 避免多个 __init__.py 产生歧义. 相对路径也便于扫描作业在下载产物后找到同一份源码.
在现有 pytest.ini 中增加:
1 | |
这样生成的 JUnit 报告包含文件位置信息, 便于 SonarQube 对应到测试文件. 保留原有的 Django settings 和测试文件匹配规则.
test.sh 使用:
1 2 3 4 5 | |
脚本会输出覆盖率与测试执行报告, 并保留 pytest 的退出状态. 测试失败时, 流水线应停止.
配置扫描范围¶
在根目录的 sonar-project.properties 中填写:
1 2 3 4 5 6 7 8 9 10 11 | |
sonar.sources指定业务源码根目录, 注意属性名末尾有 s.sonar.tests与sonar.test.inclusions指定测试文件.board/tests.py从业务源码中排除后, 仍作为测试代码参与分析.sonar.inclusions和sonar.exclusions控制源码分析范围;**匹配任意层级目录.- 两个报告路径必须对应测试作业实际生成并上传的文件.
这个示例对应 board/tests.py 的目录结构. 项目的测试放在其他位置时, 应同时调整测试分类、Coverage.py 配置与报告路径.
将质量门禁加入流水线¶
在现有 .gitlab-ci.yml 中合入下面的质量检查配置. 构建和部署继续使用项目已有的 BuildKit 与 Kustomize 配置.
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 | |
测试作业 unit-test 应通过 sh test.sh 生成报告, 并配置产物:
1 2 3 4 5 6 7 | |
needs: artifacts: true 让扫描作业下载这些文件. GIT_DEPTH: "0" 保留分析所需的提交历史. sonar.qualitygate.wait=true 会等待服务端计算质量门禁; 门禁不通过或等待超时, 扫描作业都会失败.
镜像构建放在 build 阶段, 通过阶段顺序等待质量检查. 部署作业还应显式依赖扫描成功, 将以下依赖合入已有配置:
1 2 3 4 5 6 7 8 9 | |
GitLab 的 needs 可以跨越阶段直接调度作业, 因此已有依赖列表也必须纳入质量检查. 扫描与部署使用相同的默认分支规则, 避免部署依赖一个未被创建的作业.
课程扫描模板需要直接内联到项目中. 模板默认的 allow_failure: true 应改为本章使用的 false, 才能形成严格门禁.
查看扫描与门禁结果¶
提交并推送后, 在 GitLab Build → Pipelines 检查 unit-test、sonarqube-check、build-image、deploy 的状态. 扫描日志末尾应出现 QUALITY GATE STATUS: PASSED, 并提供项目结果链接.
在 SonarQube 项目中查看:
- Overview: 质量门禁与主要指标.
- Issues: 问题的规则、严重程度、代码位置与修复建议.
- Security Hotspots: 需要结合业务场景审核的安全敏感代码.
- Measures: 覆盖率、测试结果、重复率与复杂度等数据.
当前实例的 Sonar way 主要检查新代码: 新增问题为 0、覆盖率至少 80%、重复率不超过 3%、安全热点审核率达到 100%. 小规模变更的覆盖率和重复率可能按实例规则豁免, 实际判定以项目 Quality gate 页面为准.
New Code 与 Overall Code 的范围不同. 首次分析用于建立基线, 门禁通过后整体代码中仍可能有历史问题. 阅读结果时应同时检查整体指标和问题列表, 并在后续提交中持续整改; 门禁通过不能替代对整个项目的检查.
常见问题¶
| 现象 | 检查方式 |
|---|---|
| 导入页面看不到仓库 | 核对 GitLab 登录账号、项目成员权限和 PAT 的 read_api scope; 令牌到期后重新配置 |
| 扫描鉴权失败 | 核对 SONAR_TOKEN 的类型、项目、有效期, 以及扫描分支是否能读取 Protected 变量 |
| 报告不存在或覆盖率无数据 | 先检查测试产物, 再核对 needs、报告路径、XML 中的 source 和文件名 |
| 日志提示文件路径有歧义 | 保留相对于仓库根目录的完整路径, 尤其注意多个同名文件 |
| 质量门禁失败 | 查看失败条件和新代码范围, 修复问题后重新提交; 安全热点按实际用途审核 |
| 扫描失败仍执行部署 | 检查 allow_failure、阶段顺序和部署作业的 needs |
本例用一条单独的验收流水线覆盖为无效的 SONAR_TOKEN, 验证扫描鉴权失败后, build-image 和 deploy 都被跳过. 该变量仅对这条验收流水线生效; 随后的正常流水线继续使用项目原有分析令牌.
配置成功后, 应能看到与当前提交 SHA 对应的分析记录、正确的测试数量和覆盖率, 且扫描失败时构建和部署被阻断.
参考资料¶
流水线基础见 GitLab CI/CD, 应用发布配置见 Kubernetes 部署, 后端作业要求见后端部署.