Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >量化你团队的代码质量

量化你团队的代码质量

作者头像
我与梦想有个约会
发布于 2023-10-21 07:44:16
发布于 2023-10-21 07:44:16
1.1K00
代码可运行
举报
文章被收录于专栏:jiajia_dengjiajia_deng
运行总次数:0
代码可运行

在疫情背景下各大公司都有所异动,toB 的团队企业内卷也越来越明显。此时此刻如果团队中的产品又出现各种低级问题无疑是雪上加霜。本文围绕团队在产品质量攻坚工作中做的一些质量检查手段,介绍如何让你团队的代码质量可以量化,并保留最珍贵、可维护、可持续、可传承的工程化代码。

整合目标

本文除了让大家了解这些工具如何使用以外,还会重点描述如何组织这些代码质量的周边工具链使其达到工程化程度,讨论什么该做,什么不该做,为什么这么做。我对所谓 工程化 有以下几个明确的定义:

  • 可维护:贴近 GitOps,尽量将所有可变配置放到代码仓库,而不是分散维护,Everything is code.
  • 可持续:不是应付一次检查或攻坚,而是形成常态
  • 可传承:新人只关注代码,不关注质量工具的配置细节,通过类似于 MRs 的结果反馈不断改进自身代码质量

一些涉及到权限控制的位置(如代码质量阈设置)是需要有管理员把控的,要实施这些步骤首先团队的技术管理负责人要有这些认知并且能在关键点拍板。如果仅认为这些东西有了就够了恐怕是很难实施下去的! 本文示例均已一个简单的 ne-phoenix 基础库代码作为示例,介绍围绕该工程展开的质量突击。

准备工具

  • clang-tidy、infer 用于静态代码检查
  • lcov 用于统计单元测试代码覆盖率
  • gcovr 用于生成覆盖率报告及转为 SonarQube 支持的报告格式
  • sonar-scanner 用于传送以上工具的报告结果到 SonarQube 平台(平台搭建请参考官方文档)
  • pre-commit 可选,用于提交时本地执行静态代码检查

这些工具在 macOS 中均可通过 brew 来进行安装,比较特殊的是 clang-tidy,它在 LLVM 工具链中,您需要在 brew install llvm 后再通过 brew link llvm 按提示将可执行文件添加到环境变量中,使脚本可以直接访问到 clang-tidy 可执行程序。

Code coverage

单元测试、API 测试、集成测试,只听这些概念就足够让我们晕头转向,但无论如何,我一直很认同一句话:没有覆盖率统计的测试就是耍流氓。即便你提供了所谓每天的自动化测试报告,貌似可以量化,但真正的作用谁有知道呢?虽然覆盖率统计并不能代表代码就是 100% 可靠的。但它可以通过量化的数据告诉我们代码的哪些分支、哪些逻辑我们还没有覆盖,至少能让你知道,你的测试是不是在做一些无意义的事情。 在 ne-phoenix 基础库中,我们以 CMake + Conan 驱动整个工程的编译,单元测试的框架使用了 Google Test。要统计执行测试程序后对代码的覆盖情况,我们要做以下几点工作:

  • 增加编译选项为 coverage 做准备
  • lcov 初始化一次基础扫描
  • 编译并运行测试可执行程序
  • lcov 扫描执行测试程序后的结果捕获覆盖到的代码情况
  • lcov 与基础报告对比生成结果

这个步骤比较繁琐,我们找到了一个开源的 CMake 插件 CodeCoverage.cmake,有了这个插件,您只需要在您的工程中添加几行 CMake 代码即可实现覆盖率统计能力:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (APPLE)
    include(CodeCoverage)
    append_coverage_compiler_flags()
endif ()

.....
..... 

if (BUILD_TESTING)
    add_subdirectory(testing)
    if (APPLE)
        setup_target_for_coverage_lcov(
            NAME coverage
            SONARQUBE TRUE
            BASE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
            EXECUTABLE testing
            EXECUTABLE_ARGS --gtest_output=xml:result.xml
            EXCLUDE "/*v1/*" "/*/.conan/data/*" "/*CompilerId*" "/*/testing*" "/*/*_unittest.cc"
        )
    endif ()
endif ()

