简介
sonarqube 自动代码审查工具,检查代码错误、漏洞等。
可以与现有的工作流程集成,实现跨项目分支和拉取请求的持续代码检查。
上述描述中几个组件的关系图:
硬件准备
软件配置
安装 sonarqube
https://www.sonarqube.org/downloads/
基于docker方式
不过这种方式下数据库默认是个非生产数据库
## 创建数据目录
mkdir -p /data/cicd/sonarqube/{sonarqube_conf,sonarqube_extensions,sonarqube_logs,sonarqube_data}
chmod 777 -R /data/cicd/sonarqube/
## 运行
docker run -itd --name sonarqube \
-p 9000:9000 \
-v /data/cicd/sonarqube/sonarqube_conf:/opt/sonarqube/conf \
-v /data/cicd/sonarqube/sonarqube_extensions:/opt/sonarqube/extensions \
-v /data/cicd/sonarqube/sonarqube_logs:/opt/sonarqube/logs \
-v /data/cicd/sonarqube/sonarqube_data:/opt/sonarqube/data \
sonarqube:7.9.6-community
## 验证
docker logs -f sonarqube
## 将上一个步骤容器里生成的lib目录复制到宿主机
mkdir -p /data/cicd/sonarqube/sonarqube_lib
cd /data/cicd/sonarqube/sonarqube_lib
docker cp sonarqube:/opt/sonarqube/lib/* ./
docker run -itd --name sonarqube \
-p 9000:9000 \
-v /data/cicd/sonarqube/sonarqube_conf:/opt/sonarqube/conf \
-v /data/cicd/sonarqube/sonarqube_extensions:/opt/sonarqube/extensions \
-v /data/cicd/sonarqube/sonarqube_logs:/opt/sonarqube/logs \
-v /data/cicd/sonarqube/sonarqube_data:/opt/sonarqube/data \
-v /data/cicd/sonarqube/sonarqube_lib:/opt/sonarqube/lib \
sonarqube:7.9.6-community
访问地址: http://ip:9000
账户密码:admin/admin
基于二进制安装方式
安装 sonarqube 中文插件
如果自动安装不上,可能需要手动安装
https://www.yuque.com/zeyangli/wmaaq7/pcgq4k
选择对应的版本:
下载对应的版本:
https://github.com/xuhuisheng/sonar-l10n-zh/releases/tag/sonar-l10n-zh-plugin-1.29
cd /data/cicd/sonarqube/sonarqube_extensions/downloads
wget https://github.com/xuhuisheng/sonar-l10n-zh/releases/download/sonar-l10n-zh-plugin-1.29/sonar-l10n-zh-plugin-1.29.jar
chmod +x sonar-l10n-zh-plugin-1.29.jar
docker restart sonarqube
配置 sonarqube
开启强制认证
安装 sonar-scanner 到 jenkins slave
https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner
命令行方式安装
$ wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.0.2311-linux.zip
$ tar zxf sonar-scanner-xxxx.tar.gz -C /usr/local
$ vim /etc/profile
export SCANNER_HOME=/usr/local/sonar-scanner-4.6.0.2311-linux
export PATH=$PATH:$SCANNER_HOME/bin
$ source /etc/profile
$ sonar-scanner -v
INFO: Scanner configuration file: /usr/local/sonar-scanner-4.6.0.2311-linux/conf/sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: SonarScanner 4.6.0.2311
INFO: Java 11.0.3 AdoptOpenJDK (64-bit)
INFO: Linux 4.18.0-80.el8.x86_64 amd64
docker 方式安装
docker run \
--rm \
-e SONAR_HOST_URL="http://${SONARQUBE_URL}" \
-e SONAR_LOGIN="myAuthenticationToken" \
-v "${YOUR_REPO}:/usr/src" \
sonarsource/sonar-scanner-cli
sonar-scanner 的使用
两种方式:
- 项目根路径下加载配置文件
- 直接命令行指定项目
加载配置文件方式:sonar-project.properties
# 定义唯一的关键字
sonar.projectKey=devops-hello-service
# 定义项目名称
sonar.projectName=My project
# 定义项目的版本信息
sonar.projectVersion=1.0
# 指定扫描代码的目录位置(多个逗号分隔)
sonar.sources=.
# 执行项目编码
sonar.sourceEncoding=UTF-8
# sonarqube 的地址、账户、密码
sonar.host.url=
sonar.login
sonar.password
命令行方式:
# 指定配置文件
sonar-scanner -Dproject.settings=myproject.properties
# 命令行传参
sonar-scanner -Dsonar.projectKey=myproject -Dsonar.sources=src1
扫java项目
👙sonarqube 先安装java语言规则插件:Java code quality and security
sonar-scanner 扫描java项目会使用一些文件:
- 会用到target目录下的classes
sonar.links.ci = 项目对应的 jenkins 地址
sonar.links.homepage = 项目对应的 git 地址,对应扫描后的项目报告里的项目主页
sonar-scanner -Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.projectKey=devops-maven-service \
-Dsonar.projectName=devops-maven-service \
-Dsonar.projectVersion=1.0 \
-Dsonar.login=admin \
-Dsonar.password=admin \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=http://192.168.1.200/devops/devops-maven-service \
-Dsonar.links.ci=http://192.168.1.200:8080/job/demo-pipeline-service/ \
-Dsonar.sources=src \
-Dsonar.sourceEncoding=UTF-8 \
-Dsonar.java.binaries=target/classes \
-Dsonar.java.test.binaries=target/test-classes \
-Dsonar.java.surefire.report=target/surefire-reports
扫前端项目
插件:SonarJS
sonar-scanner -Dsonar.projectKey=devops-web-service \
-Dsonar.projectName=devops-web-service \
-Dsonar.projectVersion=1.0 \
-Dsonar.sources=src \
-Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.login=admin \
-Dsonar.password=admin \
-Dsonar.sourceEncoding=UTF-8
#sonar.sources=dist/static/js
扫golang项目
插件:SonarGo
sonar-scanner -Dsonar.projectKey=devops-golang-service \
-Dsonar.projectName=devops-golang-service \
-Dsonar.sources=src \
-Dsonar.login=admin \
-Dsonar.password=admin \
-Dsonar.host.url=http://192.168.1.200:9000
## 有测试用例的情况
sonar.exclusions=**/*_test.go
sonar.tests=.
sonar.test.inclusions=**/*_test.go
登录方式集成
ldap 集成
👙截图里配置要写入到 sonarqube 的主配置文件里
gitlab 集成
安装 gitlab auth 插件并重启
gitlab 创建应用
👙redirect uri 的格式必须是截图里的格式,主地址是 sonarqube 地址。
sonarqube 配置 gitlab auth 插件,填写上面创建的 gitlab 应用信息
正式集成到jenkins
安装 jenkins 插件: SonarQube Scanner,这个插件有以下优点:
- 在 jenkinslib 里的 sonar-scanner 就无需指定 sonarqube 的服务器地址、登录信息了。
- 在 jenkins 工程里将会提供 sonarqube 的项目地址。
配置 SonarQube Scanner 插件:
- 创建 SonarQube 管理员令牌,并添加 Jenkins 凭据 secret text 类型.
- jenkins web 里配置 sonarqube 地址
👙下面两个文件和文章:jenkins-集成gitlab 里的代码并不太一致。
Jenkinslib:https://github.com/Spinestars/jenkins/blob/master/src/org/devops/sonarqube.groovy
Jenkinsfile:https://github.com/Spinestars/jenkins/blob/master/ci.jenkinsfile
sonarqube 规则定义
sonarqube 质量阈
超过质量阈,sonarqube 项目会报错。
超过质量阈退出流水线
Jenkinslib:https://github.com/Spinestars/jenkins/blob/master/src/org/devops/sonarqube.groovy
质量阈接口的返回json。上述代码用到了这个接口返回值。
涉及的代码如下:
//获取扫描结果, 如果超出质量阈,则执行 error 关键词,退出流水线。
result = GetProjectStatus(projectName)
println(result)
if (result.toString() == "ERROR"){
mytools.EmailUser(userEmail,"代码质量阈错误")
error " 代码质量阈错误!请及时修复!"
} else {
println(result)
}
...
def HttpReq(reqType,reqUrl,reqBody){
def sonarServer = "http://192.168.1.200:9000/api"
response = httpRequest authentication: '4675830a-4330-4dd6-9185-cf62161967f0',
httpMode: reqType,
contentType: "APPLICATION_JSON",
consoleLogResponseBody: true,
ignoreSslErrors: true,
requestBody: reqBody,
url: "${sonarServer}/${reqUrl}"
//quiet: true
return response
}
//获取Sonar质量阈状态
// 这个接口从 sonarqube 项目详情页里通过F12就可以看到,是一个get请求,并返回json字符串,包含质量阈的结果
def GetProjectStatus(projectName){
apiUrl = "project_branches/list?project=${projectName}"
response = HttpReq("GET",apiUrl,'')
response = readJSON text: """${response.content}"""
result = response["branches"][0]["status"]["qualityGateStatus"]
//println(response)
return result
}
自动绑定规则和质量阈到项目
Api地址:http://
Jenkinslib:https://github.com/Spinestars/jenkins/blob/master/src/org/devops/sonarqube.groovy
查找项目
接口返回数据,通过判断 total 是否为 0,来判断项目是否存在。
涉及代码:
//搜索项目, 返回项目是否存在的结果
result = SerarchProject(projectName)
println(result)
//判断项目是否存在
if (result == "false"){
println("${projectName}---项目不存在,准备创建项目---> ${projectName}!")
CreateProject(projectName)
} else {
println("${projectName}---项目已存在!")
}
...
//搜索Sonar项目
def SerarchProject(projectName){
apiUrl = "projects/search?projects=${projectName}"
response = HttpReq("GET",apiUrl,'')
response = readJSON text: """${response.content}"""
result = response["paging"]["total"]
if(result.toString() == "0"){
return "false"
} else {
return "true"
}
}
新建项目
//创建Sonar项目
def CreateProject(projectName){
apiUrl = "projects/create?name=${projectName}&project=${projectName}"
response = HttpReq("POST",apiUrl,'')
println(response)
}
更新语言规则集
👙需要先在 sonarqube 服务上定义好质量规则
// 绑定项目质量规则,从项目名里获取质量规则名.
// 项目名规则: 质量规则名-项目名
qpName=projectName.split("-")[0] //anyops
//qpName="myjava"
if (projectType == "npm"){
ConfigQualityProfiles(projectName,"js",qpName)
ConfigQualityProfiles(projectName,"ts",qpName)
} else if (projectType == "maven") {
ConfigQualityProfiles(projectName,"java",qpName)
}
...
//绑定项目质量规则
def ConfigQualityProfiles(projectName,lang,qpname){
apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${qpname}"
response = HttpReq("POST",apiUrl,'')
println(response)
}
获取质量阈ID
要绑定质量阈到项目,需要先获取质量阈ID
其API地址是:http://
json数据
代码如下:
//获取质量阈ID
def GetQualtyGateId(gateName){
apiUrl= "qualitygates/show?name=${gateName}"
response = HttpReq("GET",apiUrl,'')
response = readJSON text: """${response.content}"""
result = response["id"]
return result
}
绑定质量阈到项目
//配置质量阈
ConfigQualityGates(projectName,qpName)
...
//配置项目质量阈
def ConfigQualityGates(projectName,gateName){
gateId = GetQualtyGateId(gateName)
apiUrl = "qualitygates/select?gateId=${gateId}&projectKey=${projectName}"
response = HttpReq("POST",apiUrl,'')
println(response)println(response)
}
扫描结果输出到 gitlab 的 commit 上
仅支持 sonarqube 6.7 版本,通过在 sonar-scanner 添加额外的命令行参数启用。
教程链接:https://youdianzhishi.com/web/course/1013/1290
配置 sonarqube 多分支模式的支撑
默认社区版 sonarqube 不支持多分支项目。不过这个插件本身作者是不保证持续维护的。
两种方式使用这个多分支插件。
第一种,使用作者打包好的 docker 镜像:https://hub.docker.com/r/mc1arke/sonarqube-with-community-branch-plugin
第二种,在社区版里添加插件
插件地址:https://github.com/mc1arke/sonarqube-community-branch-plugin
插件安装方法:
- Copy the plugin JAR file to the
extensions/plugins/
directory of your SonarQube instance - Add
-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=web
to thesonar.web.javaAdditionalOpts
property in your Sonarqube installation’sconfig/sonar.properties
file, e.g.sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.0.jar=web
- Add
-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=ce
to thesonar.ce.javaAdditionalOpts
property in your Sonarqube installation’sconfig/sonar.properties
file, e.g.sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.0.jar=ce
- Start Sonarqube, and accept the warning about using third-party plugins
扫描的时候加上额外的参数:-Dsonar.branch.name = branch_name (e.g master)
最终效果: