How to add SonarQube scans and see their results from a Github PR
By: Francislâiny Campos
Tags: Automation, Continuous Integration, Continuous Delivery, Web Development, Software Development

For this tutorial we’ll use a Java/Maven project as our basis and Jenkins as our CI tool. We’ll be setting SonarQube PR analysis using Jenkinsfiles and Docker. Cool, let the fun begin!

Let’s start assuming that you already have your SonarQube account created and keep going from there, okay? Something important to mention here also is that at the time of this writing, it’s required to have a SonarQube developer account for one to be able to add Github PR decorations. For many other things, you may still be okay with the community version though, and can still see SonarQube results, so if you’re only interested in this part, this article should still be okay for you.

As the sample used here will be a Java Maven repository, we’ll need to add a few things to our .pom file.

<sonar.version>3.4.0.905</sonar.version>

<jacoco-maven-plugin.version>0.8.5</jacoco-maven-plugin.version> <plugin>

<groupId>org.sonarsource.scanner.maven</groupId>

<artifactId>sonar-maven-plugin</artifactId>

<version>${sonar.version}</version>

</plugin> <plugin>

<groupId>org.jacoco</groupId>

<artifactId>jacoco-maven-plugin</artifactId>

<version>${jacoco-maven-plugin.version}</version>

<configuration>

<destFile>${basedir}/target/jacoco.exec</destFile>

<dataFile>${basedir}/target/jacoco.exec</dataFile>

</configuration>

<executions>

<execution>

<id>jacoco-initialize</id>

<goals>

<goal>prepare-agent</goal>

</goals>

</execution>

<execution>

<id>jacoco-site</id>

<phase>verify</phase>

<goals>

<goal>report</goal>

</goals>

</execution>

<execution>

<!-- Rules for configuring build failure below a threshold limit based

on code coverage value using Jacoco -->

<id>check</id>

<goals>

<goal>check</goal>

</goals>

<configuration>

<excludes>

<exclude>**/*config*.*</exclude>

</excludes>

<rules>

<rule implementation="org.jacoco.maven.RuleConfiguration">

<element>BUNDLE</element>

<limits>

<limit implementation="org.jacoco.report.check.Limit">

<counter>INSTRUCTION</counter>

<value>COVEREDRATIO</value>

<minimum>0.50</minimum>

</limit>

</limits>

</rule>

</rules>

</configuration>

</execution>

</executions>

</plugin> <plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-surefire-plugin</artifactId>

<version>${maven-surefire-plugin.version}</version>

<configuration>

<testSourceDirectory>src/test/java/com/my/directory/tests</testSourceDirectory>

<trimStackTrace>false</trimStackTrace>

<excludes>

<exclude>**/SmokeTests.java</exclude>

</excludes>

</configuration>

</plugin> <profile>

<id>sonar</id>

<activation>

<activeByDefault>true</activeByDefault>

</activation>

<properties>

<!-- Edit this URL for sonarQube server --> <sonar.host.url>https://sonarqubedeveloper.internal</sonar.host.url>

<sonar.login>mySonarQubeToken</sonar.login>

<sonar.pullrequest.github.repository>HMH-Core/MyRepoNameWithout</sonar.pullrequest.github.repository>

<!-- Sonar-JaCoCo properties -->

<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>

<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>

<sonar.jacoco.reportPaths>${basedir}/target/jacoco.exec</sonar.jacoco.reportPaths>

<java.version>1.8</java.version>

<sonar.coverage.exclusions>