首先在脚本开始判断平台并引入 CodeCoverage.cmake 插件,调用 append_coverage_compiler_flags() 接口全局添加统计代码覆盖率所需的编译选项。随后调用 setup_target_for_coverage_lcov() 添加一个自定义 CMake 目标用来执行并输出覆盖率统计报告,它的参数分别如下:

  • NAME 在 CMake 中生成的自定义目标名称
  • SONARQUBE 是否生成 SonarQube 兼容的覆盖率统计报告
  • BASE_DIRECTORY 要统计覆盖率源码的起始目录
  • EXECUTABLE 执行测试的程序,这里使用接入了 Google Test 的可执行程序
  • EXECUTABLE_ARGS 执行测试程序是的命令行参数,用于生成 GTest 结果报告为 xml 上报给 GitLab
  • EXCLUDE 在报告中排除一些不需要的目录

添加完成后只需要如下两条命令,就可以自动在 CMake 缓存目录生成覆盖率统计报告了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 初始化工程为 Debug
cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=14
# 编译 coverage 目标
cmake --build build --config Debug --target coverage

生成 coverage 目标完成后,该目标会自动化执行测试程序并统计出报告:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Writing directory view page.
Overall coverage rate:
  lines......: 80.5% (1583 of 1966 lines)
  functions..: 78.3% (503 of 642 functions)
SonarQube code coverage info report saved in coverage_sonarqube.xml.
Open ./coverage/index.html in your browser to view the coverage report.

我们打开 build/coverage/index.html 就可以看到完整的覆盖率情况了:

点击某个文件进入可查看当前测试程序覆盖到了哪些条件判断,其中红色的表示你的测试程序没有覆盖到该位置的代码:

除了可视化的 html 查看覆盖率报告外,还输出了 SonarQube 兼容的 xml 格式报告 build/coverage_sonarqube.xml 文件,稍后我们介绍如何将该文件上传到 SonarQube 平台用以统计。 同时测试程序的成功、失败情况也输出在了 build/result.xml 中,稍后我们介绍如何将该文件上传到 GitLab 展示。

Code static analyzer

无论颗粒度是怎样的测试不仅能帮助我们发现业务流程中的问题,也能让我们尽快发现代码实现上的问题。但代码质量、可读性、可扩展性这些都是无法得知的,这些可以通过静态代码检查来实现。 Google 团队在 Chromium 项目中很早就应用了诸多静态代码检查工具,有的是依赖编译的,有的是通过正则模式分析的,各有优劣。仰仗于各个大厂和开源社区的努力,周边工具链越来越给力,类 clang-tidy、infer 的工具,不仅能实现完整的静态代码检查,还可以完全替代以前的正则类扫描工具如 cpplint 等。本文以 clang-tidy 分析 C++ 代码举例,让我们一起了解如何从头分析一个完整的工程。 如果你是 CMake 工程,做到这件事情非常简单,只需要在 CMake 初始化工程时增加参数:-DCMAKE_EXPORT_COMPILE_COMMANDS=ON,该参数的增加会告知 CMake 将所有源文件的编译选项写入到一个名为 compile_commands.json 的 json 文件中。后续所有的静态代码检查都是基于该文件进行的。 以 ne-phoenix 工程举例,首先使用如下命令生成工程配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug \
    -DBUILD_TESTING=ON \
    -DCMAKE_CXX_STANDARD=14 \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

compile_commands.json 会生成到 CMake 的缓存目录 build 下,然后调用 clang-tidy 命令,对你关注的文件进行分析:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
clang-tidy -p=build main.cpp

clang-tidy 有默认的规则是启用所有,如果你希望控制规则细节,可在工程目录放置一个 .clang-tidy 配置文件,内容类似如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Checks: >
  -*,
  abseil-*,
  bugprone-*,
  clang-analyzer-*,
  google-*,
  misc-*,
  modernize-*,
  performance-*,
  portability-*,
  readability-*,
  -google-readability-braces-around-statements,
  -google-readability-namespace-comments,
  -google-runtime-references,
  -misc-non-private-member-variables-in-classes,
  -modernize-return-braced-init-list,
  -modernize-use-trailing-return-type,
  -modernize-avoid-c-arrays,
  -performance-move-const-arg,
  -readability-braces-around-statements,
  -readability-identifier-length,
  -readability-magic-numbers,
  -readability-named-parameter,
  -readability-redundant-declaration,
  -readability-function-cognitive-complexity,
  -bugprone-narrowing-conversions,
  -bugprone-easily-swappable-parameters,
  -bugprone-implicit-widening-of-multiplication-result

