玩转一下 SonarQube
SonarQube 介绍
SonarQube 社区版是开源的代码质量管理平台,涵盖了架构设计、注释、编码规范、潜在缺陷、代码复杂度、单元测试、重复代码 7 个维度。通过强大的插件扩展机制,支持对主流编程语言的指标分析,目前可以支持超过 20 种以上主流编程语言。
SonarQube 在进行代码质量管理时,会从下图所示的七个纬度来分析项目的质量。
SonarQube 在进行代码质量管理时,会从七个纬度来分析项目的质量。
- 糟糕的复杂度分析:文件、类、方法等,如果复杂度过高将难以改变,这会使得开发人员难以理解它们,且如果没有自动化的单元测试,对于程序中的任何组件的改变都将可能导致需要全面的回归测试。
- 重复:显然程序中包含大量复制粘贴的代码是质量低下的,sonar 可以展示源码中重复严重的地方。
- 缺乏单元测试:可以很方便的统计并展示单元测试覆盖率。
- 没有代码标准:sonar 可以通过 PMD,CheckStyle,Findbugs 等等代码规则检测工具规范代码编写。
- 没有足够的或者过多的注释:没有注释将使代码可读性变差,特别是当不可避免地出现人员变动时,程序的可读性将大幅下降,而过多的注释又会使得开发人员将精力过多地花费在阅读注释上,亦违背初衷。
- 潜在的 bug:可以通过 PMD,CheckStyle,Findbugs 等等代码规则检测工具检测出潜在的缺陷。
issue 的类型分为五个:
- [Blocker]阻断:错误,高概率影响程序运行,例如:内存泄漏,未关闭的 JDBC 连接等等,代码必须修复。
- [Critical]严重:低概率影响程序运行活着一个安全漏洞的错误,例如:空 catch 块,SQL 注入等,这样的代码需要立即审查。
- [Major]主要:代码缺陷,影响开发人员的生产力,例如:裸露一段代码,复制代码块,未使用的参数,这样的代码需要关注或忽略。
- [Minor]次要:可能较少的影响开发人员生产力,这样的代码需要关注或忽略。。
- [info]信息:不是错误,也不是质量缺陷,只是发现而已,这样的代码可以忽略。
- 糟糕的设计:可以找出循环,展示包与包,类与类之间的相互依赖关系,可以检测自定义的架构规则。可以管理第三方的 jar 包,可以利用 LCOM4 检测单个任务规则的应用情况,检测耦合。
SonarQube 可以测量的关键指标,包括代码错误、 代码异味(code smells)、安全漏洞和重复的代码。
- 代码错误 是代码中的一部分不正确或无法正常运行、可能会导致错误的结果,是指那些在代码发布到生产环境之前应该被修复的明显的错误。
- 代码异味 不同于代码错误,被检测到的代码是可能能正确执行并符合预期。然而,它不容易被修复,也不能被单元测试覆盖,却可能会导致一些未知的错误,或是一些其它的问题。从长期的可维护性来讲,立即修复代码异味是明智之举。通常在编写代码的时候,代码异味并不容易被发现,而 SonarQube 的静态分析是一种发现它们的很好的方式。
- 安全漏洞 正如听起来的一样:指的是现在的代码中可能存在的安全问题的缺陷。这些缺陷应该立即修复来防止黑客利用它们。
- 重复的代码 也和听起来的一样:指的是源代码中重复的部分。代码重复在软件设计中是一种很不好的做法。总的来说,如果对一部分代码进行更改而另一部分没有,则会导致一些维护性的问题。例如,识别重复的代码可以很容易的将重复的代码打包成一个库来重复的使用。
- 为什么它那么重要
SonarQube 为组织提供了一个集中的位置来管理和跟踪多个项目代码中的问题。它还可以把持续的检查与质量门限相结合。一旦项目分析过一次以后,更进一步的分析会参考软件最新的修改来更新原始的统计信息,以反映最新的变化。这些跟踪可以让用户看到问题解决的程度和速度。这与 “尽早发布并经常发布”不谋而合。
另外,SonarQube 可使用 可持续集成流程,比如像 Hudson 和 Jenkins 这样的工具。这个质量门限可以很好的反映代码的整体运行状况,并且通过 Jenkins 等集成工具,在发布代码到生产环境时担任一个重要的角色。
本着 DevOps 的精神, SonarQube 可以量化代码质量,来达到组织内部的要求。为了加快代码生产和发布的周期,组织必须意识到它们自己的技术债务和软件问题。通过发现这些信息, SonarQube 可以帮助组织更快的生成高质量的软件。
组件组成
- sonarqube server : 他有三个程序分别是 webserver(配置和管理 sonar) searchserver(搜索结果返回给 sonarUI) ComplateEngineserver(计算服务 将分析结果入库)。
- sonarqube db : 数据库 存放配置。
- sonarqube plugins: 插件增加功能。
- sonar-scanner : 代码扫描工具 可以有多个。
SonarQube 各组件的工作流程
- 开发者在 IDE 中编码,并使用 SonarLint 执行本地代码分析;
- 开发者向软件配置管理平台(Git,SVN,TFVC 等)提交代码;
- 代码提交触发持续集成平台自动构建、使用 SonarQube Scanner 执行分析;
- 分析报告被发送到 SonarQube Server 进行处理;
- 处理好的报告生成对应可视化的视图,并将数据保持到数据库;
- 开发者可以在页面通过查看,评论,解决问题来管理和减少技术债;
SonarQube 中的一些重要概念
指标:SonarQube 中的主要指标有可靠性,安全性,可维护性,测试覆盖率,复杂度,重复代码,规模(大小),问题等。
- 代码规则:在 SonarQube 中,通过插件提供的规则,在执行代码分析时对代码进行分析并生成问题。由于规则中定义了修复问题话费的成本(时间),解决问题的代价以及技术债可以通过这些问题进行计算。规则一般有三种类型:可靠性(Bug),可维护性(坏味道),安全性(漏洞)。
- 质量配置:质量配置提供了根据需求配置一组代码规则的能力,这组代码规则将被用于分析某些指定的组件(项目)。例如,项目 A 对应什么编程语言,适用于那些代码规则等等。
- 质量阈:质量阈是一系列对项目指标进行度量的条件。项目必须达到所有条件才能算整体上通过了质量阈。例如,配置质量阈为新增 Bugs 大于 10,新代码可靠率低于评级 A,新代码可维护率低于评级 B,那分析完成后若指标符合这些标准,则代码质量将被认为是不合格的。
SonarQube Server 处理分析报告时,根据质量配置中的代码规则进行匹配,从而生成具体的指标数据,然后根据质量阈中的阈值判断出项目的代码是否合格。
下载社区版
maven 配置 详见
<settings>
<pluginGroups>
<pluginGroup>org.sonarsource.scanner.maven</pluginGroup>
</pluginGroups>
<profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- Optional URL to server. Default value is http://localhost:9000 -->
<sonar.host.url>
http://localhost:9000
</sonar.host.url>
</properties>
</profile>
</profiles>
</settings>
在项目 pom.xml 中添加 maven 插件,以及 排除文件 。
<properties>
<sonar.exclusions>**/persistence/generated/*.java</sonar.exclusions>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.6.0.1398</version>
</plugin>
</plugins>
</build>
运行 mvn clean verify sonar:sonar
,或者不修改项目 pom 配置,直接运行 mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar
Sonar 项目主要指标以及代码坏味道详解
Reliability 可靠性
Reliability Rating
可靠性比率的计算方法
- A = 0 Bug 最高等级 A,表示代码无 bug
- B = at least 1 Minor Bug 代码只要有一个次要 bug,等级就为 B
- C = at least 1 Major Bug 只要包含一个重要 bug,等级将为 C
- D = at least 1 Critical Bug 只要有一个严重 bug,等级评估为 D
- E = at least 1 Blocker Bug 只要有一个最高等级的阻断级别的 bug,可靠性评估为 E,最低级别。
Reliability remediation effort 修复所有缺陷问题成本/耗时
Reliability remediation effort on new code 在新增代码上修复所有缺陷问题成本/耗时
备注
图中气泡大小根据 bug 数变化,bug 数越大气泡越大。视觉更加直观。
Security 安全性
Security Rating
安全度指标计算方法
- A = 0 Vulnerability 没有漏洞时,项目评估为最高级别 A
- B = at least 1 Minor Vulnerability 只要包含一个次要漏洞,项目评估为级别 B
- C = at least 1 Major Vulnerability 只要包含一个重要漏洞,项目评估为级别 C
- D = at least 1 Critical Vulnerability 只要包含一个严重漏洞,评估为 D
- E = at least 1 Blocker Vulnerability 只要包含一个阻断漏洞,项目评估为最低级别 E
备注
lines of code 计量方法:包括至少一个字符,不包括空格。
图中气泡大小根据漏洞数变化,漏洞数越大气泡越大。视觉上直观显示。
Maintainability 可维护性
Technical Debt
技术债务 概念,这个概念最早是在 1992 年由 Ward Cunningham 在他的论文“The WyCash Portfolio Management System”中提出的,之后被软件工程界接受并推广,《重构》的作者 Martin Fowler 也在其网站上对技术债务有所介绍。其实原理可以理解为“出来混早晚要还的”,当前不规范的代码,会对以后产品修改的成本造成影响。Technical Debt 计算公式如下:
开发成本
开发一行代码(LOC)的成本。 示例:如果开发 1 LOC 的成本估计为 30 分钟,则此属性的值为 30。目前我们采用的是系统默认值 30。注意此处成本是指从零开始重写代码所需的成本。
可维护性
可维护性等级范围从 A(非常好)到 E(非常差)。 评级由技术债务比率的值决定,技术债务比率是将项目的技术债务与从零开始重写代码所需的成本进行比较。 A 到 D 的默认值为 0.05,0.1,0.2,0.5。任何超过 0.5 评级就为 E。
举个例子:假设开发成本是 30 分钟,2,500 LOC 的技术债务为 24,000 分钟的项目将有技术债务比率为 24000 /(30 * 2,500)= 0.32。 因此项目的可维护性评级就是 D。
Coverage 覆盖率
Coverage
行覆盖和条件覆盖的混合。单元测试覆盖多少源代码。Coverage = (CT + CF + LC)/(2*B + EL),其中 :
- CT = conditions that have been evaluated to ‘true’ at least once 至少有一次被判断为 true 的条件数
- CF = conditions that have been evaluated to ‘false’ at least once 至少一次被判断为 false 的条件数
- LC = covered lines = lines_to_cover uncovered_lines 已覆盖的行数
- B = total number of conditions 条件总数
- EL = total number of executable lines (lines_to_cover) 所有可执行的代码总行数
Line coverage
单元测试覆盖行数密度
Line coverage = LC / EL
- LC = covered lines (lines_to_cover - uncovered_lines) 已覆盖的行数
- EL = total number of executable lines (lines_to_cover) 所有可执行的代码总行数
Condition coverage
Condition Coverage=(CT+CF)/(2*B)
- CT = 至少一次使用 ‘true’的条件数
- CF = 至少一次使用 ‘false’ 的条件数
- B = 条件总数
Unit test success density (%)
测试成功密度=(单元测试总数-(单元测试错误数+单元测试失败数))/单元测试数*100
Duplications 重复
Duplication
SonarQube 使用自己的复制/粘贴检测引擎,可以检测重复:
- 在源文件中
- 跨项目中的多个文件
- 项目的各个模块
- 跨多个项目
Duplicated Lines(%)
重复率=重复行数/总行数*100
- Duplicated blocks:重复代码块行数
- Duplicated files:重复文件数
- Duplicated lines:重复行数
处理 Duplicated
- 分析这些重复,并通过使用继承或其他合适的模式来消除它们(只有在要对块进行单元测试时才这样做)
- 将复制的更改复制到复制的块上
- 使用问题和技术债务机制,通过编辑质量配置文件以包括来自公共 Sonar 存储库的复制块规则,监控成本并跟踪此错误的修复。
Size 大小
Complexity 复杂度
Complexity 复杂度
以下关键词增加复杂性:if, for, while, case, catch, throw, return (不是方法的最后一个语句), &&, ||, ?
备注
else, default, finally 不增加复杂度
代码复杂度过高将难以理解、难以维护。
Code Smells 坏味道
某些东西会混淆维护者或在读代码时产生误导。有时,Bug 和 Code Smell 之间的界线是模糊的。 当有疑问时,问自己:“打破这条规则的代码是否是程序员想要的? 如果答案是“可能不是”,那么它是一个 Bug。 否则它就是一个代码坏味道。
Issues 问题
Open Issues
当前存在的全部问题
Reopened Issues
关闭后又重新打开的问题,可能由于之前误判关闭或者重新出现同样问题,需要再次将问题置为打开状态。
Confirmed Issues
确认的问题 - 通过确认问题,你基本上是承认:“是的,这是一个问题。” ,并将问题从“打开”状态移动到“已确认”状态。
False Positive Issues
误判问题-在上下文中查看问题,你意识到可能由于一些原因判定了这个问题,然而这个问题实际上不是一个问题,因此可以在此处标记为 False Positive,然后继续下一步。注意:做此判断的人需要拥有项目的管理员权限。
Won't Fix
不修复的问题 – 通过查看上下文中的关联,你意识到虽然这是一个有效的问题,实际上并不需要修复。因此可以在此处标记为 Won't Fix,然后继续下一步。注意做如此判断的人则需要拥有项目的管理员权限。
此 CI 非彼 CI
docker 安装
- docker pull sonarqube
- docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube
- http://myserver:9000
使用
- 编辑 maven 的 settings.xml
- 分析项目 mvn sonar:sonar
不明觉厉的代码质量说的到底是什么?
- 正确?严格符合规格说明书
- 相对灵活?
- 相对简单?
- 使用公开的算法?
- 使用了合适的语法?
- 没有重新发明轮子?
- 没有代码坏味?
- 代码紧凑?
- 代码逻辑清晰明了?
- 有良好的注释?
- 有良好的性能?
- 优雅?不晦涩?
按你胃,谁还有更好的定义?
码农的 7 个死穴-SonarQube 涵盖代码质量的 7 个维度
使用 MySQL 数据库
使用嵌入式 H2 数据库的话,SonarQube 会在下方一直显示一条警告信息:
有点碍眼,还是考虑切换到 MySQL 上吧。
Create a new MySQL Schema called sonar
# Create SonarQube database and user. # Command: mysql -u root -p < create_database.sql CREATE DATABASE sonar CHARACTER SET utf8mb4 COLLATE utf8_general_ci; CREATE USER 'sonar' IDENTIFIED BY 'sonar'; GRANT ALL ON sonar.* TO 'sonar'@'%' IDENTIFIED BY 'sonar'; GRANT ALL ON sonar.* TO 'sonar'@'localhost' IDENTIFIED BY 'sonar'; FLUSH PRIVILEGES;
Edit the properties sonar.jdbc.username, sonar.jdbc.password and sonar.jdbc.url in [sonar_qube_root_folder]/conf/sonar.properties file with the next values
sonar.jdbc.username=sonar sonar.jdbc.password=sonar sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance
Launch SonarQube (it applies for windows-x86–32)
- Go to [sonar_qube_root_folder]/bin/[architecture]/StartSonar.bat
- Go to http://localhost:9000/
安装中文包插件
在线安装
Administration->Marketplace->Plugins,搜索“chinese pack”,安装
离线安装
装完后就这样子了
mvn clean verify -DskipTests org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar \
-Dsonar.projectKey=cn.org.bjca.site:bjca-site \
-Dsonar.host.url=http://192.168.116.82:9000 \
-Dsonar.login=55fd8d17a90e78365675f70c7c4375075a6fecdd
命令行中指定排除目录
mvn clean verify -DskipTests org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar \
-Dsonar.projectKey=usercenter \
-Dsonar.host.url=http://192.168.116.82:9000 \
-Dsonar.login=5de9dda11579f5779d84f0802ba80ab62399ecc1 \
-Dsonar.exclusions=com/company/packageA/generated/**/*.java,com/company/packageB/generated/**/*.java
该种命令行指定了 sonar.host.url 的,不需要单独在~/.m2/settings.xml 中再配置 sonar 的信息了。
gitlab 集成
#.gitlab-ci.yml stages: - build build_master: image: maven stage: build artifacts: paths: - target/*.jar script: - mvn package sonar:sonar -Dsonar.host.url=http://192.168.116.82:9000/ only: - master
使用 Sonar Scanner 分析代码
参考:
- (官网]( https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner
- SonarQube Scanning in 15 Minutes
sonar-scanner \
-Dsonar.projectKey= my-stinky-php-files \
-Dsonar.sources=. \
-Dsonar.host.://localhost:9000 \
-Dsonar.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
如果发现
有数据但是点进去后并没有明细,尝试删除 ES 文件重启 sonar 服务
rm -rf sonarqube/data/es5
SonarQube Api 使用:
https://codeen-app.euclid-ec.org/sonar/web_api/api/measures
可以使用 http://192.168.126.182:9000/api/measures/component?componentId=AWkUMtOgOkBh-huuQOcL&metricKeys=ncloc,complexity,violations,bugs 来获取一个项目的基本信息,用于生成一些自定义的报表
https://docs.sonarqube.org/latest/user-guide/metric-definitions/
SonarQube Webhooks
Administration -> Configuration -> Webhooks
配置回调地址
调用接口参数示例
{"serverUrl":"http://localhost:9000","taskId":"AWkzSF8Qt6GvzYFKix3r","status":"SUCCESS","analysedAt":"2019-02-28T16:45:58+0800","changedAt":"2019-02-28T16:45:58+0800","project":{"key":"cn.bjca.footstone:typhon","name":"typhon","url":"http://localhost:9000/dashboard?id=cn.bjca.footstone%3Atyphon"},"branch":{"name":"master","type":"LONG","isMain":true,"url":"http://localhost:9000/dashboard?id=cn.bjca.footstone%3Atyphon"},"qualityGate":{"name":"Sonar way","status":"OK","conditions":[{"metric":"new_reliability_rating","operator":"GREATER_THAN","value":"1","status":"OK","onLeakPeriod":true,"errorThreshold":"1"},{"metric":"new_duplicated_lines_density","operator":"GREATER_THAN","status":"NO_VALUE","onLeakPeriod":true,"errorThreshold":"3"},{"metric":"new_maintainability_rating","operator":"GREATER_THAN","value":"1","status":"OK","onLeakPeriod":true,"errorThreshold":"1"},{"metric":"new_coverage","operator":"LESS_THAN","status":"NO_VALUE","onLeakPeriod":true,"errorThreshold":"80"},{"metric":"new_security_rating","operator":"GREATER_THAN","value":"1","status":"OK","onLeakPeriod":true,"errorThreshold":"1"}]},"properties":{}}
[GIN] 2019/02/28 - 16:46:19 | 200 | 249.315µs | 127.0.0.1 | POST /sonar
{"serverUrl":"http://localhost:9000","taskId":"AWkzTRMUt6GvzYFKix3u","status":"SUCCESS","analysedAt":"2019-02-28T16:51:08+0800","changedAt":"2019-02-28T16:51:08+0800","project":{"key":"cn.bjca.footstone:typhon","name":"typhon","url":"http://localhost:9000/dashboard?id=cn.bjca.footstone%3Atyphon"},"branch":{"name":"master","type":"LONG","isMain":true,"url":"http://localhost:9000/dashboard?id=cn.bjca.footstone%3Atyphon"},"qualityGate":{"name":"Sonar way custom","status":"ERROR","conditions":[{"metric":"new_reliability_rating","operator":"GREATER_THAN","value":"1","status":"OK","onLeakPeriod":true,"errorThreshold":"1"},{"metric":"new_duplicated_lines_density","operator":"GREATER_THAN","status":"NO_VALUE","onLeakPeriod":true,"errorThreshold":"3"},{"metric":"bugs","operator":"GREATER_THAN","value":"9","status":"ERROR","onLeakPeriod":false,"errorThreshold":"0"},{"metric":"new_maintainability_rating","operator":"GREATER_THAN","value":"1","status":"OK","onLeakPeriod":true,"errorThreshold":"1"},{"metric":"new_coverage","operator":"LESS_THAN","status":"NO_VALUE","onLeakPeriod":true,"errorThreshold":"80"},{"metric":"new_security_rating","operator":"GREATER_THAN","value":"1","status":"OK","onLeakPeriod":true,"errorThreshold":"1"}]},"properties":{}}
[GIN] 2019/02/28 - 16:51:27 | 200 | 97.476µs | 127.0.0.1 | POST /sonar
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: CSS3 制作圆环进度条
下一篇: 不要相信一个熬夜的人说的每一句话
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论