代码质量平台实践-SonarQube
目录
推荐文章
https://www.yuque.com/xyy-onlyone/aevhhf?# 《玩转Typora》
本节实战
实战名称 |
---|
? 实践:Scanner进行项目代码扫描(测试成功)-2023.6.24 |
? 实践:Jenkins集成SonarQube(命令行方式)(测试成功)-2023.6.24 |
? 实践:Jenkins集成SonarQube(jenkins插件方式)(测试成功)-2023.6.24 |
? 实践:新建SonarQube质量配置(测试成功)-2023.6.25 |
? 实践:新建SonarQube质量阈(测试成功)-2023.6.25 |
? 实践:SonarQube多分支代码扫描(测试成功)-2023.6.25 |
? 实践:SonarQube控制代码扫描步骤运行(测试成功)-2023.6.25 |
1、SonarQube 简介
SonarQube®是一种自动代码审查工具,可检测代码中的错误,漏洞和代码味道。它可以与您现有的工作流程集成,以实现跨项目分支和拉取请求的持续代码检查。
开发人员在IDE开发代码,可以安装SonarLint插件(本地代码扫描)进行提交前代码扫描。
当开发人员提交代码到版本控制系统中,自动触发jenkins进行代码扫描。
sonarQube本身具有消息通知webhook,当然也可以借助Jenkins的email插件来发送消息通知。
组件与服务组成:
-
SonarQube Server启动包含3个主要进程:
- Web服务器,供开发人员,管理人员浏览高质量的快照并配置SonarQube实例
- 基于Elasticsearch的Search Server从UI进行搜索服务。
- Compute Engine服务器,负责处理代码分析报告并将其保存在SonarQube数据库中。
-
SonarQube数据库要存储:SonarQube实例的配置(安全,插件设置等)项目,视图质量快照。
-
服务器上安装了多个SonarQube插件,可能包括语言,SCM,集成,身份验证和管理插件。
-
在持续集成服务器上运行一个或多个SonarScanner,以分析项目。
2、SonarQube平台安装配置
见单独md。
3、SonarScanner使用方法
代码扫描过程: 本地(构建节点)安装配置SonarScanner环境,然后通过设置sonar的一系列参数进行扫描分析。
- 配置文件方式读取扫描参数 (推荐)
- 命令行方式读取扫描参数
方法1:配置文件方式读取扫描参数
一个基本的sonar-project.properties
配置文件的参数:
# 定义唯一的关键字
sonar.projectKey=devops6-maven-service
# 定义项目名称
sonar.projectName=devops6-maven-service
# 定义项目的版本信息
sonar.projectVersion=1.0
# 指定扫描代码的目录位置(多个逗号分隔)
sonar.sources=.
# 执行项目编码
sonar.sourceEncoding=UTF-8
# 指定sonar Server
sonar.host.url=http://172.29.9.101:9000
# 认证信息
sonar.login=admin
sonar.password=Admin@123
这些配置项都是统一的,目前sonar支持将扫描参数以文件的方式存放或者以命令行传参的方式读取。
文件方式:可以将扫描参数放到项目的根目录或者sonar-scanner的配置文件目录等自定义的目录中;
命令行传参则可以直接将变量传递给sonarsacnner cli -Dsonar.projectKey=xxx 。
方法2:命令行方式读取扫描参数 (命令行方式会覆盖掉配置文件方式的)
# 指定配置文件
sonar-scanner -Dproject.settings=myproject.properties
# 命令行传参
sonar-scanner -Dsonar.projectKey=myproject -Dsonar.sources=src1
1.Java项目扫描
sonarqube服务器端需要安装Java语言规则插件
sonar-scanner -Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.projectKey=devops-maven-service \
-Dsonar.projectName=devops-maven-service \
-Dsonar.projectVersion=1.1 \
-Dsonar.login=admin \
-Dsonar.password=admin123 \
-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
`sonar.projectKey` 指定项目的关键字
`sonar.host.url`指定服务器地址(可以直接在配置文件中写死),
`projectName`指定项目的名称,
`projectVersion`指定项目的版本(可以用构建时间和构建ID定义),
`login`指定登录用户名,
`password`指定登录用户密码,
`projectDescription`指定项目的描述信息,
`links.homepage`指定项目的主页(超链接),
`sources`指定扫描的目录,
`sourceEncoding`指定扫描时的编码,
`java.binaries`指定编译后的类文件目录(必填),
`java.test.binaries`指定编译后的测试类目录,
`java.surefire.report`指定测试报告目录。
? 实践:Scanner进行项目代码扫描(测试成功)-2023.6.24 |
- 实验环境
sonarqube:9.9.0-community (docker方式部署)
SonarScanner 4.8.0.2856 (部署在宿主机上)
-
实验软件(无)
-
手动扫描代码
在devops6-maven-service
项目里创建sonar-project.properties
文件:
# 定义唯一的关键字
sonar.projectKey=devops6-maven-service
# 定义项目名称
sonar.projectName=devops6-maven-service
# 定义项目的版本信息
sonar.projectVersion=1.0
# 指定扫描代码的目录位置(多个逗号分隔)
sonar.sources=.
# 执行项目编码
sonar.sourceEncoding=UTF-8
# 指定sonar Server
sonar.host.url=http://172.29.9.101:9000
# 认证信息
sonar.login=admin
sonar.password=Admin@123
# java classes
sonar.java.binaries=target/classes
sonar.java.test.binaries=target/test-classes
sonar.java.surefire.report=target/surefire-reports
提交。
- 在本地
devops6-maven-service
本地项目里,拉取代码,然后扫描
#拉取代码
[root@Devops6 devops6-maven-service]#pwd
/data/devops6/devops6-maven-service
[root@Devops6 devops6-maven-service]#ls
mvnw mvnw.cmd pom.xml src target
[root@Devops6 devops6-maven-service]#git pull
[root@Devops6 devops6-maven-service]#ls
mvnw mvnw.cmd pom.xml sonar-project.properties src target
#删除之前的打包好的缓存数据
[root@Devops6 devops6-maven-service]#rm -rf target/
#打包
[root@Devops6 devops6-maven-service]#mvn clean package
#扫描
[root@Devops6 devops6-maven-service]#sonar-scanner
- 查看扫描报告
测试结束。?
2.Web前端项目扫描
sonar-scanner \
-Dsonar.projectKey=demo-devops-ui \
-Dsonar.projectName=demo-devops-ui \
-Dsonar.sources=src \
-Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.login=0809881d71f2b06b64786ae3f81a9acf22078e8b \
-Dsonar.projectVersion=2.0 \
-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.sourceEncoding=UTF-8
3.Golang项目扫描
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
4、CI流水线集成
1.JenkinsPipeline集成
本次集成重点演示两种方式: 1. 使用命令行方式 2. 使用Jenkins扩展插件的方式。
(1)使用命令行方式
? 实践:Jenkins集成SonarQube(命令行方式)(测试成功)-2023.6.24 |
- 实验环境
jenkins/jenkins:2.346.3-2-lts-jdk11
gitlab/gitlab-ce:15.0.3-ce.0
sonarqube:9.9.0-community
SonarScanner 4.8.0.2856
- 实验软件
链接:https://pan.baidu.com/s/1TWnlWTaHP_XP3O1aErXCdA?pwd=0820
提取码:08202023.6.24-Jenkins集成SonarQube-code
- 先在jenkins里配置下
devops6-maven-service
共享库设置
- 先手动构建下,测试下流水线
构建成功。
- 我们来看下gitlab
devops6-maven-service
的sonar-project.properties
文件里是不是存在一些问题,需要修改的呢?
这里的SnoarQube账号密码怎么能用明文来显示呢。显示是存在问题的。
Valut专门用来管理秘钥的,那是目前来说最安全的一种方式了。
- 在新建一个Jenkins凭据
同时利用Jenkinbs的片段生成器
来生成代码:
withCredentials([usernamePassword(credentialsId: '003d1667-653e-40f3-8103-b74614643aba', passwordVariable: 'SONAR_PASSWD', usernameVariable: 'SONAR_USER')]) {
// some block
}
-
然后服务器地址,我们也把它写放在流水线里。
-
修改完
sonar-project.properties
配置内容后,提交。
# 定义唯一的关键字
sonar.projectKey=devops6-maven-service
# 定义项目名称
sonar.projectName=devops6-maven-service
# 定义项目的版本信息
sonar.projectVersion=1.0
# 指定扫描代码的目录位置(多个逗号分隔)
sonar.sources=.
# 执行项目编码
sonar.sourceEncoding=UTF-8
# 指定sonar Server
# sonar.host.url=http://172.29.9.101:9000
# 认证信息
# sonar.login=admin
# sonar.password=Admin@123
# java classes
sonar.java.binaries=target/classes
sonar.java.test.binaries=target/test-classes
sonar.java.surefire.report=target/surefire-reports
- 这里编辑pipeline代码
我们期待的写法是这样的:
- 继续改写Jenkins pipeline代码
@Library("devops06@main") _
//import src/org/devops/Build.groovy
def build = new org.devops.Build()
pipeline {
agent {label "build"}
stages{
stage("CheckOut"){
steps{
script{
build.CheckOut()
}
}
}
stage("Build"){
steps{
script{
build.Build()
}
}
}
stage("CodeScan"){
steps{
script{
withCredentials([usernamePassword(credentialsId: '003d1667-653e-40f3-8103-b74614643aba',
passwordVariable: 'SONAR_PASSWD',
usernameVariable: 'SONAR_USER')]) {
sh """/data/devops6/sonar-scanner-4.8.0.2856-linux/bin/sonar-scanner \
-Dsonar.login=${SONAR_USER} \
-Dsonar.password=${SONAR_PASSWD} \
-Dsonar.host.url=http://172.29.9.101:9000
"""
}
}
}
}
}
}
提交。
- 运行
可以看到,代码检查步骤也是ok的。
测试结束。?
(2)使用Jenkins扩展插件的方式
? 实践:Jenkins集成SonarQube(Jenkins插件方式)(测试成功)-2023.6.24 |
- 实验环境
jenkins/jenkins:2.346.3-2-lts-jdk11
gitlab/gitlab-ce:15.0.3-ce.0
sonarqube:9.9.0-community
SonarScanner 4.8.0.2856
- 实验软件
链接:https://pan.baidu.com/s/1TWnlWTaHP_XP3O1aErXCdA?pwd=0820
提取码:08202023.6.24-Jenkins集成SonarQube-code
- 官方文档
参考:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-jenkins/
- 创建SonaQube的账户token
sqa_1339c18e86d442f9209bf363376554d5df5ca7a5
我的账号-生成令牌。
- 将token保存到Jenkins凭据中
生成代码:
withSonarQubeEnv(credentialsId: 'bdefe5e2-62a0-4e20-bf5a-51abedfe6df1') {
// some block
}
- 在Jenkins中安装插件sonarqube scanner。
- 转到"管理Jenkins>系统配置",向下滚动到SonarQube配置部分,单击Add SonarQube,添加服务器,选择凭据。
在片段生成器中查看用法, 注入与所选SonarQube 安装相关的环境变量。将设置以下变量:
SONAR_HOST_URL ## 在jenkins管理页面配置的sonar地址
SONAR_AUTH_TOKEN ## 在jenkins管理页面配置的sonar认证信息
- 此时,继续编写pipeline代码
使用withSonarQubeEnv DSL引入在Jenkins中配置的sonar环境。
@Library("devops06@main") _
//import src/org/devops/Build.groovy
def build = new org.devops.Build()
pipeline {
agent {label "build"}
stages{
stage("CheckOut"){
steps{
script{
build.CheckOut()
}
}
}
stage("Build"){
steps{
script{
build.Build()
}
}
}
stage("CodeScan"){
steps{
script{
// withCredentials([usernamePassword(credentialsId: '003d1667-653e-40f3-8103-b74614643aba',
// passwordVariable: 'SONAR_PASSWD',
// usernameVariable: 'SONAR_USER')]) {
// sh """/data/devops6/sonar-scanner-4.8.0.2856-linux/bin/sonar-scanner \
// -Dsonar.login=${SONAR_USER} \
// -Dsonar.password=${SONAR_PASSWD} \
// -Dsonar.host.url=http://172.29.9.101:9000
// """
// }
withSonarQubeEnv(credentialsId: 'bdefe5e2-62a0-4e20-bf5a-51abedfe6df1') {
sh """/data/devops6/sonar-scanner-4.8.0.2856-linux/bin/sonar-scanner \
-Dsonar.login=${SONAR_AUTH_TOKEN} \
-Dsonar.host.url=${SONAR_HOST_URL}
"""
}
}
}
}
}
}
- 跑流水线
用了插件的好处:这里可以直接跳过去,看报告。
最终的效果如下:
相比命令行只是增加了一些扩展链接, 对于经常操作Jenkins的用户方便些。
测试成功。?
2.GitLAB CI集成
? 实践:GitLab PipeLine中的代码扫描(测试成功)-2022.5.26 |
- 使用FROUP Variable存储sonar的账号和密码:
来到devops4组下:
- 来到devops4-gitlablib-service项目里:
编辑jobs/CI.yaml
文件:
.pipelineInit:
tags:
- "${RUNNER_TAG}"
stage: .pre
variables:
GIT_CHECKOUT: "true" ##局部开启作业的代码下载
script:
- ls -l
.cibuild:
tags:
- "${RUNNER_TAG}"
stage: build
script:
- echo "${BUILD_SHELL}"
- ${BUILD_SHELL}
# artifacts:
# paths:
# - ${ARTIFACT_PATH}
.citest:
tags:
- "${RUNNER_TAG}"
stage: test
script:
- echo "${TEST_SHELL}"
- ${TEST_SHELL}
# artifacts:
# reports:
# junit: ${TEST_REPORTS}
.codescan:
tags:
- "${RUNNER_TAG}"
stage: codescan
script:
|-
/usr/local/sonar-scanner/sonar-scanner-4.7.0.2747-linux/bin/sonar-scanner \
-Dsonar.login=${SONAR_USER} \
-Dsonar.password=${SONAR_PASSWD} \
-Dsonar.projectVersion=${CI_COMMIT_BRANCH}
编辑.gitlabci.yml
文件:
include:
- project: 'devops4/devops4-gitlablib-service'
ref: main
file:
- '/jobs/CI.yaml'
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "web"
when: always
- if: $CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000"
when: never
- when: always
variables:
GIT_CHECKOUT: "false" ## 全局关闭作业代码下载
BUILD_SHELL: "sh -x build.sh" ## 构建命令
TEST_SHELL: "/usr/local/apache-maven-3.8.5/bin/mvn test " ## 测试命令
# ARTIFACT_PATH: "target/*jar" ## 制品路径
# TEST_REPORTS: "target/surefire-reports/TEST-*.xml" ##测试报告
RUNNER_TAG: "builder"
stages:
- build
- test
- codescan
pipelineInit:
extends:
- .pipelineInit
cibuild:
extends:
- .cibuild
citest:
extends:
- .citest
codescan:
extends:
- .codescan
- 编写完成后,提交,然后就可以看到能够成功构建:
测试完成。?
3.插件方式
? 实践:Jenkins插件进行扫描(测试成功)-2022.5.26 |
- 官方参考
参考:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-jenkins/
- 创建SonaQube的账户token:
- 将token保存到Jenkins凭据中:
- 在Jenkins中安装插件sonarqube scanner:
- 转到"管理Jenkins>系统配置",向下滚动到SonarQube配置部分,单击Add SonarQube,添加服务器,选择凭据。
- 在片段生成器里生成代码:
使用withSonarQubeEnv DSL引入在Jenkins中配置的sonar环境:
withSonarQubeEnv(credentialsId: '09a996dd-2b05-46c8-90f9-09905bbc22c9') {
// some block
}
- 然后在之前的devops4-maven-service回放里编写下代码:
@Library("mylib@main") _ //加载共享库
import org.devops.* // 导入库
def checkout = new Checkout() //New实例化
def build = new Build()
def unittest = new UnitTest()
def sonar = new Sonar()
//env.buildType = "${JOB_NAME}".split("-")[1]
//流水线
pipeline {
agent { label "build" }
options {
skipDefaultCheckout true
}
stages{
stage("Checkout"){
steps{
script {
println("GetCode")
checkout.GetCode("${env.srcUrl}", "${env.branchName}")
}
}
}
stage("Build"){
steps{
script{
println("Build")
//build.CodeBuild("${env.buildType}")
sh "${env.buildShell}"
}
}
}
/*stage("UnitTest"){
steps{
script{
unittest.CodeTest("${env.buildType}")
}
}
}*/
stage("CodeScan"){
steps{
script{
withSonarQubeEnv(credentialsId: '09a996dd-2b05-46c8-90f9-09905bbc22c9') {
cliPath="/usr/local/sonar-scanner/sonar-scanner-4.7.0.2747-linux/bin"
sh """${cliPath}/sonar-scanner \
-Dsonar.projectVersion=master
"""
}
}
}
}
}
}
- 运行并观察效果:
相比命令行只是增加了一些扩展链接, 对于经常操作Jenkins的用户方便些。
测试完成。?
5、SonarQube REST API实践(可选)
? 实践:SonarQube REST API(测试成功)-2022.5.27 |
SonarQube系统的API文档: http://172.29.9.101:9000/web_api
//查找项目
api/projects/search?projects=${projectName}"
//创建项目
api/projects/create?name=${projectName}&project=${projectName}"
//更新语言规则集
api/qualityprofiles/add_project?language=${language}&qualityProfile=${qualityProfile}&project=${projectName}"
//项目授权
api/permissions/apply_template?projectKey=${projectKey}&templateName=${templateName}"
//更新质量阈
api/qualitygates/select?projectKey=${projectKey}&gateId=${gateId}"
SonarQube API的请求方法
curl --location \
--request GET \
'http://192.168.1.200:9000/api/projects/search?projects=day4-maven2-service' \
--header 'Authorization: Basic YWRtaW46YWRtaW4xMjM0'
jenkins代码中不要存在敏感信息, 将base64格式的SonarQube 用户token YWRtaW46YWRtaW4xMjM0
存储到Jenkins凭据中(Secret Text类型),后续使用withCredentials
将值赋值给变量SONAR_TOKEN
。
考虑到Api的URL都具有相同部分http://192.168.1.200:9000/api
所以单独复制给变量sonarApi
。每个接口返回的都是JSON类型的数据, 这里使用readJSON进行解析和处理。【所以有了下面的代码】
def SonarRequest(apiUrl,method){
withCredentials([string(credentialsId: "52df4ad9-7167-4bf6-a1fc-2f9f17713472", variable: 'SONAR_TOKEN')]) {
sonarApi = "http://192.168.1.200:9000/api"
response = sh returnStdout: true,
script: """
curl --location \
--request ${method} \
"${sonarApi}/${apiUrl}" \
--header "Authorization: Basic ${SONAR_TOKEN}"
"""
try {
response = readJSON text: """ ${response - "\n"} """
} catch(e){
response = readJSON text: """{"errors" : true}"""
}
return response
}
}
1.查找项目
接口地址和参数: http://172.29.9.101:9000/api/projects/search?projects=day4-maven-service
请求类型: GET
- postman调试:
转换cURL命令:
curl --location --request GET 'http://172.29.9.101:9000/api/projects/search?projects=devops4-maven-service' \
--header 'Authorization: Basic YWRtaW46YWRtaW4xMjM='
- Jenkins代码中不要存在敏感信息, 将base64格式的SonarQube 用户token
YWRtaW46YWRtaW4xMjM0
存储到Jenkins凭据中(Secret Text类型),后续使用withCredentials
将值赋值给变量SONAR_TOKEN
。
在jenkins里添加凭据:
利用片段式语法生成代码:
- 编写jenkins pipeline代码,然后找一个pipeline项目的回放里进行测试:
pipeline {
agent {
label "build"
}
stages {
stage("run"){
steps{
script{
result = ProjectSearch("devops4-maven-service")
println(result)
}
}
}
}
}
// 查找项目
def ProjectSearch(projectName){
apiUrl = "projects/search?projects=${projectName}"
response = SonarRequest(apiUrl,"GET")
if (response.paging.total == 0){
println("Project not found!.....")
return false
}
return true
}
def SonarRequest(apiUrl,method){
withCredentials([string(credentialsId: "66b7dd41-5434-43a3-8d02-505e2f2dc38f", variable: 'SONAR_TOKEN')]) {
sonarApi = "http://172.29.9.101:9000/api"
response = sh returnStdout: true,
script: """
curl --location \
--request ${method} \
"${sonarApi}/${apiUrl}" \
--header "Authorization: Basic ${SONAR_TOKEN}"
"""
try {
response = readJSON text: """ ${response - "\n"} """
} catch(e){
response = readJSON text: """{"errors" : true}"""
}
return response
}
}
运行测试:
- 此时,我先把刚才sonar里面的项目给删除掉,再来跑一次流水线,看下效果:
可以看到,会提示项目不存在。
2.创建项目
接口地址和参数: http://172.29.9.101:9000/api/projects/create?name=devops4-maven-service&project=devops4-maven-service
请求类型:POST
- postman调试:
cURL:
curl --location --request POST 'http://172.29.9.101:9000/api/projects/create?name=devops4-maven-service&project=devops4-maven-service' \
--header 'Authorization: Basic YWRtaW46YWRtaW4xMjM='
- 编写Jenkins Pipeline,并运行测试:
// 创建项目
def CreateProject(projectName){
apiUrl = "projects/create?name=${projectName}&project=${projectName}"
response = SonarRequest(apiUrl,"POST")
try{
if (response.project.key == projectName ) {
println("Project Create success!...")
return true
}
}catch(e){
println(response.errors)
return false
}
}
完整代码如下:
pipeline {
agent {
label "build"
}
stages {
stage("run"){
steps{
script{
projectName = "devops4-maven-service"
result = ProjectSearch("devops4-maven-service")
println(result)
if (result == false){
CreateProject(projectName)
}
}
}
}
}
}
// 查找项目
def ProjectSearch(projectName){
apiUrl = "projects/search?projects=${projectName}"
response = SonarRequest(apiUrl,"GET")
if (response.paging.total == 0){
println("Project not found!.....")
return false
}
return true
}
def SonarRequest(apiUrl,method){
withCredentials([string(credentialsId: "66b7dd41-5434-43a3-8d02-505e2f2dc38f", variable: 'SONAR_TOKEN')]) {
sonarApi = "http://172.29.9.101:9000/api"
response = sh returnStdout: true,
script: """
curl --location \
--request ${method} \
"${sonarApi}/${apiUrl}" \
--header "Authorization: Basic ${SONAR_TOKEN}"
"""
try {
response = readJSON text: """ ${response - "\n"} """
} catch(e){
response = readJSON text: """{"errors" : true}"""
}
return response
}
}
// 创建项目
def CreateProject(projectName){
apiUrl = "projects/create?name=${projectName}&project=${projectName}"
response = SonarRequest(apiUrl,"POST")
try{
if (response.project.key == projectName ) {
println("Project Create success!...")
return true
}
}catch(e){
println(response.errors)
return false
}
}
可以看到,sonar上项目被创建成功!
3.更新项目质量配置
接口地址和参数: http://172.29.9.101:9000/api/qualityprofiles/add_project?language=java&project=devops4-maven-service&qualityProfile=devop4
请求类型:POST
postman调试:
cUrl:
curl --location --request POST 'http://172.29.9.101:9000/api/qualityprofiles/add_project?language=java&project=devops4-maven-service&qualityProfile=devops4' \
--header 'Authorization: Basic YWRtaW46YWRtaW4xMjM='
Jenkins Pipeline:
// 更新项目质量配置
def UpdateQualityProfiles(lang, projectName, profileName){
apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${profileName}"
response = SonarRequest(apiUrl,"POST")
if (response.errors != true){
println("ERROR: UpdateQualityProfiles ${response.errors}...")
return false
} else {
println("SUCCESS: UpdateQualityProfiles ${lang} > ${projectName} > ${profileName}" )
return true
}
}
完整代码如下:
pipeline {
agent {
label "build"
}
stages {
stage("run"){
steps{
script{
projectName = "devops4-maven-service"
result = ProjectSearch("devops4-maven-service")
println(result)
if (result == false){
CreateProject(projectName)
}
UpdateQualityProfiles("java", projectName, "devops4")
}
}
}
}
}
// 查找项目
def ProjectSearch(projectName){
apiUrl = "projects/search?projects=${projectName}"
response = SonarRequest(apiUrl,"GET")
if (response.paging.total == 0){
println("Project not found!.....")
return false
}
return true
}
def SonarRequest(apiUrl,method){
withCredentials([string(credentialsId: "66b7dd41-5434-43a3-8d02-505e2f2dc38f", variable: 'SONAR_TOKEN')]) {
sonarApi = "http://172.29.9.101:9000/api"
response = sh returnStdout: true,
script: """
curl --location \
--request ${method} \
"${sonarApi}/${apiUrl}" \
--header "Authorization: Basic ${SONAR_TOKEN}"
"""
try {
response = readJSON text: """ ${response - "\n"} """
} catch(e){
response = readJSON text: """{"errors" : true}"""
}
return response
}
}
// 创建项目
def CreateProject(projectName){
apiUrl = "projects/create?name=${projectName}&project=${projectName}"
response = SonarRequest(apiUrl,"POST")
try{
if (response.project.key == projectName ) {
println("Project Create success!...")
return true
}
}catch(e){
println(response.errors)
return false
}
}
// 更新项目质量配置
def UpdateQualityProfiles(lang, projectName, profileName){
apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${profileName}"
response = SonarRequest(apiUrl,"POST")
if (response.errors != true){
println("ERROR: UpdateQualityProfiles ${response.errors}...")
return false
} else {
println("SUCCESS: UpdateQualityProfiles ${lang} > ${projectName} > ${profileName}" )
return true
}
}
运行后效果:
4.控制逻辑(实践)
-
项目没有配置质量, 默认使用sonarway(内置质量)。
-
默认直接使用sonarscanner,扫描的项目,使用的内置的默认质量。
如果具有单独的质量配置,例如每个组织一个质量配置。 此时就需要先手动在web页面创建一个空的项目,然后在项目的配置中设置目标质量配置。(下面是手动的操作步骤)
自动化实现方式 :
-
查询项目是否存在
-
- 存在: 直接更新质量配置
- 不存在: 创建空的项目然后更新质量配置
stage("sonartest"){
steps{
script{
// 判断项目是否存在
sonarProjectName = "${JOB_NAME.split('/')[-1]}"
result = ProjectSearch(sonarProjectName)
println(result)
if (result != true){
println("Create Sonar Project!...")
CreateProject(sonarProjectName)
}
// 指定项目的配置
UpdateQualityProfiles("java", sonarProjectName, "${sonarProjectName.split('-')[0]}")
}
}
}
完整的jenkinsfile代码:
pipeline {
agent {
label "build"
}
stages{
stage("sonartest"){
steps{
script{
// 判断项目是否存在
sonarProjectName = "${JOB_NAME.split('/')[-1]}"
result = ProjectSearch(sonarProjectName)
println(result)
if (result != true){
println("Create Sonar Project!...")
CreateProject(sonarProjectName)
}
// 指定项目的配置
UpdateQualityProfiles("java", sonarProjectName, "${sonarProjectName.split('-')[0]}")
}
}
}
}
}
def SonarRequest(apiUrl,method){
withCredentials([string(credentialsId: "52df4ad9-7167-4bf6-a1fc-2f9f17713472", variable: 'SONAR_TOKEN')]) {
sonarApi = "http://192.168.1.200:9000/api"
response = sh returnStdout: true,
script: """
curl --location \
--request ${method} \
"${sonarApi}/${apiUrl}" \
--header "Authorization: Basic ${SONAR_TOKEN}"
"""
try {
response = readJSON text: """ ${response - "\n"} """
} catch(e){
response = readJSON text: """{"errors" : true}"""
}
return response
}
}
// 更新质量阈
def UpdateQualityProfiles(lang, projectName, profileName){
apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${profileName}"
response = SonarRequest(apiUrl,"POST")
if (response.errors != true){
println("ERROR: UpdateQualityProfiles ${response.errors}...")
return false
} else {
println("SUCCESS: UpdateQualityProfiles ${lang} > ${projectName} > ${profileName}" )
return true
}
}
// 创建项目
def CreateProject(projectName){
apiUrl = "projects/create?name=${projectName}&project=${projectName}"
response = SonarRequest(apiUrl,"POST")
try{
if (response.project.key == projectName ) {
println("Project Create success!...")
return true
}
}catch(e){
println(response.errors)
return false
}
}
// 查找项目
def ProjectSearch(projectName){
apiUrl = "projects/search?projects=${projectName}"
response = SonarRequest(apiUrl,"GET")
if (response.paging.total == 0){
println("Project not found!.....")
return false
}
return true
}
? 自己实际测试过程如下:
- 来到jenkins共享库
devops4-jenkinslib-service
,我们创在Sonar.grovy文件里进行编辑:
package org.devops
def CodeScan(branchName){
cliPath="/usr/local/sonar-scanner/sonar-scanner-4.7.0.2747-linux/bin"
withCredentials([usernamePassword(credentialsId: '79d8f75b-3733-49f4-950f-19f8480fda03',
passwordVariable: 'SONAR_PASSWD',
usernameVariable: 'SONAR_USER')]) {
// some block
sh """${cliPath}/sonar-scanner \
-Dsonar.login=${SONAR_USER} \
-Dsonar.password=${SONAR_PASSWD} \
-Dsonar.projectVersion=${branchName}
"""
}
}
def Init(projectName, lang, profileName){
result = ProjectSearch(projectName)
println(result)
if (result == false){
CreateProject(projectName)
}
UpdateQualityProfiles(lang, projectName, profileName)
}
// 查找项目
def ProjectSearch(projectName){
apiUrl = "projects/search?projects=${projectName}"
response = SonarRequest(apiUrl,"GET")
if (response.paging.total == 0){
println("Project not found!.....")
return false
}
return true
}
def SonarRequest(apiUrl,method){
withCredentials([string(credentialsId: "66b7dd41-5434-43a3-8d02-505e2f2dc38f", variable: 'SONAR_TOKEN')]) {
sonarApi = "http://172.29.9.101:9000/api"
response = sh returnStdout: true,
script: """
curl --location \
--request ${method} \
"${sonarApi}/${apiUrl}" \
--header "Authorization: Basic ${SONAR_TOKEN}"
"""
try {
response = readJSON text: """ ${response - "\n"} """
} catch(e){
response = readJSON text: """{"errors" : true}"""
}
return response
}
}
// 创建项目
def CreateProject(projectName){
apiUrl = "projects/create?name=${projectName}&project=${projectName}"
response = SonarRequest(apiUrl,"POST")
try{
if (response.project.key == projectName ) {
println("Project Create success!...")
return true
}
}catch(e){
println(response.errors)
return false
}
}
// 更新项目质量配置
def UpdateQualityProfiles(lang, projectName, profileName){
apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${profileName}"
response = SonarRequest(apiUrl,"POST")
if (response.errors != true){
println("ERROR: UpdateQualityProfiles ${response.errors}...")
return false
} else {
println("SUCCESS: UpdateQualityProfiles ${lang} > ${projectName} > ${profileName}" )
return true
}
}
jenkinsfile代码:
@Library("mylib@main") _ //加载共享库
import org.devops.* // 导入库
def checkout = new Checkout() //New实例化
def build = new Build()
def unittest = new UnitTest()
def sonar = new Sonar()
//env.buildType = "${JOB_NAME}".split("-")[1]
//流水线
pipeline {
agent { label "build" }
options {
skipDefaultCheckout true
}
stages{
stage("Checkout"){
steps{
script {
println("GetCode")
checkout.GetCode("${env.srcUrl}", "${env.branchName}")
}
}
}
stage("Build"){
steps{
script{
println("Build")
//build.CodeBuild("${env.buildType}")
sh "${env.buildShell}"
}
}
}
/*stage("UnitTest"){
steps{
script{
unittest.CodeTest("${env.buildType}")
}
}
}*/
stage("CodeScan"){
steps{
script{
profileName = "${JOB_NAME}".split("-")[0]
sonar.Init("${JOB_NAME}", "java", profileName)
sonar.CodeScan("${env.branchName}")
}
}
}
}
}
注意:也要保证devops4-maven-service
项目里sonar-project.properties文件的配置正确:
- 提交流水线,观察效果:
符合预期。?
6、其他日常使用实践
1.规则的禁用与启用
目的: 掌握默认规则中的一部分规则如何激活和禁用。
质量规则、质量阈–这一般是由TeamLeader、开发人员去指定的。
进入质量配置页面, 可以看到所有的语言规则配置。在这里可以看到规则的使用情况。
这里假设我要调整Go语言的规则配置, 点击规则数量数字。
创建新的规则集:
点击更多激活规则
, 进入规则设置页面。
激活或者下线规则。(活动/挂起)
使用规则: 先在页面配置项目,然后使用SonarScanner扫描。
? 实践:新建SonarQube质量配置(测试成功)-2023.6.25 |
自己测试过程:
- 测试环境
sonarqube:9.9.0-community
- 创建新的质量配置
- 给特定的配置规则指定项目
- 激活更多规则
完成。
2.质量阈的配置
目的: 适用于以质量门禁作为交付关卡。
? 实践:新建SonarQube质量阈(测试成功)-2023.6.25 |
自己测试过程:
- 测试环境
sonarqube:9.9.0-community
- 创建新的质量阈
- 给新创建的质量阈指定项目
- 也可以添加新的条件
3.代码覆盖率统计
找一个具有大量单元测试的项目, 然后集成jacoco插件,生成覆盖率报告,最后由sonar收集。
-
Maven集成Jacoco(本次在gitlab的devops4-maven-service项目里的
pom.xml
里修改)
添加jacoco-maven-plugin
和junit
插件。
<dependencies>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
添加插件:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<skipMain>true</skipMain>
<skip>true</skip>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.5.201505241946</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>target/jacoco.exec</dataFile>
<outputDirectory>target/jacoco-reports</outputDirectory>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
- SonarQube安装Jacoco插件(8.9.1 版本可以跳过,已经集成)
https://github.com/SonarSource/sonar-jacoco/releases/download/1.1.0.898/sonar-jacoco-plugin-1.1.0.898.jar
# 指定代码覆盖率工具为jacoco
sonar.core.codeCoveragePlugin=jacoco
# 指定exec二进制文件存放路径
sonar.jacoco.reportPaths=target/jacoco.exec
cd devops-jacoco-service/
sonar-scanner -Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.projectKey=devops-jacoco-service \
-Dsonar.projectName=devops-jacoco-service \
-Dsonar.projectVersion=1.0 \
-Dsonar.login=admin \
-Dsonar.password=admin \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=http://www.baidu.com \
-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 \
-Dsonar.core.codeCoveragePlugin=jacoco \
-Dsonar.jacoco.reportPaths=target/jacoco.exec
- 以上编辑完成后,提交,然后再jenkins上构建验证:
测试效果:(失败)—老师当时这里也是没做实际测试的!
测试时间:2023年6月25日
测试环境:
apache-maven-3.9.2
jenkins/jenkins:2.346.3-2-lts-jdk11
gitlab/gitlab-ce:15.0.3-ce.0
sonarqube:9.9.0-community
SonarScanner 4.8.0.2856
当前maven版本无jacoco
插件:
构建失败:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GdQoEgQV-1687735995069)(https://bucket-hg.oss-cn-shanghai.aliyuncs.com/img/image-20230625070530207.png)]
4.多分支代码扫描
https://github.com/mc1arke/sonarqube-community-branch-plugin/releases
1. Sonar 7.9.6版本
将插件放到extensions/plugins
和 lib/common
目录中,然后重启sonar。
## 临时方案
docker exec -it sonarqube bash
cd /opt/sonarqube/lib/common
cp ../../extensions/plugins/sonarqube-community-branch-plugin-1.3.2 ./
exit
docker restart sonarqube
## 持久化lib目录后
[root@zeyang-nuc-service sonarqube]# ls
sonarqube_conf sonarqube_data sonarqube_extensions sonarqube_lib sonarqube_logs
[root@zeyang-nuc-service sonarqube]# cp /root/sonarqube-community-branch-plugin-1.3.2.jar sonarqube_extensions/plugins/
[root@zeyang-nuc-service sonarqube]# chmod +x sonarqube_extensions/plugins/sonarqube-community-branch-plugin-1.3.2.jar
[root@zeyang-nuc-service sonarqube]#
[root@zeyang-nuc-service sonarqube]#
[root@zeyang-nuc-service sonarqube]# cp /root/sonarqube-community-branch-plugin-1.3.2.jar sonarqube_lib/common/
[root@zeyang-nuc-service sonarqube]# chmod +x sonarqube_lib/common/sonarqube-community-branch-plugin-1.3.2.jar
[root@zeyang-nuc-service sonarqube]#
docker restart sonarqube
##扫描参数增加 –Dsonar.branch.name=
sonar-scanner -Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.projectKey=devops-maven2-service \
-Dsonar.projectName=devops-maven2-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 \
-Dsonar.branch.name=release-1.1.1
⚠️ 注意: 需要先把主分支扫描一遍,不然会报错。
ERROR: Error during SonarScanner execution
ERROR: No branches currently exist in this project. Please scan the main branch without passing any branch parameters.
ERROR:
ERROR: Re-run SonarScanner using the -X switch to enable full debug logging.
2. Sonar 8.9.1 版本
新版本插件的配置有变化,效果和使用方式不变。
- 将插件下载到extensions/plugins/目录。
- 更新sonar服务端的配置文件。
- 重启docker restart sonarqube 。
# cd /data/cicd2/sonarqube/
# ls
sonarqube_conf sonarqube_data sonarqube_extensions sonarqube_logs
# cat sonarqube_conf/sonar.properties
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
# ls sonarqube_extensions/plugins/
sonar-gitlab-plugin-4.1.0-SNAPSHOT.jar sonar-l10n-zh-plugin-8.9.jar sonarqube-community-branch-plugin-1.8.0.jar
- 源文档描述:
1. Copy the plugin JAR file to the extensions/plugins/ directory of your SonarQube instance
2. Add -javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=web to the sonar.web.javaAdditionalOptions property in your Sonarqube installation's config/sonar.properties file, e.g. sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.0.jar=web
3. Add -javaagent:./extensions/plugins/sonarqube-community-branch-plugin-${version}.jar=ce to the sonar.ce.javaAdditionalOptions property in your Sonarqube installation's config/sonar.properties file, e.g. sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.0.jar=ce
4. Start Sonarqube, and accept the warning about using third-party plugins
? 实践:SonarQube多分支代码扫描(测试成功)-2023.6.25 |
- 实验环境
jenkins/jenkins:2.346.3-2-lts-jdk11
gitlab/gitlab-ce:15.0.3-ce.0
sonarqube:9.9.0-community
SonarScanner 4.8.0.2856
- 实验软件(无)
- 我们可以看到这里默认是没有其他分支的:
- 官网下载插件:
https://github.com/mc1arke/sonarqube-community-branch-plugin
本次找到1.14.0插件:
https://github.com/mc1arke/sonarqube-community-branch-plugin/releases/download/1.14.0/sonarqube-community-branch-plugin-1.14.0.jar
- 配置:
#(1)下载插件
[root@Devops6 ~]#cd /data/devops6/sonarqube/
[root@Devops6 sonarqube]#ls
sonarqube_conf sonarqube_data sonarqube_extensions sonarqube_logs
[root@Devops6 sonarqube]#cd sonarqube_extensions/plugins/
[root@Devops6 plugins]#ls
sonar-l10n-zh-plugin-9.9.jar
[root@Devops6 plugins]#wget https://gh.ddlc.top/https://github.com/mc1arke/sonarqube-community-branch-plugin/releases/download/1.14.0/sonarqube-community-branch-plugin-1.14.0.jar
[root@Devops6 plugins]#ll -h
total 13M
-rw-r--r-- 1 1000 1000 69K Jun 24 08:17 sonar-l10n-zh-plugin-9.9.jar
-rw-r--r-- 1 root root 13M Dec 31 23:46 sonarqube-community-branch-plugin-1.14.0.jar
[root@Devops6 plugins]#
#(2)更新sonar服务端的配置文件
[root@Devops6 sonarqube]#pwd
/data/devops6/sonarqube
[root@Devops6 sonarqube]#ls
sonarqube_conf sonarqube_data sonarqube_extensions sonarqube_logs
[root@Devops6 sonarqube]#cd sonarqube_conf/
[root@Devops6 sonarqube_conf]#ls
[root@Devops6 sonarqube_conf]#vim sonar.properties #这里新建次文件
sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.14.0.jar=web
sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.14.0.jar=ce
#(3)重启sonarqube
[root@Devops6 ~]#docker restart sonarqube9
重启sonarqube完成后,就可以看到这里的项目出现了分支字样:
- 在devops-maven-service项目以master分支创建一个dev分支:
- 修改jenkins共享库里
Sonar.groovy
的代码:
@Library("devops06@main") _
//import src/org/devops/Build.groovy
def build = new org.devops.Build()
pipeline {
agent {label "build"}
stages{
stage("CheckOut"){
steps{
script{
build.CheckOut()
}
}
}
stage("Build"){
steps{
script{
build.Build()
}
}
}
stage("CodeScan"){
steps{
script{
// withCredentials([usernamePassword(credentialsId: '003d1667-653e-40f3-8103-b74614643aba',
// passwordVariable: 'SONAR_PASSWD',
// usernameVariable: 'SONAR_USER')]) {
// sh """/data/devops6/sonar-scanner-4.8.0.2856-linux/bin/sonar-scanner \
// -Dsonar.login=${SONAR_USER} \
// -Dsonar.password=${SONAR_PASSWD} \
// -Dsonar.host.url=http://172.29.9.101:9000
// """
// }
withSonarQubeEnv(credentialsId: 'bdefe5e2-62a0-4e20-bf5a-51abedfe6df1') {
sh """/data/devops6/sonar-scanner-4.8.0.2856-linux/bin/sonar-scanner \
-Dsonar.login=${SONAR_AUTH_TOKEN} \
-Dsonar.host.url=${SONAR_HOST_URL} \
-Dsonar.branch.name=${env.branchName}
"""
}
}
}
}
}
}
提交。
- 然后,然后在jenkins上跑一次流水线,本次是以dev分支跑:
符合预期,测试结束。?
5.扫描结果关联commitid
⚠️ 注意:
7.几,8.几的版本有这个插件,但9版本已经不支持次功能了。
提前装好插件:https://github.com/gabrie-allaigre/sonar-gitlab-plugin/tree/4.1.0-SNAPSHOT插件的说明文档查看该插件的Readme文档。 (仅质量阈失败后才可以展示扫描报告)
# cp sonar-gitlab-plugin-4.1.0-SNAPSHOT.jar /data/cicd/sonarqube/sonarqube_extensions/plugins/
# chmod +x /data/cicd/sonarqube/sonarqube_extensions/plugins/sonar-gitlab-plugin-4.1.0-SNAPSHOT.jar
# docker restart sonarqube
-Dsonar.gitlab.failure_notification_mode 值为commit-status表示更改提交状态, 值为nothing不做任何动作。
sonar-scanner -Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.projectKey=devops-jacoco-service \
-Dsonar.projectName=devops-jacoco-service \
-Dsonar.projectVersion=1.0 \
-Dsonar.login=0809881d71f2b06b64786ae3f81a9acf22078e8b \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=http://www.baidu.com \
-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 \
-Dsonar.core.codeCoveragePlugin=jacoco \
-Dsonar.jacoco.reportPaths=coverage/jacoco.exec \
-Dsonar.gitlab.commit_sha=f898a9fdbd319e68d519aa2ff42ad80da5186103 \
-Dsonar.gitlab.ref_name=main \
-Dsonar.gitlab.project_id=37 \
-Dsonar.dynamicAnalysis=reuseReports \
-Dsonar.gitlab.failure_notification_mode=commit-status \
-Dsonar.gitlab.url=http://192.168.1.200 \
-Dsonar.gitlab.user_token=CwmDA_4TKevDPRh4_SEf \
-Dsonar.gitlab.api_version=v4
1.静态配置
2.动态配置
? 实践:扫描结果关联commitid(动态配置)(测试成功)-2022.6.3 |
- 那么,接下来配置下动态的,看下效果:
-Dsonar.gitlab.commit_sha=f898a9fdbd319e68d519aa2ff42ad80da5186103 \
-Dsonar.gitlab.ref_name=main \
-Dsonar.gitlab.project_id=37 \
-Dsonar.dynamicAnalysis=reuseReports \
-Dsonar.gitlab.failure_notification_mode=commit-status \
-Dsonar.gitlab.url=http://192.168.1.200 \
-Dsonar.gitlab.user_token=CwmDA_4TKevDPRh4_SEf \
-Dsonar.gitlab.api_version=v4
- 获取commitID:
//获取CommitID
def GetCommitID(){
ID = sh returnStdout: true, script:"git rev-parse HEAD"
return ID -"\n"
}
[root@devops devops4-maven-service]#git rev-parse HEAD
b1087191a26bf36b7f77f31093a9e226a8846674
- 获取projectID:
因为我们是有规范的,jenkins的作业name和gitlab的项目是保持一致的:
curl --location --request GET 'http://172.29.9.101/api/v4/projects?search=devops4-maven-service' \
--header 'PRIVATE-TOKEN: MhEV52bNpbUnnSfNg1nc' \
--header 'Authorization: Basic YWRtaW46YWRtaW4xMjM='
如果获取一个不存在的项目的话,这里返回值为空。
- 这里直接在jenkins的pipeline的回放里临时测试一下效果:
完整代码:
pipeline {
agent {
label "build"
}
stages {
stage("Run") {
steps{
script{
commitID = GetCommitID()
groupName = "${JOB_NAME}".split('-')[0]
projectID = GetProjectID("${JOB_NAME}", groupName)
println("commitID: ${commitID}")
println("projectID: ${projectID}")
}
}
}
}
}
//获取CommitID
def GetCommitID(){
ID = sh returnStdout: true, script:"git rev-parse HEAD"
return ID -"\n"
}
//获取ProjectID
// fork
// namespace
// usera/devops-service-app
// userb/devops-service-app
def GetProjectID(projectName, groupName){
response = sh returnStdout: true,
script: """
curl --location --request GET \
http://172.29.9.101/api/v4/projects?search=${projectName} \
--header 'PRIVATE-TOKEN: MhEV52bNpbUnnSfNg1nc' \
--header 'Authorization: Basic YWRtaW46YWRtaW4xMjM='
"""
response = readJSON text: response
if (response != []){
for (p in response) {
if (p["namespace"]["name"] == groupName){
return response[0]["id"]
}
}
}
}
运行后效果如下:
符合预期,但是注意下,这个commitID好像不是最新一次的commitID……
- 方法都写好了,我们就把它加到共享库里去:
共享库例的代码如下:
Jenkinsfile
@Library("mylib@main") _ //加载共享库
import org.devops.* // 导入库
def checkout = new Checkout() //New实例化
def build = new Build()
def unittest = new UnitTest()
def sonar = new Sonar()
def gitcli = new GitLab()
//env.buildType = "${JOB_NAME}".split("-")[1]
//流水线
pipeline {
agent { label "build" }
options {
skipDefaultCheckout true
}
stages{
stage("Checkout"){
steps{
script {
println("GetCode")
checkout.GetCode("${env.srcUrl}", "${env.branchName}")
}
}
}
stage("Build"){
steps{
script{
println("Build")
//build.CodeBuild("${env.buildType}")
sh "${env.buildShell}"
}
}
}
/*stage("UnitTest"){
steps{
script{
unittest.CodeTest("${env.buildType}")
}
}
}*/
stage("CodeScan"){
steps{
script{
profileName = "${JOB_NAME}".split("-")[0]
sonar.Init("${JOB_NAME}", "java", profileName)
//commit-status
commitID = gitcli.GetCommitID()
groupName =profileName
projectID = gitcli.GetProjectID("${JOB_NAME}", groupName)
sonar.CodeScan("${env.branchName}", commitID, projectID)
}
}
}
}
}
GitLab.groovy
package org.devops
//获取CommitID
def GetCommitID(){
ID = sh returnStdout: true, script:"git rev-parse HEAD"
return ID -"\n"
}
//获取ProjectID
// fork
// namespace
// usera/devops-service-app
// userb/devops-service-app
def GetProjectID(projectName, groupName){
response = sh returnStdout: true,
script: """
curl --location --request GET \
http://172.29.9.101/api/v4/projects?search=${projectName} \
--header 'PRIVATE-TOKEN: MhEV52bNpbUnnSfNg1nc' \
--header 'Authorization: Basic YWRtaW46YWRtaW4xMjM='
"""
response = readJSON text: response
if (response != []){
for (p in response) {
if (p["namespace"]["name"] == groupName){
return response[0]["id"]
}
}
}
}
- 此时,在jebkins的devops4-maven-service项目运行流水线,观察效果:
可以看到,构建成功:
在gitlab的devops4-maven-service项目的commit查看效果:
符合预期,测试结束。?
6.控制代码扫描步骤运行
stage("SonarScan"){
when {
environment name: 'skipSonar', value: 'false'
}
}
? 实践:SonarQube控制代码扫描步骤运行(测试成功)-2023.6.25 |
自己测试过程:
- 实验环境
jenkins/jenkins:2.346.3-2-lts-jdk11
gitlab/gitlab-ce:15.0.3-ce.0
sonarqube:9.9.0-community
SonarScanner 4.8.0.2856
-
实验软件(无)
-
修改jenkins共享库里的代码:
修改Jenkinsfile共享库
里的下代码,添加when片段:
- 然后在jenkins的
devops6-maven-service
pipeline里添加选项参数:
- 最后,构建,并观察效果:
不扫描代码:
扫描代码:
可以看到,本次就跳过代码扫描了。
测试结束。?
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
? 微信二维码
x2675263825 (舍得), qq:2675263825。
? 微信公众号
《云原生架构师实战》
? 语雀
https://www.yuque.com/xyy-onlyone
? csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
? 知乎
https://www.zhihu.com/people/foryouone
最后
好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!文章来源:https://www.uudwc.com/A/XNZ8z/
// userb/devops-service-app
def GetProjectID(projectName, groupName){
response = sh returnStdout: true,
script: “”"
curl --location --request GET
http://172.29.9.101/api/v4/projects?search=${projectName}
–header ‘PRIVATE-TOKEN: MhEV52bNpbUnnSfNg1nc’
–header ‘Authorization: Basic YWRtaW46YWRtaW4xMjM=’
“”"
response = readJSON text: response
if (response != []){
for (p in response) {
if (p[“namespace”][“name”] == groupName){
return response[0][“id”]
}
}
}
}
- 此时,在jebkins的devops4-maven-service项目运行流水线,观察效果:
可以看到,构建成功:
[外链图片转存中...(img-gSibJ7o7-1687735995076)]
在gitlab的devops4-maven-service项目的commit查看效果:
[外链图片转存中...(img-I39K9EPM-1687735995076)]
符合预期,测试结束。?
### 6.控制代码扫描步骤运行
```groovy
stage("SonarScan"){
when {
environment name: 'skipSonar', value: 'false'
}
}
[外链图片转存中…(img-T6X07g3f-1687735995077)]
[外链图片转存中…(img-YyI8IQEE-1687735995077)]
? 实践:SonarQube控制代码扫描步骤运行(测试成功)-2023.6.25 |
自己测试过程:
- 实验环境
jenkins/jenkins:2.346.3-2-lts-jdk11
gitlab/gitlab-ce:15.0.3-ce.0
sonarqube:9.9.0-community
SonarScanner 4.8.0.2856
-
实验软件(无)
-
修改jenkins共享库里的代码:
修改Jenkinsfile共享库
里的下代码,添加when片段:
[外链图片转存中…(img-Tn6bNV3F-1687735995077)]
- 然后在jenkins的
devops6-maven-service
pipeline里添加选项参数:
[外链图片转存中…(img-BZ1CDgZv-1687735995077)]
- 最后,构建,并观察效果:
不扫描代码:
[外链图片转存中…(img-Avn69JMx-1687735995077)]
[外链图片转存中…(img-gZ6Xiv2P-1687735995078)]
[外链图片转存中…(img-TMfrBEfz-1687735995078)]
扫描代码:
[外链图片转存中…(img-cDURsZpy-1687735995078)]
[外链图片转存中…(img-nP0uW8RM-1687735995078)]
可以看到,本次就跳过代码扫描了。
测试结束。?
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
? 微信二维码
x2675263825 (舍得), qq:2675263825。
[外链图片转存中…(img-XRvwGXq9-1687735995078)]
? 微信公众号
《云原生架构师实战》
[外链图片转存中…(img-J3qSw6m1-1687735995078)]
? 语雀
https://www.yuque.com/xyy-onlyone
[外链图片转存中…(img-N5Iozulj-1687735995079)]
? csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
[外链图片转存中…(img-VGMmxbjO-1687735995079)]
? 知乎
https://www.zhihu.com/people/foryouone
[外链图片转存中…(img-lxI6plPY-1687735995079)]
最后
好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!
[外链图片转存中…(img-VnaqUhrR-1687735995079)]文章来源地址https://www.uudwc.com/A/XNZ8z/