本次集成重点演示两种方式: 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.devopsdef 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"""breakcase "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"""breakdefault: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)}}}}}
}