SonarCloud is a code quality tool that can identify bugs and vulnerabilities in your code. This post will explore how to integrate SonarCloud, GitHub, Jenkins and Maven to report any new code quality issues on pull requests.

SonarCloud is the cloud based variant of SonarQube, freeing you from running and maintaining a server instance. Older (<7) SonarQube versions had a preview analysis mode to report any new issues in a branch on the associated pull request. In newer versions of SonarQube this functionality has moved to the paid version, or the SonarCloud offering.

So, to start out, these are the components we aim to hook together:

  1. SonarCloud

  2. GitHub

  3. Jenkins

  4. Maven

SonarCloud

It’s easy enough to get started with SonarCloud; You can sign-up with your GitHub account. Once logged in you can grant access to individual repositories or entire organizations. For pull request decoration to work the SonarCloud application should be installed on your GitHub organization(s) and configured to have acccess to the repositories.

GitHub

To integrate SonarCloud with GitHub have a look at the the sonarcloud documentation. Now at present there’s an AutoScan Beta Feature, which supports quite a few languages already. Java however, is unsupported at the moment, leaving the integration up to us. Had we been using Travis CI, then they have excellent documentation on using SonarCloud with Travis CI.

Jenkins

Documentation and support for Jenkins is relegated to the "another CI service" instructions, so there’s a bit more work to do and figure out. There’s pointers to the Branches overview page and Pull request analysis page, both of which get us part of the way there.

SonarQube plugin & configuration

Firstly, we want to configure our Jenkins instance to point to SonarCloud. There’s a Jenkins plugin for SonarQube that allows you to do just that. From your SonarCloud Account Security tab generate a token, and fill in the blurred values below.

SonarQube Jenkins plugin

SonarQube Jenkins plugin

The plugin provides a withSonarQubeEnv('SonarCloud') { …​ } block which ensures the configured properties are available to any scanner running within.

Branch analysis

For branch analysis to work, we need to pass the sonar.branch.name parameter to our Sonar Scanner. When using Maven builds in Jenkins, that then comes down to the following pipeline step:

withSonarQubeEnv('SonarCloud') {
    sh "./mvnw org.jacoco:jacoco-maven-plugin:prepare-agent verify \
        sonar:sonar -Dsonar.branch.name=${env.BRANCH_NAME}"
}

Easy enough, since the branch name is already available as an environment variable.

Pull request analysis

PR analysis requires a few different properties, with sample values given in the SonarCloud documentation.

sonar.pullrequest.base=master
sonar.pullrequest.branch=feature/my-new-feature
sonar.pullrequest.key=5
sonar.pullrequest.provider=GitHub
sonar.pullrequest.github.repository=my-company/my-repo

Now some of these variables are trivially available, but in particular the key needs a bit of tweaking to be made available. In our case we’re scanning our GitHub organization, which needs to be configured to discover both "branches" and "pull requests from origin". This ensures builds for pull requests are enriched with three CHANGE_* environment variables which we can use to recreate the required arguments.

Jenkins Organization Scan

Jenkins Organization Scan

Maven

With the extra CHANGE_* pull request environment variables available in Jenkins, we then again need to pass them to the Maven sonar:sonar plugin. We achieve this through the following Jenkins scripted pipeline block.

stage 'SonarCloud'
// Split https://github.com/organization/repository/pull/123
def urlcomponents = env.CHANGE_URL.split("/")
def org = urlcomponents[3]
def repo = urlcomponents[4]
withSonarQubeEnv('SonarCloud') {
    sh "./mvnw sonar:sonar \
    -Dsonar.pullrequest.provider=GitHub \
    -Dsonar.pullrequest.github.repository=${org}/${repo} \
    -Dsonar.pullrequest.key=${env.CHANGE_ID} \
    -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH}"
}

As you can see the sonar.pullrequest.github.repository argument is composed from the CHANGE_URL environment variable, while CHANGE_ID maps to sonar.pullrequest.key. You might notice this stage is run separately after ./mvnw verify has already run. In our case we only run this step when the CHANGE_ID environment variable is available, through our Global Shared Jenkins Pipeline Library.

End result

Now, when all these components come together, any pull request will get decorated with the SonarCloud analysis results. If any build fails the quality gate, you’ll see the results reflected on the pull request state. This ensures any new pull requests can not contribute new code quality issues.

GitHub Pull Request decoration

GitHub Pull Request decoration

shadow-left