This integration focuses on two ways: 1 Use command line mode 2 How to use the Jenkins extension.
Command line mode
Add a code scanning phase to the pipeline, and then define a script in the script tag. (in fact, this script is composed of sonar scanner commands and parameters that we manually execute on the server) [you can run this code first to ensure that the scan is successful, and then further optimize]
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 """ } } } }
Some problems can be found through the above code:
- The scan parameter values are written dead and cannot be used for other items.
- There is sensitive data information in the code.
Since you want to be universal, you need to formulate specifications. For example:
- We uniformly use Jenkins's job name as the name of SonarQube project.
- The authentication information used by Sonar during scanning is also stored in Jenkins's system credentials (Secret Text type) to avoid sensitive information in the pipeline. Then, withCredentials is used to assign the value content of the credentials to the variable SONAR_TOKEN reference.
- Using BUILD_NUMBER is the version of the sonarqube project (timestamp, version number, and committed can be used).
- -Dsonar.links.ci=${BUILD_URL} SonarQube's extended link to facilitate jump in the system.
- -Dsonar. links. Extended link of home = ${env. Srcurl} sonarqube to facilitate jump in the system.
After optimization:
// Credential list credentials = ["sonar" : '06bf5ee4-f571-4fe4-9b52-d17190ce54e5'] //Server list 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 """ } } } } }
Above, we have completed the scanning parameter setting of a Java type project. But have you ever thought about the existence of multi language projects in the enterprise? At this point, we need to make code scanning more flexible and support multiple types of code scanning.
- Use different code scanning parameters according to different construction tools;
- For example, maven corresponds to java type projects and npm corresponds to front-end type projects
Finally, the above code is incorporated into the shared library. Create 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 content:
@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) } } } } } }