问题:
开源版本sonarqube-server,同一个代码仓库,无法区分不同分支,从而实现按代码的不同分支显示对应分支的扫描结果。
如上图,所有分支的扫描结果,全部显示为master,而pipeline在checkout代码时,使用的为分支通配符形式。
解决:
后经过调查,发现github上面有开源插件,能实现上述功能,github地址如下:https://github.com/mc1arke/sonarqube-community-branch-plugin
下载插件放置到 ${SONAR_HOME}/extensions/plugins目录下,重启soanrqube-server。扫描时,在项目的sonar-project.properties文件里面,增加sonar.branch.name=${GIT_BRANCH}配置即可。
如上图,在checkout代码时,获取实际分支设置为环境变量。
如上图,在sonar-project.properties文件里面,增加sonar.branch.name的配置;最终sonarqube效果如下图
完整jenkinsfile如下:
pipeline{
triggers{
bitbucketPush()
pollSCM('')
}
agent any
options{
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '200'))
}
stages{
stage("Checkout"){
steps{
deleteDir()
script{
def getGitCredentialsID = { String gitRepositoryPath ->
if(gitRepositoryPath.startsWith("ssh://")){
return "svcacctdevops-git"
}
if(gitRepositoryPath.startsWith("http")){
return "svcacctdevops-git-http"
}
return "svcacctdevops-git"
}
def gitCredentialsID = getGitCredentialsID("http://xxxxx/testjava.git")
REPOSITORY_PATH = "http://xxxxx/testjava.git" //代码仓库地址
def targetRefSpec = ''
def getTargetBranches ={ String branchName ->
if (branchName.startsWith(":")) {
return branchName
}
if (branchName.contains("*")) {
return "origin/${branchName}"
}
return "refs/heads/${branchName}"
}
def targetBranches = []
def targetBranch = getTargetBranches("release**") //代码仓库分支名,为通配符形式
targetBranches.add([name:"${targetBranch}"])
def scmVars = checkout(
[$class: 'GitSCM', branches: targetBranches, doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'CloneOption', depth: 0, honorRefspec: true, noTags: true, reference: '', shallow: false]], submoduleCfg: [],
userRemoteConfigs: [[credentialsId: gitCredentialsID, name: 'origin', refspec: targetRefSpec, url: REPOSITORY_PATH]]])
GIT_COMMIT = scmVars.GIT_COMMIT
GIT_BRANCH = scmVars.GIT_BRANCH.replaceAll("origin/","").replaceAll("/","_")
env.CODE_COMMIT = GIT_COMMIT
env.GIT_COMMIT = GIT_COMMIT
env.CODE_BRANCH = GIT_BRANCH
// def GIT_BRANCH = "release/1.0.1"
env.GIT_BRANCH = GIT_BRANCH
env.GIT_REPOSITORY = "http://xxxxx/testjava.git"
env.GIT_CREDENTIALSID = gitCredentialsID
stash "cloneCode"
}
}
}
stage("BuildImage"){
options{
timeout(time:3600, unit:'SECONDS')
}
steps{
script{
def getVolumes = {
def volumes = [
hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock'),
hostPathVolume(hostPath: '/jenkins/data/.m2/repository', mountPath: '/root/.m2/repository/')
]
return volumes
}
def safePath = { String path ->
if(path.startsWith("/")){
path = "." + path
}
if(!path.endsWith("/")){
path = path + "/"
}
return path
}
// def ciImage = "<no value>/<no value>:<no value>"
def ciImage = "http:/xxxxxx/java:oraclejdk8" //CI镜像地址
def contextPath = safePath("./")
def pomPath = safePath("./")
def execCmds = {
def cmdstr = ""
def cmds = []
cmds << "mvn clean install -DskipTests=true"
cmdstr = cmds.join("
")
return {
try{
sh cmdstr
}
finally{
}
}
}
def pom = readMavenPom file: pomPath + "pom.xml"
env.POM_ARTIFACTId = pom.artifactId
env.POM_GROUPID = pom.groupId
env.POM_VERSION = pom.version
env.POM_MODELVERSION = pom.modelVersion
env.POM_NAME = pom.name
def registry = alauda.parseRegistry("${ciImage}")
def label = "ci-node-${UUID.randomUUID().toString()}"
podTemplate(
label: label,
containers:[
containerTemplate(name: 'ci-container', image: "${ciImage}", ttyEnabled: true,
envVars: [envVar(key: "LANG", value: "C.UTF-8")])
],
nodeUsageMode: "EXCLUSIVE",
volumes: getVolumes(),
nodeSelector: 'jenkins-ci=true',
imagePullSecrets: [ 'common-registry-user' ],
inheritFrom: 'base'
){
node(label) {
container('ci-container') {
def dest = "${env.WORKSPACE}/__dest__"
def source = "${env.WORKSPACE}/__source__"
def bin = "${env.WORKSPACE}/__bin__"
def upload = "${env.WORKSPACE}/__upload__"
sh "mkdir -p ${dest}"
dir("./__source__"){
unstash "cloneCode"
withEnv([
"ALAUDACI_DEST_DIR=${dest}","ALAUDACI_SOURCE_DIR=${source}", "ALAUDACI_BIN_DIR=${bin}", "ALAUDACI_UPLOAD_DIR=${upload}"
]){
dir("${contextPath}"){
execCmds()()
}
}
def count = sh(script: "ls -A ${dest} |wc -w", returnStdout:true).trim()
if(count == "0"){
echo "dest directory is empty, will copy source directory to dest"
sh "cp -r ./ ${dest}"
}
}
dir("./__dest__"){
stash "alaudaciDest"
}
}
}
}
}
}
}
stage("CodeScan"){
agent {label "sonarqube"}
options{
timeout(time:7200, unit:'SECONDS')
}
steps{
script{
def safePath = { String path ->
if(path.startsWith("/")){
path = "." + path
}
if(!path.endsWith("/")){
path = path + "/"
}
return path
}
def sonarProjectName = "${env.JOB_NAME}".replaceAll("/",":")
def sonarProjectKey = "devopstools:${sonarProjectName}"
def genSonarProperties ={ sonar_info ->
def propertiesPath = "sonar-project.properties"
def userPropsStr = ""
if (fileExists(propertiesPath)){
def userProps = readProperties file: propertiesPath
userPropsStr = userProps.collect{k,v->return k+"="+v}.join('
')
}
def sonarContextPath = safePath(".")
writeFile file: propertiesPath, text: """${userPropsStr}
sonar.projectKey=${sonarProjectKey}
sonar.projectName=${sonarProjectName}
sonar.host.url=${sonar_info.getEndpoint()}
sonar.login=${sonar_info.getToken()}
sonar.junit.reportPaths=${sonarContextPath}target/surefire-reports
sonar.jacoco.reportPaths=${sonarContextPath}target/jacoco.exec
sonar.language=Java
sonar.sources=${sonarContextPath}
sonar.branch.name=${GIT_BRANCH}
"""
return propertiesPath
}
unstash "alaudaciDest"
// Retrieve Sonar Info
def sonar_info = alauda.integration("6c32eb4c-c143-45ad-9f4d-16d27494c6be", "devopstools").retrieve()
// Generate sonar-project.properties file
def propertiesPath = genSonarProperties(sonar_info)
// Init Sonar Project
sh "echo start setting qualitygate to 4"
withCredentials([string(credentialsId: 'sonarToken', variable: 'SONARTOKEN')])
{
retry(3){
sh "cmdsonar qualitygate select --host ${sonar_info.getEndpoint()} --token ${SONARTOKEN}
--gate-id 4 --name ${sonarProjectName} --properties ${propertiesPath}"
}
//cmdsonar为封装sonarqube的api的一个二进制工具,能实现在扫描代码前设置使用非默认的quality gate
}
// Start scan
sh "sonar-scanner -Dsonar.java.binaries=./target/classes -Dproject.settings=${propertiesPath}"
addShortText(text:"SonarQube", link:"${sonar_info.getEndpoint()}/dashboard?id=${sonarProjectKey}")
}
}
}
}
post{
always{
script{
echo "clean up workspace"
deleteDir()
}
}
}
}