通过开源插件实现sonarqube区分不同分支显示代码扫描结果

  问题: 


         开源版本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()
			}

}

	}
}
原文地址:https://www.cnblogs.com/360linux/p/13062058.html