随着业务的发展,程序员维护的系统会越来越庞大。原本一个简单稳定的功能,可能在迭代几次后复杂度上升,导致潜在的风险随之暴露,最终导致服务不稳定,造成业务价值的损失。因此,各位大佬们一致认为需要从源头抓起,从个人技术成长到工作流程标准化去提供系统稳定性。与此同时,我也在代码质量这个方向进行挖掘,试图通过代码质量分析去反向要求程序员提高代码编程能力,降低错误风险,这才有了今天的主角-SonarQube
从以下几个方向调研:
Sonarqube社区庞大,主流的VCS也在使用,是一款主流的代码质量分析产品,主要调研方向往Sonarqube开始展开
总结:社区版基本能满足日常工作需要,比起收费版本,我们可能要考虑下如何在master分支做代码分析,取得利益最大化。
SonarQube 是一个用于代码质量管理的开源平台,用于管理源代码的质量。 通过插件形式,可以支持包括 java, C#, C/C++, PL/SQL,
Cobol, JavaScrip, Groovy
等等二十几种编程语言的代码质量管理与检测。
SonarQube可以从以下七个维度检测代码质量,而作为开发人员至少需要处理前5种代码质量问题。
官方给出了典型的开发过程:
SonarQube工作流程包含3个组件:
问题共分为三种类型:
打开:问题被质量分析后的初始状态(SonarQube)
确认:问题修复后,需要开发人员手动指定,表示该问题已修复(开发人员)
误判:标记问题为误判,表示此问题不应该标记为问题,无需处理(管理员)
标记为不会修复:表示此问题不做处理(管理员)
重新打开:当SonarQube再次分析报告时,若问题再次暴露则显示为重新打开(SonarQube)
可以将问题分配给指定用户。
当问题分配给其他用户后,若该用户有启动提醒功能,则SonarQube会发送邮件进行告警
当Sonar分析报告后,会根据SCM的相关记录找到对应的用户,进行自动指派。
安全热点是SonarQube检测出来可能存在安全问题,需要项目管理员进行复审,确认是否存在问题。
复审状态总共有三个,分别为
在这个板块,SonarQube会解释为何是安全代码,且告诉你怎么修复。(英语不好的人建议翻译一下)
即SCM更新下来的代码,没啥区别,SonarQube自己也会存储一份
管理项目的基本配置,如
设置新代码周期的定义,默认按通用配置(即按上个版本的分析开始计算)。
也可以指定其他选项,如
“天数”:可以指定距离上次分析多少天的数据,作为新代码
“指定分析”:未知…(没看懂,跳过)
质量配置:表示项目适配的质量配置,质量配置都是基于语言的,一个质量配置下面会存在多个代码规则。
下图表示的项目qx_whale的质量配置基于java、xml两种语言,别分启用了452和11条代码规则。
质量阈:它是项目质量是否合格的标准,通过设置质量阈来判断项目的代码质量是否达标。
默认使用SonarQube内置的质量阈配置(Sonar way)
也可以自定义质量阈,如笔者定义的My Sonar Way,只要出现阻断违规问题,就达不到质量阈的要求
即项目-指标板块,展示项目的代码质量。 官方表示未来会废弃,所以不推荐大家使用
配置一些跳转链接,比如项目的首页地址。建议在SonarScanner运行时指定sonar.links.homepage去配置首页地址
当前项目的权限配置,后面用户与权限模块会特别介绍,这里就不赘述了
SonarQube每个项目的标识都是唯一的,请确保使用者的项目标识唯一!!!
俗称web hook,懂得都懂(可以与jenkins集成,将分析报告的质量阈状态回传,以便jenkins判断是否继续执行pipeline任务)
问题菜单跟“项目-问题”展示的基本一致。不同的是,问题菜单展示的是个人参与项目的所有问题,所以数量上相对比较多。
质量配置,用于定义编程语言的代码分析集合。一个质量配置可以配置多个代码规则
举个例子,我们看下质量配置/java下的代码规则详情
下图表示Java语言的质量配置模板Sonar way,共配置了452个激活的规则,187个未激活的规则,一共配置了639个规则。
内置质量模板Sonar way不允许修改,若用户想要自定义质量模板,必须拥有“质量配置管理员”的权限才可以进行操作。
回到质量模板MyJavaRule,可以看到我们配置了一条代码规则。那么质量配置就介绍到这里了。
什么情况下会使用到质量配置呢?
一般使用官方内置的Sonar way即可,如果有特殊需求的话,可以自己去定义质量模板。
质量阈是一系列基于指标的布尔表达式。它可以帮助我们实时了解项目是否已经满足生产要求了。理想情况下,所有项目使用相同的质量阈。每个项目的质量阈状态都会展示在首页。
上图表示,所有项目默认的质量阈均为Sonar way,指标解释:
新代码分析时,若覆盖率小于80% 或者 重复行大于3% 或者…安全比率劣于A时,判定为质量阈失败。
自定义质量阈,首先要有质量阈管理员的权限,可以参考下图设置(建议技术经理或者项目负责人设置此权限)
新建一个自定义质量阈MySonarWay,只添加一个条件,当阻断违规的问题大于0时,判定为质量阈失败。
同时,还可以指定哪些项目使用此质量阈
项目权限,用于设置公开或者私有
公开项目所有人都可以访问
私有项目只有访问权限的人可以访问(推荐)
角色大致上可以分为三种:系统管理员、技术经理、开发人员
系统管理员:只负责sonar平台的管理,不负责项目相关操作
技术经理:负责项目成员定义,项目组定义,权限分配,质量配置、质量阈等配置
开发人员:默认项目创建与项目执行分析,当开发人员创建项目时,该人员成为项目的管理者,拥有项目的所有权
配置默认权限模板(Default template),项目创建人拥有项目的所有权。
若技术经理也需要同等权力的话,可以主动申请成为项目的管理员(详见下图)
只有订阅了项目提醒,用户才会收到项目推送的邮件。在管理员进行问题分配给用户时,特别有用。
以下介绍如何进行项目提醒设置
SonarQube登录时,可以使用Gitlab进行授权登录,配置如下
服务端:SonarQube:8.9.2(LTS)(最低JDK11)
扫描器:SonarScanner(最低JDK8)
索引库:ElasticSearch(内置,无需安装)
数据库:Progresql(最低9.6)
内存要求:至少2GB RAM
下载点这里官方链接,建议使用版本8.9(LTS)
安装后进行解压,会有一个SonarQube文件夹,以下简称SONAR_HOME
特别注意,官方文档有说明SonarQube8.9+要使用jdk11的版本
# Path to JVM executable. By default it must be available in PATH.
# Can be an absolute path, for example:
#wrapper.java.command=/path/to/my/jdk/bin/java
# 配置sonarqube启动时的jdk版本
wrapper.java.command=/usr/local/webserver/jdk-11.0.13/bin/java
...
### web
sonar.web.host=10.10.10.15
sonar.web.port=9000
### 数据库(如果不配置,则启用内置的H2数据库)
sonar.jdbc.username=admin
sonar.jdbc.password=admin
sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube?currentSchema=my_schema
### 日志
sonar.path.logs=/www/sonarqube/logs/
服务端相关命令
# 启动
sh SONAR_HOME/bin/linux-x86-64/sonar.sh start
# 停止
sh SONAR_HOME/bin/linux-x86-64/sonar.sh stop
# 重启
sh SONAR_HOME/bin/linux-x86-64/sonar.sh restart
执行分析需要使用前面介绍的扫描器scanner
java语言一般都是maven管理的项目,无需安装scanner,可以通过命令行直接分析报告
mvn clean package sonar:sonar \
-Dsonar.login={sonar个人凭证} \
-Dsonar.projectKey=qx_whale \
-Dsonar.projectName=qx_whale \
-Dsonar.host.url=http://10.10.10.15:9000
在官方安装扫描器SonarScanner
/Users/admin/Downloads/sonar-scanner-4.7.0.2747-macosx/bin/sonar-scanner \
-Dsonar.host.url=http://10.10.10.15:9000 \
-Dsonar.login={sonar个人凭证} \
-Dsonar.language=php \
-Dsonar.projectKey=qx_whale2 \
-Dsonar.projectName=qx_whale2 \
-Dsonar.projectBaseDir=/code/myProject
Dsonar.projectBaseDir 指定代码分析路径
Dsonar.language 指定分析语言(默认根据扫描文件进行分析)
sonarqube-ce有非常多的插件可以使用,详情可以参考官方支持的插件
Sonarqube早在7.x版本是支持分支功能的,可以从分支进行代码分析,后来因为商业化演进,逐渐把分支功能给deprecated掉,合并到DE(开发者版本)收费。
分支功能可以让开发人员在测试分支尽早发现问题,设置收费这个很让人挺失望的。
好在国外大神把分支插件开发出来了,功能同7.x之前的基本一致,所以想要白嫖分支功能的话,大家可以参考以下示例去进行安装
cd {SONARQUBE_HOME}/extensions/plugins
wget https://github.com/mc1arke/sonarqube-community-branch-plugin/releases/download/1.8.1/sonarqube-community-branch-plugin-1.8.1.jar
### 记得修改权限,因为sonarqube需要通过sonar这个用户去启动
chown -R sonar:sonar sonarqube-community-branch-plugin-1.8.1.jar
sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.1.jar=web
sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.1.jar=ce
### 切记,要切换sonar用户
su sonar
cd {SONARQUBE_HOME}
./bin/linux-x86-64/sonar.sh restart
如图显示,表示插件安装成功,接下来就可以愉快地使用分支功能了,点个赞吧
路径:系统管理-系统配置-SonarQube servers
注意,一般不配置凭证。
路径:系统管理-全局工具配置-SonarQube Scanner
配置scanner组件
令牌:03e27c52459e3c2156760fb1d8f9d24d59c7bf9e
5. 在Jenkins上构建一个流水线任务
Jenkinsfile
pipeline {
agent any
tools {
maven 'maven' // jenkins配置的maven名称
}
stages {
stage('SCM') {
steps {
git url: 'https://github.com/foo/bar.git'
}
}
stage('build && SonarQube analysis') {
steps {
withSonarQubeEnv('My SonarQube Server') {
sh 'mvn clean package sonar:sonar -Dsonar.login=03e27c52459e3c2156760fb1d8f9d24d59c7bf9e'
}
}
}
stage("Quality Gate") {
steps {
timeout(time: 1, unit: 'HOURS') {
// Parameter indicates whether to set pipeline to UNSTABLE if Quality Gate fails
// true = set pipeline to UNSTABLE, false = don't
waitForQualityGate abortPipeline: true
}
}
}
}
}
相关术语解释:
-Dsonar.login:用户令牌(Sonar用户)
官方推荐使用流水线来进行代码质量分析
withSonarQubeEnv(‘My SonarQube Server’):表示引入’My SonarQube Server’这个环境
waitForQualityGate abortPipeline: true 表示等待sonarqube服务端返回质量阈报告,若质量阈不通过,则终止pipeline任务
插件介绍 https://www.jenkins.io/doc/pipeline/steps/sonar/
其他语言(通用)
通过流水线,对非maven项目进行代码质量分析,需要引入全局工具sonar scanner
Jenkinsfile
pipeline {
agent any
tools {
maven 'maven' // jenkins配置的maven名称
}
stages {
stage('SCM') {
steps {
git url: 'https://github.com/foo/bar.git'
}
}
stage('build && SonarQube analysis') {
steps {
withSonarQubeEnv('My SonarQube Server') {
// 引用jenkins的全局工具defaultSonarScanner
def scannerHome = tool 'defaultSonarScanner';
sh "${scannerHome}/bin/sonar-scanner -Dsonar.login=03e27c52459e3c2156760fb1d8f9d24d59c7bf9e"
}
}
}
stage("Quality Gate") {
steps {
timeout(time: 1, unit: 'HOURS') {
// Parameter indicates whether to set pipeline to UNSTABLE if Quality Gate fails
// true = set pipeline to UNSTABLE, false = don't
waitForQualityGate abortPipeline: true
}
}
}
}
}
org.sonarqube.ws.client.HttpException: Error 404 on http://10.14.8.157:9000/api/ce/task?id=AYBlkgJ_0a2bDva9JOF9 : {"errors":[{"msg":"No activity found for task \u0027AYBlkgJ_0a2bDva9JOF9\u0027"}]}
at org.sonarqube.ws.client.BaseResponse.failIfNotSuccessful(BaseResponse.java:36)
at hudson.plugins.sonar.client.HttpClient.getHttp(HttpClient.java:38)
at hudson.plugins.sonar.client.WsClient.getCETask(WsClient.java:51)
出现这个问题,不要害怕,应该是在sonar上删除项目并重建导致的,jenkins会在本地缓存报告的taskid,查看jenkins日志,你会发现出现了多个report-task.txt
解决方案:登录jenkins服务器,将.scannerwork/report-task.txt删除即可,一般target/sonar/report-task.txt存储的是最新的taskid。
org.sonarqube.ws.client.HttpException: Error 401 on http://10.14.8.157:9000/api/ce/task?id=AYCYfR4av8Ot_eXr5Wqi :
at org.sonarqube.ws.client.BaseResponse.failIfNotSuccessful(BaseResponse.java:36)
at hudson.plugins.sonar.client.HttpClient.getHttp(HttpClient.java:38)
at hudson.plugins.sonar.client.WsClient.getCETask(WsClient.java:51)
认证问题,一般调用waitForQualityGate()会遇到这样的问题。这个是插件的缺陷来的。
理论上,我们在withSonarQubeEnv()设置sonar.login表示通过这个用户去执行分析,并且希望在waitForQualityGate()执行时拿到sonar.login去获取回调结果,但结果是直接返回了401没有认证。
解决方案:通过sonarqube管理员生成令牌,然后去jenkins上生成secret key凭证,最后绑定到jenkins-系统管理-sonarqube servers-凭证。这样waitForQualityGate()在进行回调时就会使用sonar-admin的令牌去认证,401的问题就解决了。
有一点需要特别说明下,这是个比较粗糙的做法,但无意外它确实能帮助我们解决问题。
在项目组,我们要求每个sonar scanner运行时都必须指定sonar.login参数
恰逢公司进行标准化建设,许多公共组件开始崛起,围绕着团队的工作效率展开。有幸地,我参与了本次代码质量分析调研,对我而言既是挑战,也是成长。从3月份底开始接触,到5月份初产出调研报告,中间各种工作堆积断断续续,估摸着总耗时72小时吧,大多数调研工作都是在夜里完成的,凌晨1~2点更不在话下,有辛酸。但往好处想,倘若通过这双手,将优秀工具的使用方法普及给团队,从而让团队前进一小步,这何尝不是一种奖励呢。