# WarningsAsErrors: "*"
HeaderFilterRegex: ".*"

FormatStyle: file

该规则参考了 Google Cloud 开源项目配置,所有配置项可参考 LLVM 官网:Extra Clang Tools 上面单独调用 clang-tidy 只能分析单个文件,如果要分析多个文件,我们要把所有文件依次传给 clang-tidy。这样命令写起来比较繁琐且不易阅读。更重要的是无法实现多个实例同时对多个文件进行检查,效率极低。LLVM 工具链中早就想好了这些问题,他们提供了 run-clang-tidy.py 提供我们进行批量分析,见:LLVM run-clang-tidy.py。有了这个脚本,我们就可以批量进行分析了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
python3 .build/run-clang-tidy.py -p=build -j 8 > build/clang-tidy-output.txt
  • -p 表示指定 compile_commands.json 文件所在目录
  • -j 8 表示最多可以同时执行 8 路分析不同的文件,加快分析速度

分析时间视工程目录源码文件多少而定,如果代码中使用的模板较多,分析的时间会较长。分析完成后会在 build 目录下生成名为 clang-tidy-output.txt 的分析结果,手动打开该文件你就可以可以看到一分析的错误信息了。接下来就是将这个报告上传到 SonarQube 平台。

SonarQube 集成

由于考虑篇幅问题,这里不详细介绍 SonarQube 的部署及多分支插件的安装,这部分资料官网和 StackOverflow 资料非常多,大家可参考搭建部署。在上传报告前参考文章开头,先安装好 sonar-scanner 上传工具。将项目的配置信息保存到名为 sonar-project.properties 的配置文件中并存放到项目根目录下,内容类似:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# must be unique in a given SonarQube instance
sonar.host.url=http://10.246.152.58:9000
sonar.projectKey=ne-phoenix
sonar.login=sqp_86571ff6d309106814c26e22621e23d87******
sonar.qualitygate.wait=true
sonar.sources=.
sonar.sourceEncoding=UTF-8
sonar.cxx.file.suffixes=.cxx,.cpp,.cc,.c,.hxx,.hpp,.hh,.h
sonar.lang.patterns.objc=**/*.m,**/*.mm
sonar.cxx.clangtidy.reportPaths=build/clang-tidy-output.txt
sonar.exclusions=build/**,**/*_unittest.*,conanfile.py,uploadConan.py

各个参数用途如下:

  • sonar.host.url SonarQube 服务器地址
  • sonar.projectKey SonarQube 平台上创建的工程名
  • sonar.login SonarQube 上传 token
  • sonar.qualitygate.wait 表示等待 SonarQube 返回扫描结果
  • sonar.source 表示源码是当前根目录
  • sonar.sourceEncodin 表示以 UTF-8 格式分析报告
  • sonar.cxx.file.suffixes 表示要分析的 C++ 文件后缀
  • sonar.lang.patterns.objc 表示要分析的 Objective-C 代码的文件后缀
  • sonar.cxx.clangtidy.reportPaths 表示要上报的 clang-tidy 分析报告
  • sonar.exclusions 表示要排除的目录,包括测试覆盖率、静态分析结果

上传时只需要调用 sonar-scanner 即可将当前分支信息上报到 SonarQube 平台,如果一切顺利,将会返回如下内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 26.011s
INFO: Final Memory: 25M/108M
INFO: ------------------------------------------------------------------------
➜  ne-phoenix git:master)

此时再次打开 SonarQube 平台,就可以看到分析结果了(一定要安装 cxx-community 插件并应用 clang-tidy 规则):

SonarQube 支持设置每个工程的质量阈,如果您的团队短时间内无法对新代码实现高的覆盖率,可适当调整质量阈,以管理员身份登陆 SonarQube,点击上方菜单的 Quility Gates:

内置有默认的质量阈,代码覆盖率的要求达到了 80%,您可以自己手动新建一个质量与并在单独的工程设置中选择你自己创建的质量阈。

CI 集成

GitLab 测试报告集成

