本次集成重点演示两种方式: 1. 使用命令行方式 2. 使用Jenkins扩展插件的方式。
命令行方式
流水线中添加代码扫描阶段, 然后在script
标签中定义一段脚本。 (其实这段脚本就是我们手动在服务器上面执行的sonar-scanner的命令和参数组成的)【可以先运行该段代码确保扫描成功,然后进一步优化】
stage("SonarScan"){
steps{
script{
sh """
sonar-scanner \
-Dsonar.projectKey=demo-devops-service \
-Dsonar.projectName=demo-devops-service \
-Dsonar.sources=src \
-Dsonar.host.url=http://192.168.1.200:9000 \
-Dsonar.login=0809881d71f2b06b64786ae3f81a9acf22078e8b \
-Dsonar.projectVersion=1.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 \
-Dsonar.java.binaries=target/classes \
-Dsonar.java.test.binaries=target/test-classes \
-Dsonar.java.surefire.report=target/surefire-reports
"""
}
}
}
}
通过上面的代码可以发现一些问题:
- 扫描参数值都是写死的,无法使其他项目通用。
- 代码中存在敏感数据信息。
既然想通用,就要制定规范。 例如:
- 我们统一使用Jenkins的作业名称做为SonarQube项目名称。
- 将Sonar在进行扫描时用到的认证信息,也存储到Jenkins的系统凭据中(Secret Text类型),避免流水线中存在敏感信息。然后使用
withCredentials
将凭据的值内容赋值给变量SONAR_TOKEN
引用。
- 使用
BUILD_NUMBER
作为sonarqube项目版本(可以使用时间戳、版本号、commitid)。 -Dsonar.links.ci=${BUILD_URL}
SonarQube的扩展链接, 方便在系统中跳转。
-Dsonar.links.homepage=${env.srcUrl}
SonarQube的扩展链接, 方便在系统中跳转。
优化后:
// 凭据列表
credentials = ["sonar" : '06bf5ee4-f571-4fe4-9b52-d17190ce54e5']
//服务器列表
servers = ["sonar": 'http://192.168.1.200:9000']
pipeline {
...
stage("CodeScan"){
steps{
script {
withCredentials([string(credentialsId: "${credentials['sonar']}", variable: 'SONAR_TOKEN')]) {
sh """
sonar-scanner \
-Dsonar.projectKey=${JOB_NAME.split('/')[-1]} \
-Dsonar.projectName=${JOB_NAME.split('/')[-1]} \
-Dsonar.sources=src \
-Dsonar.host.url=${servers['sonar']} \
-Dsonar.login=${SONAR_TOKEN} \
-Dsonar.projectVersion=${BUILD_NUMBER} \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=${env.srcUrl} \
-Dsonar.links.ci=${BUILD_URL} \
-Dsonar.sourceEncoding=UTF-8 \
-Dsonar.java.binaries=target/classes \
-Dsonar.java.test.binaries=target/test-classes \
-Dsonar.java.surefire.report=target/surefire-reports
"""
}
}
}
}
}
上面我们完成了,一个Java类型项目的扫描参数设置。 但是是否想过在企业中存在多种语言类型的项目? 此时我们要让代码扫描变的更加灵活一些,支持多种类型的代码扫描。
- 根据不同的构建工具,使用不同的代码扫描参数;
- 例如: maven 对应java类型项目, npm对应前端类型项目
最终将上述代码,纳入共享库。创建sonar.groovy。
package org.devops
def scanner(buildType,token,projectDescription,srcUrl){
switch(buildType){
case "maven":
sh """
sonar-scanner \
-Dsonar.host.url=http://139.198.166.235:9000 \
-Dsonar.projectKey=${env.JOB_NAME} \
-Dsonar.projectName=${env.JOB_NAME} \
-Dsonar.projectVersion=${env.BUILD_NUMBER} \
-Dsonar.login=${token} \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=${env.srcUrl} \
-Dsonar.links.ci=${env.BUILD_URL} \
-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
"""
break
case "npm":
sh """
sonar-scanner \
-Dsonar.projectKey=${env.JOB_NAME} \
-Dsonar.projectName=${env.JOB_NAME} \
-Dsonar.sources=src \
-Dsonar.host.url=http://139.198.166.235:9000 \
-Dsonar.login=${token} \
-Dsonar.projectVersion=${env.BUILD_NUMBER} \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage=${env.srcUrl} \
-Dsonar.links.ci=${env.BUILD_URL} \
-Dsonar.sourceEncoding=UTF-8
"""
break
default:
println("sonar error !")
}
}
Jenkinsfile内容:
@Library("devopslib@main") _
def project = new org.devops.build()
def sonar = new org.devops.sonarquebscanner()
def buildTools = ["maven": "/usr/local/apache-maven-3.8.1"]
def credentials = ["devops-maven-sonarqube": "f8b33d17-c1cf-428e-aa31-99d4038e59d0"]
String buildType = "${env.buildType}"
String projectDescription = "this is maven project"
currentBuild.description = "maven project"
pipeline {
agent {
label 'build'
}
stages {
stage('CheckOut') {
steps {
checkout([$class: 'GitSCM',
branches: [[name: "${branchName}"]],
extensions: [], userRemoteConfigs:
[[credentialsId: "${credentialsId}",
url: "${srcUrl}"]]])
}
}
stage('Build'){
steps{
script{
project.build(buildType,buildTools)
}
}
}
stage("UnitTest"){
steps{
script{
sh "${buildTools["maven"]}/bin/mvn test"
}
}
post{
success{
script{
junit 'target/surefire-reports/*.xml'
}
}
}
}
stage('CodeScan'){
steps{
script{
withCredentials([string(credentialsId: "${credentials['devops-maven-sonarqube']}", variable: 'token')]) {
sonar.scanner(buildType,token,projectDescription,srcUrl)
}
}
}
}
}
}