一、表定义
下面我们跟着sonar里面几张重要的表来分析里面的几个概念以及数据的存储关系。抛开规则相关的表,sonar中最重要的莫过于以下几张表
一个项目下面包含多个分支,一个分支中有多个组件,一个问题归属某个分支,也归属某个组件;
1、projects表
sonar项目表,该表记录了我们在sonar的项目页面可以看到的项目列表
字段名 |
类型 |
说明 |
uuid |
varchar(40) |
项目数据唯一标识 |
kee |
varchar(400) |
sonar项目的KEY |
name |
varchar(2000) |
sonar项目名(页面展示) |
qualifier |
varchar(100) |
项目类型 |
当我们通过sonar.projectKey和sonar.projectName
来执行sonar scanner命令时,其值与该表中的字段对应。页面效果:
2、project_branches表
一个项目下可以包含多个分支,该表便是记录了分支信息
字段名 |
类型 |
说明 |
uuid |
varchar(50) |
分支数据唯一标识 |
project_uuid |
varchar(50) |
项目uuid |
kee |
varchar(255) |
分支名,里面master |
branch_type |
varchar(12) |
分支类型,例如:BRANCH |
merge_branch_uuid |
varchar(50) |
合并分支uuid |
当我们指定sonar.branch.name
时,便会在这里被记录。
3、components表
所谓组件就是一个个文件,包括文件夹。该表会记录某个分支下有多少被扫描的组件
字段名 |
类型 |
说明 |
uuid |
varchar(50) |
组件标识 |
name |
varchar(2000) |
组件名 |
long_name |
varchar(2000) |
组件名 |
qualifier |
varchar(10) |
组件类型:TRK、DIR、FIL |
language |
varchar(20) |
组件的开发语言 |
project_uuid |
varchar(50) |
与分支表的uuid一致 |
module_uuid |
varchar(50) |
组件模块uuid |
root_uid |
||
main_branch_project_uuid |
varchar(50) |
主分支的组件,该字段为空 |
4、issues表
当对某个组件根据某些规则进行扫描时,对于产生的问题都会被记录到这里
字段名 |
类型 |
说明 |
project_uuid |
varchar(50) |
与分支表的uuid一致 |
component_uuid |
varchar(50) |
与组件表的uuid一致 |
line |
int4 |
问题产生的行号 |
checksum |
varchar(1000) |
问题行的校验和 |
rule_uuid |
varchar(40) |
规则的uuid |
issue_type |
int2 |
问题类型,1:异味;2:bug;3:漏洞;4:安全热点 |
severity |
varchar(10) |
问题严重性:BLOCKER[阻断]、CRITICAL[严重]、MAJOR[主要]、MINOR[次要]、INFO[提示] |
manual_severity |
bool |
是否是人工调整的级别 |
status |
varchar(20) |
问题状态:OPEN,CONFIRMED,RESOLVED,REOPENED |
resolution |
varchar(20) |
决议,例如:FALSE-POSITIVE |
message |
varchar(4000) |
问题描述 |
author_login |
varchar(255) |
问题责任人 |
assignee |
varchar(255) |
分配问题到的人 |
issue_creation_date |
int8 |
问题创建时间,例如:1697511737000 |
issue_update_date |
int8 |
问题更新时间 |
issue_close_date |
int8 |
问题关闭时间(sonar关闭) |
这个表是重点,下面会对某些字段进行说明
1)问题类型(issue_type)
- 错误(Bug):可能导致运行时出现错误或意外行为的编码错误。
- 漏洞(Vulnerability):代码中容易受到攻击的点。
- 代码异味(Code Smell):一个可维护性问题,使代码混乱且难以维护。
2)问题严重性(severity)
如果一个问题影响多个软件质量,则它可能具有多个严重性。例如,问题可能对软件的安全性产生很大影响,但对其可维护性的影响很小。随着规则的更新,这将适用于越来越多的问题。
1)阻断(BLOCKER):很有可能影响应用程序在生产环境中的行为的 bug。例如,内存泄漏或未关闭的 JDBC 连接是必须立即修复的 BLOCKER。
2)严重(CRITICAL):影响生产中应用程序行为的可能性较低的 bug 或表示安全漏洞的问题。空的捕获块或SQL注入将是一个关键问题。必须立即审查代码。
3)主要(MAJOR):质量缺陷,可能会严重影响开发人员的生产力。一段未覆盖的代码、重复的块或未使用的参数是主要问题的示例。
4)次要(MINOR):一个质量缺陷,可能会稍微影响开发人员的生产力。例如,行不应该太长,“switch”语句应该至少有3个案例,都被认为是小问题。
5)信息(INFO):既不是错误也不是质量缺陷,只是一个发现。
严重性(severity)在SonarQube 10.2中进行了演变,映射关系如下
Old Severity |
Mapped to |
Blocker, Critical |
High |
Major,Medium |
Minor |
Info |
Low |
3)问题状态(status)
问题创建后,问题流经生命周期,采用以下状态之一:
- 开放(Open):由SonarQube在新问题上设置。
- 已确认(Resolved):手动设置以指示问题有效。
- 已解决(Resolved):手动设置以指示下一次分析应关闭问题。
- 重新打开(Reopened):当已解决的问题尚未实际更正时,由SonarQube自动设置。
- 已关闭(Closed):由SonarQube为自动创建的问题自动设置。
4)决议(resolution)
已关闭的Issue将具有以下解决方案之一
- 修复(Fixed):当后续分析显示问题已更正或文件不再可用(从项目中删除、从项目中排除或重命名)时自动设置。
- 已删除(Removed):当相关规则不再可用时自动设置。该规则可能不可用,因为它已从质量配置文件中删除,或者因为底层插件已被卸载。
已解决的问题将具有以下解决方案之一
- 误报(False Positive):手动设置
- 无法修复(Won't Fix):手动设置
在以下情况下,问题(Issue)将自动关闭(状态:已关闭)
- 任何状态的问题都已正确修复 = 解决方案:已修复
- 问题不再存在,因为相关编码规则已停用或不再可用(例如,插件已被删除)= 解决方案:已删除
在以下情况下,问题会自动重新打开(状态:重新打开)
- 手动解决为“已修复”且未标记为“误报”的问题在后续分析中显示仍然存在。
5)问题责任人(author_login)
问题第一次出现时候的代码提交人,如果是Git,则为Git中配置的email。
默认情况下,某些 CI 不会获取完整的 Git 历史记录。例如,TravisCI 只获取最后 50 个 git 提交。您必须使用 git fetch --unshallow 来获取完整的历史记录。否则,系统可能不会将新问题分配给正确的开发人员。
6)问题创建时间(issue_creation_date)
问题第一次出现时候的提交时间。
二、数据统计
通过以下SQL我们可以得到各个项目下各个分支下的问题数据,基于该SQL我们还可以向上统计出其它维度的数据。
select
p.kee as project_kee,
p.name as project_name,
pb.kee as branch_name,
i.project_uuid as branch_uuid,
i.component_uuid ,
i.line ,
i.rule_uuid ,
i.issue_type ,
i.severity ,
i.issue_creation_date,
i.status ,
i.resolution
from
issues i
inner join project_branches pb on
i.project_uuid = pb.uuid
and i.line is not null
and i.author_login is not null
inner join projects p on
p.uuid = pb.project_uuid
当然,如果要统计项目维度的数据,可以根据以下字段对上面的结果进行去重
project_kee,
project_name,
component_uuid ,
line ,
rule_uuid ,
issue_type ,
severity,
issue_creation_date
三、对问题的理解
1、“新问题”定义
为了确定问题的创建日期,在每次分析期间都会执行一种算法,以确定问题是新的还是以前存在的。此算法依赖于报告问题的行的内容哈希(不包括空格)。对于多行问题,使用第一行的哈希。对于每个文件(在检测到文件重命名后),算法会获取先前分析中问题的基本列表,并尝试将这些问题与新分析报告的原始问题列表进行匹配。该算法尝试首先使用最强的证据进行匹配,然后回退到较弱的启发式方法。
- 如果问题位于同一规则上,具有相同的行号和相同的行哈希(但不一定具有相同的消息):MATCH
- 检测文件内的块移动,然后如果问题在同一(移动)行和同一规则上(但不一定具有相同的消息):MATCH
- 在同一规则上,使用相同的消息和相同的行哈希(但不一定具有相同的行):MATCH
- 在同一规则上,使用相同的消息和相同的行号(但不一定具有相同的行哈希):MATCH
- 在同一规则和相同的行哈希上(但不是相同的消息,也不是同一行):MATCH
- 是否有匹配的已关闭问题:匹配并重新打开
不匹配的“基本”问题已关闭并被视为已修复。 无与伦比的“原始”问题被认为是新的。
2、问题回溯
一旦如上所述确定一个问题是“新的”问题,下一个问题是给出它的日期。例如,如果问题在代码中存在很长时间,但由于将新规则添加到配置文件中,仅在最近的分析中发现,该怎么办?这个问题应该标明其行中最后一次修改的日期,还是首次提出这一问题的分析日期?也就是说,它应该回溯吗?如果上次更改线路的日期可用(这需要SCM集成),则在以下情况下问题将被回溯:
- 在项目或分支的第一次分析中
- 当规则在配置文件中是新规则时(已激活的全新规则或已停用但现已激活的规则)
- 当SonarQube刚刚升级时(因为规则实现现在可以更智能)
- 当规则是外部规则时
因此,回溯可能会将新提出的问题排除在新代码之外。
3、自动问题分配
在分析过程中,如果提交者可以与 SonarQube 用户相关联,则新问题会自动分配给问题行上的最后一个提交者。请注意,目前无法自动分配文件以上任何级别的问题(例如,在目录或项目级别报告的问题)。
4、技术审查
“确认”、“误报”、“不会修复”、“严重性更改”和“解决”操作都属于此类别,该类别假定对问题进行初步评审以验证其有效性。假设是时候审查上一个审查期间添加的技术债务了;此时间段可以是一天、一周或整个冲刺 (sprint)。您浏览每个新问题并分配以下之一:
- 确认(Confirm):通过确认问题,您基本上会说“是的,这是一个问题。这样做会将其从“打开”状态移动到“已确认”。
- 误报(False Positive):在上下文中查看问题,您意识到无论出于何种原因,此问题实际上都不是问题。因此,您将其标记为误报并继续。此审阅分配需要项目的“管理问题”权限级别。
- 严重性更改(Severity change):这是前两个选项之间的中间地带。是的,这是一个问题,但它并不像规则的默认严重性那样糟糕。或者也许这实际上是一个更糟糕的问题。无论哪种方式,您都可以调整问题的严重性,使其符合您认为应得的。此审阅分配需要项目的“管理问题”权限级别。
- 无法修复(Won't Fix):在上下文中查看问题,您会意识到虽然这是一个有效的问题,但它实际上不需要修复。换句话说,它代表了公认的技术债务。因此,您将其标记为“无法修复”并继续前进。此审阅分配需要项目的“管理问题”权限级别。
- 解决(Resolve):如果您认为自己已解决未解决的问题,可以解决它。如果正确,下一次分析会将其移至已关闭状态。如果您错了,它的状态将变为重新打开。
如果您倾向于将许多问题标记为误报或无法修复,则意味着某些编码规则不适合您的上下文。您可以完全停用质量配置文件中的问题,也可以使用问题排除项来缩小规则的焦点,以便它们不会用于应用程序的特定部分(或对象类型);查看有关定义分析范围的文档,了解有关包含和排除的更多详细信息。同样,进行大量严重性更改应提示你考虑更新配置文件中的规则严重性。
5、处置
一旦问题通过了技术审查,就该决定谁来处理它们了。默认情况下,议题分配给议题行上的最后一个提交者(在提出议题时),但您当然可以将它们重新分配给自己或其他人。任务分配对象将收到有关任务的电子邮件通知,但前提是他们注册了通知,并且任务将显示在问题显示的所有位置,包括“我的帐户”空间的“我的问题”列表中。
四、分支分析
1、主分支
这是默认分支,通常对应于为下一个版本开发的内容。此分支在开发团队中通常称为“main”、“develop”或“head”,并在未提供特定分支参数时进行分析。SonarQube 将此分支标记为主分支,并且对于社区版,这是您唯一可以分析的分支。
注意:主分支始终受到保护,即使它处于非活动状态,也不会自动删除。这无法更改
2、选择新主分行的影响
选择新的主分支会影响:
- 新代码:当项目的某些分支使用主分支作为参考分支时,更改主分支不会更新新的代码设置。所有分支继续指向上一个主分支。如果希望引用分支指向新的主分支,则必须手动更新新的代码设置。
- 应用程序:应用程序的主分支始终引用项目的主分支,更改项目的主分支会更改应用程序的主分支。当项目的主分支发生更改时,将自动安排应用程序重新计算(请参阅管理应用程序>计算)。更改项目的主分支后,可能需要几分钟才能传播到应用程序。
- 项目组合:项目组合不同于应用程序,因为它们可以引用项目的主分支,也可以专门引用项目的分支。
- 在第一种情况下,如果更改项目的主分支,项目组合将开始引用项目的新主分支。重新计算机制与应用程序的机制相同。
- 在第二种情况下,更改项目的主分支不会更改项目组合,因为项目组合引用的是特定分支。
- 分支分析:
- 对 CI 设置的影响:从开发人员版开始,可以在不传递显式分支名称 (sonar.branch.name) 的情况下分析分支。在这种情况下,分析会自动指向项目的主分支。如果更改主分支,则可能会无意中将旧主分支中的分析转到新分支。为避免这种情况,请确保分支分析始终指向特定分支。
- 对分析处理的影响:如果在后台任务负载繁忙期间更改主分支,则可能会影响处理分析报告的某些后台任务。这可能会导致状态不一致。解决方案是重新分析项目。这将使所有内容恢复到一致的状态。
3、设置分支分析
在分析过程中传递 sonar.branch.name 参数时,将创建一个分支
扫描程序(Scanners)在以下 CI 服务上运行时可以自动检测分支参数:
- Azure Pipelines
- Bitbucket Pipelines
- Cirrus CI
- Codemagic
- GitHub Actions
- GitLab CI/CD
- Jenkins(配置了分支源代码插件)
手动设置分支参数将覆盖自动检测。
4、问题创建和同步
在第一次分析期间,问题(type, severity, status, assignee, change log, comments)与主分支同步。在每个同步的问题中,都会在分支上问题的更改日志中添加一条注释:The issue has been copied from branch 'main' to branch '<branch>'
在每次对分支进行后续分析时,主分支中来自拉取请求的任何新问题都会自动从拉取请求继承其属性(type, severity等)。在分支上问题的更改日志中添加了一条注释:The issue has been merged from '<branch-1>' into '<branch-2>'
如果使用引用分支新代码定义,则可以在分支之间同步问题。使用此新代码定义时,引用分支中来自功能分支的任何新问题都会自动从功能分支继承其属性(类型、严重性等)。在分支上问题的更改日志中添加了一条注释:The issue has been merged from '<branch-1>' into '<branch-2>
.
5、管理非活动分支
连续七天以上未扫描的项目和分支被视为非活动状态,SonarQube 会自动删除其缓存数据以释放数据库中的空间。
如果项目有多个分支,则七天后仅删除其非活动分支的缓存。
您可以使用内务管理自动删除处于非活动状态的分支(即旧功能分支)或保留要继续维护的非活动分支(即释放分支)。
6、使用模式保持非活动分支
可以使用命名模式来保护特定分支(如发布分支)不被自动删除。为此,请在“管理>常规设置”>“内务管理”>“分支”>“分支”下使用 Java 正则表达式添加模式,以便在全局或项目级别处于非活动状态时保留。当使用遵循这些模式之一的名称创建分支时,它将无限期地保留。
例如,添加模式 release/.* 将保留名为 release/6.0、release/7 等的任何分支。
注意:模式不具有追溯性,不适用于已创建的分支。它们仅适用于设置模式后创建的分支。您可以在项目级别保护现有分支。请参阅以下部分。
五、新代码定义
为您的项目设置相关的新代码定义是充分利用 SonarQube 的重要一步。您可以从以下选项中进行选择:
- 以前的版本:在全局、项目和分支级别可用。建议用于具有常规版本或版本的项目。将新代码定义为自项目的最新版本增量以来已更改的任何代码。项目的当前版本以不同的方式确定,具体取决于生成系统:
- 如果使用 SonarScanner for Maven 完成分析,则 SonarQube 会从 pom.xml 文件中读取版本。
- 如果使用 SonarScanner for Gradle 完成分析,则 SonarQube 会从 gradle.build 文件中读取版本。
- 在所有其他情况下,必须通过设置分析参数 sonar.projectVersion 来显式指定版本。
- 天数:在全局、项目和分支级别可用。建议用于持续交付后的项目。将新代码定义为在过去 X 天内更改的任何代码(最多 90 天)。例如,将“天数”设置为 30 会创建一个从当前日期前 30 天开始的新代码周期。如果 30 天后未对新问题执行任何操作,则此问题将成为整个代码的一部分。
超过 90 天的代码不能被视为新代码,旧问题不应成为优先事项。如果在升级到 SonarQube 10.2 或更高版本之前将此选项设置为大于 90 的值,则会自动更改为 90。因此,某些问题可能会移出新代码。
- 特定分析(Specific analysis)[仅限 Web API]:选择以前的分析作为新代码定义。自该分析以来所做的任何更改都被视为新代码。为了更好地符合“清理即代码”方法,无法在 UI 中设置此选项,因为它需要频繁的用户操作才能保持最新。可用:
- 在开发者版及更高版本的分支级别
- 在社区版的项目级别,因为该版本不支持多个分支
- 引用分支(Reference branch):在项目和分支级别可用。建议用于使用功能分支的项目。选择一个特定的分支来定义新代码。您的分支与扫描程序在分析时有权访问的克隆中的引用分支之间的任何差异都被视为新代码。为避免克隆存储库时出现引用错误,我们建议克隆其所有分支。
在分支的初始分析中,可以使用 scanner 参数指定引用分支,从而覆盖全局新代码定义。有关为各种参数设置层次结构和说明的详细信息,请参阅分析参数页面。