GitLab 和 SonarQube 都支持展示测试覆盖率统计结果,GitLab 还可以把测试的所有子项内容展示在 Pipeline 结果页中:

GitLab 展示测试覆盖率:

要显示这些内容在 GitLab 上非常简单,你只需在 gitlab-ci.yml 中将 GTest 测试结果的 result.xml 当作 Artifacts 上传到 GitLab 即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
stages:
  - step-analysis
  - step-conan-package-test
  - step-deploy

coverage:
  stage: step-analysis
  script:
    - export
    - git checkout -B "$CI_BUILD_REF_NAME" "$CI_BUILD_REF"
    - cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DCMAKE_CXX_STANDARD=14 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
    - cmake --build build --config Debug --target coverage --parallel
    - lcov --list build/coverage.info
  only:
    - merge_requests
  artifacts:
    when: always
    reports:
      junit: build/result.xml
  tags:
    - yunxin-darwin-runner

命令跟我们本地测试一样,先初始化 CMake 工程,然后编译 coverage 项目,编译时会自动执行代码覆盖率检查并输出 result.xml,最后调用 lcov 在终端输出了覆盖率报告内容,类似如下效果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ lcov --list build/coverage.info
Reading tracefile build/coverage.info
                                               Lines      FunctionsBranches  
Filename                                       Rate    NumRate  NumRate   Num
================================================================================
[/Users/yunxin/builds/Kri8Pkvi/0/netease-im/ne_phoenix/src/ne_base/]
base/ne_object.h                                100%     850.0%  24    -    0
base/ne_object_ability...nnect_able_supportor.h80.8%    2671.4%   7    -    0
base/ne_object_ability...ble_shared_from_this.h62.5%     866.7%   6    -    0
base/ne_object_ability...ent/ne_signal_from3p.h 0.0%    10 0.0%   4    -    0
base/ne_object_ability...ak_closure_supportor.h 100%     250.0%   4    -    0
crypto/md5.cpp                                 86.5%   20883.3%  12    -    0
design_patterns/scoped_generic.h                0.0%     4 0.0%   3    -    0
device/mac/platform_device_mac.mm              89.5%    19 100%   3    -    0
device/platform_device.cpp                     77.8%     966.7%   3    -    0
device/posix/platform_device_posix.cpp         92.6%    2750.0%   2    -    0
file/file_util.cpp                             85.0%    4071.4%   7    -    0
file/file_version_info.h                        0.0%     2 0.0%   4    -    0
file/mac/file_version_info_mac.mm               0.0%    42 0.0%  24    -    0
file/ne_filesystem.cpp                         85.1%   141 100%  14    -    0
log/log_file.cpp                               93.2%    74 100%  10    -    0
log/log_file.h                                  100%     6 100%   6    -    0
log/log_mmap_file.cpp                          80.9%   173 100%  16    -    0
log/log_os_filesys_util_posix.cc               82.5%    5787.5%   8    -    0
mmkv/mmkv.cpp                                  84.4%    45 100%   6    -    0
mmkv/mmkv.h                                     100%    15 100%   7    -    0
numerics/safe_conversions_impl.h                100%     5 100%  13    -    0
numerics/safe_math.h                            100%     8 100%  23    -    0
numerics/safe_math_impl.h                       100%    14 100%  31    -    0
path_util/path_util.cpp                        95.7%    46 100%  11    -    0
string/string_number_conversions.cc            77.2%   16784.8% 105    -    0
string/string_util.cpp                         77.6%   19688.9%  18    -    0
string/string_util.h                           83.3%     6 100%   2    -    0
synchronization/lock.h                         71.4%    21 100%   7    -    0
system/mac/sys_info_mac.cc                     60.7%    2857.1%   7    -    0
system/posix/sys_info_posix.cc                 55.6%    1850.0%   4    -    0
system/sys_info.cc                              100%     4 100%   2    -    0
system/sys_info.h                               100%     1 100%   4    -    0
system/sys_tool.cpp                            75.9%    2985.7%   7    -    0
thread/task_loop_interface.h                    100%     650.0%  12    -    0
thread/task_thread.cpp                         83.1%   14283.3%  24    -    0
thread/task_thread.h                           91.6%   13193.3%  45    -    0
thread/thread.cpp                              81.5%   11960.6%  33    -    0
thread/thread.h                                81.8%    1177.8%   9    -    0
thread/thread_interface.h                      84.0%    2573.3%  15    -    0
time/time.cpp                                   100%    19 100%   5    -    0
time/time.h                                     100%    25 100%   4    -    0
value/ne_any.h                                 46.3%    4177.9%  95    -    0
================================================================================
                                         Total:80.6%  197878.8% 646    -    0