**/MyApplication.java, **/*Exception*.java, **/dao/**, **/dto/**, **/entity/**

</sonar.coverage.exclusions>

</properties>

</profile>

Okay, this is huge right? Let’s break it down a little. First thing we do is add the SonarQube plugin.

<plugin>

<groupId>org.sonarsource.scanner.maven</groupId>

<artifactId>sonar-maven-plugin</artifactId>

<version>${sonar.version}</version>

</plugin>

If you’re using IntelliJ as your IDE you should be able to run the SonarQube checks from the below Maven view, but you can also run them through the terminal using the mvn sonar:sonar command. But please don’t run this yet, as you may want to wait just a bit longer until we configure our SonarQube url, where the scan results will be found. We’ll do this shortly.

You may have noticed on the .pom snippet that we’re using the jacoco plugin. This is needed for our coverage checks and it should be okay to copy that part just as it is.

<plugin>

<groupId>org.jacoco</groupId>

<artifactId>jacoco-maven-plugin</artifactId>

<version>${jacoco-maven-plugin.version}</version>

<configuration>

<destFile>${basedir}/target/jacoco.exec</destFile>

<dataFile>${basedir}/target/jacoco.exec</dataFile>

</configuration>

<executions>

<execution>

<id>jacoco-initialize</id>

<goals>

<goal>prepare-agent</goal>

</goals>

</execution>

<execution>

<id>jacoco-site</id>

<phase>verify</phase>

<goals>

<goal>report</goal>

</goals>

</execution>

<execution>

<!-- Rules for configuring build failure below a threshold limit based

on code coverage value using Jacoco -->

<id>check</id>

<goals>

<goal>check</goal>

</goals>

<configuration>

<excludes>

<exclude>**/*config*.*</exclude>

</excludes>

<rules>

<rule implementation="org.jacoco.maven.RuleConfiguration">

<element>BUNDLE</element>

<limits>

<limit implementation="org.jacoco.report.check.Limit">

<counter>INSTRUCTION</counter>

<value>COVEREDRATIO</value>

<minimum>0.50</minimum>

</limit>

</limits>

</rule>

</rules>

</configuration>

</execution>

</executions>

</plugin>

We have functional tests in our repo that we want to trigger as part of the SonarQube checks, so we configure the path to finding these under the maven-surefire plugin. And there we can also mention any tests that we may not to want to run and exclude them if we wish. However, if this doesn’t apply to your case, you may be okay to ignore this part.

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-surefire-plugin</artifactId>

<version>${maven-surefire-plugin.version}</version>

<configuration> <testSourceDirectory>src/test/java/com/my/directory/tests</testSourceDirectory>

<trimStackTrace>false</trimStackTrace>

<excludes>

<exclude>**/SmokeTests.java</exclude>

</excludes>

</configuration>

</plugin>

Now we are looking at the profile piece at the bottom.

<profile>

<id>sonar</id>

<activation>

<activeByDefault>true</activeByDefault>

</activation>

<properties>

<!-- Edit this URL for sonarQube server --> <sonar.host.url>https://sonarqubedeveloper.internal</sonar.host.url>

<sonar.login>mySonarQubeToken</sonar.login>

<sonar.pullrequest.github.repository>HMH-Core/MyRepoNameWithout</sonar.pullrequest.github.repository>

<!-- Sonar-JaCoCo properties -->

<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>

<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>

<sonar.jacoco.reportPaths>${basedir}/target/jacoco.exec</sonar.jacoco.reportPaths>

<java.version>1.8</java.version>

<sonar.coverage.exclusions>

**/MyApplication.java, **/*Exception*.java, **/dao/**, **/dto/**, **/entity/**

</sonar.coverage.exclusions>

</properties>

</profile>

We have a new profile created and there under sonar.host.url we should set the url for our SonarQube instance. We also mention the Java version we’re using and the path to any files that we may want to exclude from the coverage checks handled by jacoco.

But still inside the properties piece, here we’re actually going ahead of ourselves just a little bit, and if you intend to run SonarQube locally and outside the Github context, you may be able to skip some lines and should be already good to run your validation now. However, as the title for this tutorial mentions, our final goal at the end is to display the results coming from the SonarQube checks on Github once a PR is submitted. For this we need these extra fields in the .pom file, such as the name of our repository and token for this SonarQube instance.

Okay, so we are able to run these SonarQube checks locally now. However, let’s do it better and create a Jenkins job that triggers these checks for us. This shouldn’t take too long, but if you may feel like grabbing a cup of coffee, please go ahead and I’ll wait for you here.