Sonar介绍
Sonar 是一个用于代码质量管理的开放平台。通过插件机制,Sonar 可以集成不同的测试工具、代码分析工具,以及持续集成工具。与持续集成工具(例如 Hudson/Jenkins 等
)不同,Sonar 并不是简单地把不同的代码检查工具结果(例如 FindBugs,PMD
等)直接显示在 Web 页面上,而是通过不同的插件对这些结果进行再加工处理,通过量化的方式度量代码质量的变化,从而可以方便地对不同规模和种类的工程进行代码质量管理。
Sonarqube
SonarQube 是一种自动代码审查工具,用于检测代码中的错误,漏洞和代码格式上的问题。它可以与用户现有的工作流程集成,以实现跨项目分支和提取请求的连续代码检查,同时也提供了可视化的管理页面,用于查看检测出的结果。作为Sonar 解决方案的核心元素 ,SonarQube 集成到用户现有的工作流程中并检测代码中的问题,以帮助用户对项目执行持续的代码检查。该工具可分析 30 多种不同的编程语言 ,并集成到用户的 CI 管道 和 DevOps 平台中 ,以确保其代码符合高质量标准。
结构
概念 | 定义 |
Analyzer | 分析源代码以计算 snapshots 的客户端应用程序。 |
Database | 存储配置和 snapshots。 |
Server | 用于浏览 snapshots 数据和进行配置更改的 Web 界面。 |
Sonarqube是sonar的服务端,相当于一个web服务器,用来发布应用,在线浏览、配置分析等。
源码中每个文件夹的作用
下面简单说一下每个文件夹的作用:
bin:sonarqube运行命令文件夹
conf:sonarqube配置文件夹
data:嵌入式数据库的数据(H2数据库引擎),建议只用于测试和演示
extensions:sonarqube的插件等存放文件夹
lib:sonarqube存放的运行库文件夹(jar)
logs:sonarqube日志文件夹
temp:sonarqube临时文件夹
web:sonarqube系统UI界面文件夹
四种类型规则
SonarQube对源代码执行规则以产生问题。有四种类型的规则:
代码异味(可维护性域):可维护性问题,代码是否混乱且难以维护。
错误(可靠性域):可能导致运行时错误或意外行为的编码错误。
漏洞(安全域):代码中容易受到攻击的点。
安全热点(安全域):突出显示开发人员需要检查的安全敏感代码段,和漏洞之间的主要区别是 ——在决定是否应用修复之前需要进行审查
质量门 Quality Gate
您的质量门是一组条件,可以告诉您项目是否已准备好发布。通过“代码清洁”方法,您的质量门应该:
- 专注于新的代码指标 - 当您的质量门设置为专注于新的代码指标(例如内置的 Sonar 方式质量门)时,新功能将干净地交付。只要您的质量门是绿色的,您的版本就会不断改进。
- 设定并执行高标准 – 当对新代码设定并执行标准时,您不必担心必须在旧代码中满足这些标准以及必须清理其他人的代码。您可以为 自己的 代码达到高标准而感到自豪。如果一个项目不符合这些高标准,它就无法通过质量关卡,因此无法发布。
- 成为代码质量的可靠衡量标准- 当您始终通过质量门时,您就清楚地表明开发人员可以对所有新代码保持高标准。
指标定义
复杂度
复杂度 ( complexity
):复杂度是指圈复杂度,是一种用于计算代码路径数量的定量指标。每当函数的控制流分裂时,复杂性计数器就会加一。每个函数的最小复杂度为 1。此计算因语言而略有不同,因为关键字和功能会有所不同。
重复
重复块 ( duplicated_blocks
):重复行块的数量。
重复文件 ( duplicated_files
):涉及重复的文件数量。
重复行 ( duplicated_lines
):涉及重复的行数。
重复行 (%) ( duplicated_lines_density
): duplicated_lines
/ (代码行数) * 100
问题
新问题 ( new_violations
):关于新代码首次提出的问题数量。
新 xxx 问题 ( new_xxx_violations
):新代码中首次提出的指定严重性问题的数量,其中 xxx 是以下之一: blocker
, critical
, major
, minor
, info
。
问题 ( violations
):所有州的问题总数。
xxx 问题 ( xxx_violations
):指定严重性的问题总数,其中 xxx 是以下之一: blocker
, critical
, major
, minor
, info
。
误报问题 ( false_positive_issues
):标记为误报的问题总数。
未解决问题 ( open_issues
):处于未解决状态的问题总数。
已确认问题 ( confirmed_issues
):处于已确认状态的问题总数。
重新打开的问题 ( reopened_issues
):处于重新打开状态的问题总数。
可维护性
代码异味 ( code_smells
):代码异味问题的总数。
新代码异味 ( new_code_smells
):新代码中首次提出的代码异味问题总数。
可维护性评级 ( ):(以前称为 SQALE 评级。)对项目的评级与技术负债率sqale_rating
的值相关。默认的可维护性评级网格为:
A=0-0.05,B=0.06-0.1,C=0.11-0.20,D=0.21-0.5,E=0.51-1
可维护性评级量表也可以这样表述:如果未完成的修复成本是:
- <=5% 已进入申请的时间,评级为 A
- 6% 到 10% 之间,评级为 B
- 11% 到 20% 之间,评级为 C
- 21% 到 50% 之间,评级为 D
- 任何超过 50% 的都是 E
技术债务 ( sqale_index
):修复所有代码异味的努力程度。该测量值以分钟为单位存储在数据库中。当值以天为单位显示时,假定每天有 8 小时。
新代码的技术债务 ( new_technical_debt
):修复新代码上首次出现的所有代码异味所需的工作量。
技术负债率 ( sqale_debt_ratio
):开发软件的成本与修复软件的成本之间的比率。技术负债率公式为:Remediation cost / Development cost
可以重述为:Remediation cost / (Cost to develop 1 line of code * Number of lines of code)
开发一行代码的成本值为 0.06 天。
新代码的技术负债率 ( new_sqale_debt_ratio
):开发新代码更改代码的成本与与其相关的问题的成本之间的比率。
可靠性
Bugs ( bugs
): Bug 问题的总数。
新错误 ( new_bugs
):新错误问题的数量。
可靠性评级 ( reliability_rating
)
A = 0 个错误
B = 至少 1 个小错误
C = 至少 1 个主要错误
D = 至少 1 个严重错误
E = 至少 1 个阻止错误
安全
漏洞 ( vulnerabilities
):漏洞问题的数量。
新代码上的漏洞 ( new_vulnerabilities
):新漏洞问题的数量。
安全评级 ( security_rating
)
A = 0 个漏洞
B = 至少 1 个次要漏洞
C = 至少 1 个主要漏洞
D = 至少 1 个严重漏洞
E = 至少 1 个阻止程序漏洞
尺寸
类 ( classes
):类的数量(包括嵌套类、接口、枚举和注释)。
注释行 ( comment_lines
):包含注释或注释掉的代码的行数。
非重要注释行(空注释行、仅包含特殊字符的注释行等)不会增加注释行数。
注释数(%) ( comment_lines_density
):注释行密度=注释行数/(代码行数+注释行数)*100
有了这样一个公式:
- 50%表示代码行数等于注释行数
- 100% 表示该文件仅包含注释行
目录 ( directories
):目录的数量。
文件 ( files
):文件数量。
行数 ( lines
):物理行数(回车数)。
代码行数 ( ncloc
):包含至少一个字符的物理行数,该字符既不是空格,也不是表格,也不是注释的一部分。
每种语言的代码行数 ( ncloc_language_distribution
):按语言分布的非注释代码行。
函数 ( functions
):函数的数量。根据语言的不同,函数可以定义为函数、方法或段落。
项目 ( projects
):投资组合中的项目数量。
语句 ( statements
):语句数。
测试
条件覆盖率 ( branch_coverage
):在包含一些布尔表达式的每一行代码上,条件覆盖率回答以下问题:“每个布尔表达式是否都被评估为true
和false
?”。这是单元测试执行期间遵循的流量控制结构中可能条件的密度。
条件覆盖率 = (CT + CF) / (2*B)
其中:
- CT = 至少一次被评估为“真”的条件
- CF = 至少一次被评估为“假”的条件
- B = 条件总数
新代码的条件覆盖 ( ):此定义与条件覆盖new_branch_coverage
相同,但仅限于新的/更新的源代码。
条件承保范围命中 ( branch_coverage_hits_data
):承保条件列表。
按行的条件 ( conditions_by_line
):按行的条件数。
按行覆盖的条件 ( covered_conditions_by_line
):按行覆盖的条件数。
覆盖范围 ( ):线路覆盖范围和条件覆盖范围coverage
的混合。其目标是提供更准确的答案“单元测试覆盖了多少源代码?”。
覆盖范围 = (CT + CF + LC)/(2*B + EL)
其中:
- CT = 至少一次被评估为“真”的条件
- CF = 至少一次被评估为“假”的条件
- LC = 覆盖线 = 覆盖线-未覆盖线
- B = 条件总数
- EL = 可执行行总数 (
lines_to_cover
)
新代码的覆盖率 ( ):此定义与覆盖率new_coverage
相同,但仅限于新的/更新的源代码。
行覆盖率 ( line_coverage
):在给定的代码行上,行覆盖率只是回答“在执行单元测试期间是否执行了这行代码?”的问题。它是单元测试覆盖的线的密度:
线路覆盖率 = LC / EL
其中:
- LC = 覆盖线 (
lines_to_cover
-uncovered_lines
) - EL = 可执行行总数 (
lines_to_cover
)
新代码的行覆盖率 ( ):此定义与行覆盖率new_line_coverage
相同,但仅限于新的/更新的源代码。
线路覆盖命中 ( coverage_line_hits_data
):覆盖线路的列表。
要覆盖的行数 ( lines_to_cover
):单元测试可以覆盖的代码行数(例如,空白行或完整注释行不被视为要覆盖的行)。
新代码上要覆盖的行 ( ):此定义与要覆盖的行new_lines_to_cover
相同,但仅限于新的/更新的源代码。
跳过的单元测试 ( skipped_tests
):跳过的单元测试的数量。
未覆盖的条件 ( uncovered_conditions
):单元测试未覆盖的条件数。
新代码上的未覆盖条件 ( ):此定义与未覆盖条件new_uncovered_conditions
相同,但仅限于新的/更新的源代码。
未覆盖行数 ( uncovered_lines
):单元测试未覆盖的代码行数。
新代码上未覆盖的行 ( ):此定义与未覆盖的行new_uncovered_lines
相同,但仅限于新的/更新的源代码。
单元测试 ( tests
):单元测试的数量。
单元测试持续时间 ( test_execution_time
):执行所有单元测试所需的时间。
单元测试错误 ( test_errors
):失败的单元测试数。
单元测试失败 ( test_failures
):因意外异常而失败的单元测试数量。
单元测试成功密度 (%) ( test_success_density
):测试成功密度 = (单元测试 - (单元测试错误 + 单元测试失败)) / (单元测试) * 100
SonarScanner
sonarqube-scanner相当于sonar客户端,SonarScanner是一个单独的客户端类型应用程序,与SonarQube服务器连接将运行项目分析,然后将结果发送到SonarQube服务器进行处理。SonarScanner可以处理SonarQube支持的大多数编程语言。它通常位于持续集成代理(工作线程)或单独的 docker 映像中,具体取决于项目流。
SonarQube主要分为几个模块:WebServer、CeServer、Scanner
其中Scanner是在本地执行扫描分析的工具,也就是说SonarScanner是在本地执行扫描分析之后将结果上传到服务端进行分析。本文重点介绍一下 Scanner 的源码和原理。
SonarScanner 的源码主要有三部分,一个是 SonarScannerCli 用来执行命令和接收参数(https://github.com/SonarSource/sonar-scanner-cli.git),另一个是 SonarScannerApi ,主要用来下载插件包和加载类 (https://github.com/SonarSource/sonar-scanner-api.git),还有真正用来执行扫描的 SonarScannerEngine (https://github.com/SonarSource/sonarqube/tree/master/sonar-scanner-engine)
Cppcheck
Cppcheck 是一种 C/C++ 代码缺陷静态检查工具。不同于 C/C++ 编译器及很多其它分析工具,它不检查代码中的语法错误。Cppcheck 只检查编译器检查不出来的 bug 类型,其目的是检查代码中真正的错误(即:零误报)。
支持的代码和平台:
1. 可以检查非标准代码,包括不同的编译器扩展、内联汇编代码等。
2. Cppcheck 应该在能够处理最新 C++ 标准的任何 C++ 编译器所编译。
3. Cppcheck 应该在有足够 CPU 和内存的平台上工作。
Cppcheck 的局限性:Cppcheck 很少在报告错误方面出错,但有一些 bug 无法检出。