最后的 Total:80.6% 就是总的覆盖率情况,这一步很重要,我们要在 GitLab 中添加一段正则代码,匹配最终的结果,GitLab 会在 Job 执行完成后从输出内容中正则匹配到对应内容并显示到 GitLab Job 结果页面,打开 Project->Settings->CI/CD 页面,展开 General pipelines 选项卡,在最下方的 Test coverage parsing 中输入如下正则,即可匹配到覆盖率统计数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Total:\(\d+\.?\d+\%)

如下图所示:

添加后 Save 保存,下一次触发 Pipeline 就会自动上报覆盖率百分比结果。

SonarQube 测试覆盖率集成

要上传测试覆盖率到 SonarQube 只需要在 sonar-project.properties 的配置文件中添加一行上报之前生成的 sonarqube_coverage.xml 即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# must be unique in a given SonarQube instance
sonar.host.url=http://10.246.152.58:9000
sonar.projectKey=ne-phoenix
sonar.login=sqp_86571ff6d309106814c26e22621e23d8778eb0bc
sonar.qualitygate.wait=true
sonar.sources=.
sonar.sourceEncoding=UTF-8
sonar.cxx.file.suffixes=.cxx,.cpp,.cc,.c,.hxx,.hpp,.hh,.h
sonar.lang.patterns.objc=**/*.m,**/*.mm
sonar.cxx.clangtidy.reportPaths=build/clang-tidy-output.txt
sonar.coverageReportPaths=build/coverage_sonarqube.xml
sonar.exclusions=build/**,**/*_unittest.*,conanfile.py,uploadConan.py

主意倒数第二行。通过次方式上传报告后,在 SonarQube 平台就可以展示测试覆盖率百分比的情况了:

SonarQube 平台支持设置统一的质量阈,当你的代码发现 Major 级别以上的错误又或者覆盖率达不到一定百分比,则 SonarQube 会回报给 GitLab 告诉他本次 MR 不通过并创建一个临时的错误 Job:

而如果一切正常,也会创建一个反馈入口:

点击即可直达本次 Merge request 的分析详情。

Merge request 增量代码静态检查

如果你实操过代码静态检查,你会发现在你庞大的工程中做一次代码静态分析的时间成本是非常昂贵的,我们不可能也不允许在每次 CI 阶段都要等待这么长的时间,符合逻辑的场景应该是只检查本次变更,如果能细化到代码行就更好了。可以实现吗?当然! LLVM 工具链提供了一个脚本 clang-tidy-diff.py,它可以实现细化到代码行。用于帮助我们在 CI 集成时对增量数据进行检查。下载该脚本保存到项目工程的 .build 目录下。 同样的在使用 clang-tidy-diff.py 脚本进行增量分析时,也是需要生成整个项目的 compile_commands.json 配置文件。该脚本只是将我们变更的文件列表通过参数的方式传递给 clang-tidy 可执行文件。然后到 compile_commands.json 中查找这些文件的编译指令来进行静态代码检查。生成请参考上方全量分析命令。 在发起一个 Merge request 或者 Pull request 时,一些 CI 集成工具都会帮我们收集要合并的分支已经合并的目标分支信息。通过这两个分支我们就可以确定下来修改的文件有多少。以下 git 命令可以展示从开启新的功能分支后所有的提交及文件变更信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
git diff -U0 feature/new-feature origin/develop^

以 GitLab CI 举例,假如 feature/new-feature 是基于 develop 开出的新功能分支,当发起 Merge request 时,会有两个变量分别描述这两个分支的信息。

  • ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} 用来描述新的 feature 分支
  • ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME} 用来描述目标合并分支

连带上面的已经实践过的 gitlab-ci.yml 代码,在 GitLab .gitlab-ci.yml 中我们可以这样编写脚本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
coverage:
  stage: step-analysis
  script:
    - export
    - git checkout -B "$CI_BUILD_REF_NAME" "$CI_BUILD_REF"
    - cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DCMAKE_CXX_STANDARD=14 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
    - cmake --build build --config Debug --target coverage --parallel
    - lcov --list build/coverage.info
    - set +e && git diff -U0 origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}^ ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} 
      python3 .build/clang-tidy-diff.py -path=build -p1 -j 8 > build/clang-tidy-output.txt && set -e
    - sonar-scanner -Dsonar.pullrequest.key=${CI_MERGE_REQUEST_IID}
      -Dsonar.pullrequest.branch=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}
      -Dsonar.pullrequest.base=${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
      -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME}
      -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA}
      -Dsonar.gitlab.project_id=${CI_PROJECT_PATH}
      -Dsonar.projectVersion=${CI_COMMIT_REF_NAME}
  only:
    - merge_requests
  artifacts:
    when: always
    reports:
      junit: build/result.xml
  tags:
    - yunxin-darwin-runner

注意第 10,11 行,我们通过 git diff 将变更信息传递给 clang-tidy-diff.py 脚本,该脚本会自己分析 git diff 结果对变更文件进行静态代码检查。同时在使用 sonar-scanner 进行扫描时我们也传递对应的源分支、目标分支信息,SonarQube 会创建一个 Merge Request 的分支分析信息提供您查看。 需要注意的是给 git diff 传递 base 时需要指定 origin 使用远端分支,通常情况下 GitLab CI 只会 checkout 你要编译的分支,本地可能不存在 base 分支的代码,无法进行比较。如 origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}^ 这样在上报到 SonarQube 平台后我们就可以按分支查看分析报告了(提要安装好多分支插件 branch-plugin):

查看某个 MR 或者某个分支的数据是单独显示的。

Merge request 反馈

数据上报到 SonarQube 平台后,我们每次都要人工去这个平台查看反馈报告,这样非常不方便,幸运的是 SonarQube 提供了 SCM 平台反馈能力,以管理员身份登录 SonarQube 平台,设置 GitLab 的配置如下(前提要安装好多分支插件 branch-plugin):

确保配置没有问题后,选择一个你的项目,进入项目设置页面,输入项目 ID 并选择刚才配置好的 GitLab API 保存:

确认连接无问题后保存,再次触发某个 Pipeline 并上报结果到 SonarQube 后,SonarQube 平台会调用 GitLab 提供的 API 将问题数据回报给每个 MR,并且在你有问题的代码中添加评论,效果如下:

Pre-commit 集成

如果你的团队启用了 pre-commit-hooks,您可以添加如下脚本,在每次提交时就检查一次变更的文件,这样在没有上传代码到 GitLab 时就可以及时的发现问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.0.1
    hooks:
    -   id: trailing-whitespace
        args: [--markdown-linebreak-ext=md]
    -   id: check-added-large-files
    -   id: check-merge-conflict
    -   id: end-of-file-fixer
    -   id: no-commit-to-branch
        args: ['--pattern', '^(?!((bugfixfeaturereleasehotfixsupportci)\/[A-Za-z0-9\_\-\.]+)$develop).*']
    -   id: check-case-conflict

-   repo: https://github.com/pocc/pre-commit-hooks
    rev: v1.3.4
    hooks:
    -   id: clang-format
        args: [--style=File, -i]
    -   id: clang-tidy
        args: [-p=build]

最后两行描述了如何在提交时进行 clang-tidy 的检查。pre-commit 相关信息请见文章最后扩展阅读。

总结

日常开发中一些 IDE 的辅助工具可以帮助我们随写随发现问题,如 VSCode 的 clang-tidy 检查、CLion 自带 clang-tidy 检查、VS IDE clang-tidy 检查等。通过 IDE 自带的测试工具如 VS Code TestMate、VS IDE 的 Test Explorer 都可以帮助我们本地执行单元测试、API 测试代码。这些可个根据不同开发者不同的开发环境需求而定,并不是强制要求。我们只要在 GitLab 做收口即可。 至此,代码质量相关工具工程化基本结束,我们从代码提交到 CI 再到 SonarQube 报告最后到反馈全流程均通过仓库代码配置文件的方式实现,符合我们预期的想法。在未来维护和扩展中给后来者提供了非常详尽的历史,将最有价值的数据留给他们。这也是写这篇文章的初衷。

扩展阅读

sonarqube branch plugin:https://blog.csdn.net/ewferferr/article/details/120432746 sonarqube C++ plugin:https://blog.csdn.net/qq\_15559817/article/details/100736498 clang-tidy:https://hokein.github.io/clang-tools-tutorial/clang-tidy.html pre-commit:https://pre-commit.com/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
代码覆盖率--gcov/lcov/gcovr
统计C/C++代码覆盖率的工具很多,比如OpenCppCoverage可以与VS工具配合,获取并展示代码覆盖率简单直观,但是在Linux、Mac等系统该如何统计呢?一般的持续集成工具(Jenkins、gitlab-ci等)中又该如何统计呢?
用户5521279
2019/07/24
10.4K0
C++最佳实践 | 1. 工具
本文档旨在收集对C++最佳实践所进行的协作性讨论,是《Effective C++》(Meyers) 和《C++ Coding Standards》(Alexandrescu, Sutter) 等书籍的补充。在讨论如何确保整体代码质量的同时,补充了一些没有讨论到的较低级别的细节,并提供了具体的风格建议。
C语言与CPP编程
2022/10/31
3.5K0
Golang 项目集成 SonarQube 做代码质量分析
seth-shi
2024/08/02
3750
Golang 项目集成 SonarQube 做代码质量分析
Gitlab+Jenkins+SonarQube计算增量覆盖率
当要求质量内建、测试左移、持续集成、DevOps,代码的增量覆盖率几乎是必定会被提出来的话题。这个方案明确了"谁的代码谁负责"的原则,和当年“小岗村包产到户”一样,开发人员只需要为自己的提交/合并请求来提供代码覆盖率数据,而不再需要为整个团队的代码库和历史旧账掉头发了。团队负责人也乐于实施这样的“最佳实践”,树立一个带电的“质量门禁”,没有达标的,一律拒绝签入或者合并。
Antony
2020/12/22
5.8K1
Gitlab+Jenkins+SonarQube计算增量覆盖率
从零开始构建向量数据库:Milvus 的源码编译安装(一)
我在知乎上开了一个新的专栏,想持续聊聊“向量数据库”相关的内容。本篇聊聊向量数据库领域,知名的开源技术项目:Milvus。
soulteary
2022/07/11
2.7K0
【系列教程】 C++项目开发配置最佳实践(vscode远程开发配置、格式化、代码检查、cmake管理配置)
day03 C++项目开发配置最佳实践(vscode远程开发配置、格式化、代码检查、cmake管理配置)
会玩code
2022/08/30
3.6K0
【系列教程】 C++项目开发配置最佳实践(vscode远程开发配置、格式化、代码检查、cmake管理配置)
Sonar Scanner 之 C++扫码篇
本文将解决上一篇中的一个问题 1)为什么C++项目扫出来缺陷、安全漏洞都是0?覆盖率也是0%?
Antony
2020/12/01
8K0
Sonar Scanner 之 C++扫码篇
从零开始构建向量数据库:Milvus 的源码编译安装(一)
我在知乎上开了一个新的专栏[1],想持续聊聊“向量数据库”相关的内容。本篇聊聊向量数据库领域,知名的开源技术项目:Milvus。
soulteary
2023/03/05
5.9K0
从零开始构建向量数据库:Milvus 的源码编译安装(一)
【可测试性实践】C++ 单元测试&代码覆盖率统计
最近在调研C++工程怎么做单元测试和代码覆盖率统计,由于我们工程有使用Boost库,尝试使用Boost.Test来实现单元测试并通过Gcov和Lcov来生成代码覆盖率报告。本文记录完整的搭建测试Demo,希望能带来一定参考。
巫山老妖
2024/09/12
3210
【可测试性实践】C++ 单元测试&代码覆盖率统计
对代码质量进行检查
今天习得了一个不错的项目代码质量检测工具,并且在自己的 IDE 上进行安装,这一实践不要紧,感觉还是很不错的。后来查了文档,这个工具不仅可以在 IDE 上来使用,在项目的持续集成部署上面,依然有用武之地,可以提高项目的代码质量。也就是说在你项目根目录下的 gitlab-ci.yml 文件中把它作为一个持续集成部署中的一个 pipeline,就可以对你上线代码的质量进行把控。这个工具的名字就是 SonarQube,同时针对 JetBrains 也有一款起相同作用的工具 Qodana。
用户1413827
2023/11/28
4280
对代码质量进行检查
C++语言的单元测试与代码覆盖率
直接交付没有经过测试的代码是不太好的,因为这很可能会浪费整个团队的时间,在一些原本早期就可以发现的问题上。而单元测试,就是发现问题一个很重要的环节。
顾翔
2019/12/11
3.3K0
C++语言的单元测试与代码覆盖率
SonarQube:为你的PHP代码质量保驾护航
SonarQube是一个开源的代码质量管理平台,用于检测代码中的错误、漏洞和代码规范。它可以与多种工具集成,如Gitlab、Jenkins等,以便在项目拉取后进行连续的代码检查。SonarQube旨在提供一个完整的代码质量管理解决方案,支持多种计算机编程语言,并内置大量常用代码检查规则。
Tinywan
2024/01/10
6170
SonarQube:为你的PHP代码质量保驾护航
CI 中一次单元测试覆盖率问题定位分析
最近一次开发人员提交代码有目录删除,CI的编译环节和单元测试都没有错误,但是单元测试覆盖率执行失败? 提示如下: 开始时间:2017-09-11 17:03:22 结束时间:2017-09-11 17:03:43 耗时:21秒 【执行结果】 单元测试覆盖率执行失败! 【失败原因】 Do lcov failed…
DevOps时代
2018/12/26
1.1K0
对不起,增量覆盖率门禁我们原生支持了
在SonarQube 8之后,官方提供了专门的针对 Pull Request的代码扫描方式,再结合质量门禁中的增量代码(new code)覆盖率指标,可以说是原生支持增量代码覆盖率的诉求了,如下图所示,
Antony
2021/11/09
1.8K1
Java代码质量检查
又搞一边质量扫描插件,之前做过一遍,然后后面各种忽略,然后就放弃了,所以,应该寻找一种方法,循序渐进的实施。本次将实施一个基本的打包扫描方案,包含
Ryan-Miao
2019/06/15
2.8K0
图数据库 Nebula Graph 的代码变更测试覆盖率实践
对于一个持续开发的大型工程而言,足够的测试是保证软件行为符合预期的有效手段,而不是仅仅依靠 code review 或者开发者自己的技术素质。测试的编写理想情况下应该完全定义软件的行为,但是通常情况都是很难达到这样理想的程度。而测试覆盖率就是检验测试覆盖软件行为的情况,通过检查测试覆盖情况可以帮助开发人员发现没有被覆盖到的代码。
NebulaGraph
2020/04/22
9630
图数据库 Nebula Graph 的代码变更测试覆盖率实践
C/C++ 项目必读:代码格式化和静态分析检查的一站式工作流 Cpp Linter
目前 C/C++ 语言的代码格式化和检查工具使用的最为广泛的是 LLVM[1] 项目中的 Clang-Format[2] 和 Clang-Tidy[3]。
Peter Shen
2022/11/30
1.6K0
C/C++ 项目必读:代码格式化和静态分析检查的一站式工作流 Cpp Linter
如何做Git项目的持续集成
持续集成(简称CI)指的是在代码提交的过程中持续地进行代码的集成、构建和自动化测试;借助CI工具,可以在代码提交的过程中通过单元测试等方式尽早地发现引入的问题。一般项目中,我们可以借助持续集成达到质量前移的目的。
用户5521279
2019/10/31
1.9K0
如何做Git项目的持续集成
统计c++服务的接口测试用例覆盖率
最近想统计一个c++的server 的http接口的对代码的覆盖率情况,但之前做的覆盖率统计都是Unittest的覆盖率,而且一般都是统计非daemon程序的,查了一下,daemon也可以使用gcov+lcov来生成覆盖率信息,简单记录了一下;
用户5521279
2019/06/02
2K0
SonarQube社区版分支插件V1.3.0更新
下载release插件,现在最新版本是1.3.0, 下载后将jar包放到extensions/plugins和lib/common目录中。注意如果使用的其他用户操作需要授权插件给sonarqube权限。此时重启即可。
DevOps云学堂
2020/05/08
3.1K22
SonarQube社区版分支插件V1.3.0更新
推荐阅读
相关推荐
代码覆盖率--gcov/lcov/gcovr
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验