SonarQube makes static code analysis easy for a plethora of languages and environments. In many of our newer projects we use gradle as our buildsystem and jenkins as our continuous integration server. Integrating sonarqube in such a setup can be done in a couple of ways, the most straightforward being
- Integrating SonarQube into your gradle build and invoke the gradle script in jenkins
- Letting jenkins invoke the gradle build and execute the SonarQube scanner
I chose the latter one because I did not want to add further dependencies to the build process.
Configuration of the SonarQube scanner
The SonarQube scanner must be configured by property file called sonar-project.properties
by default:
# must be unique in a given SonarQube instance sonar.projectKey=domain:project # this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. sonar.projectName=My cool project sonar.projectVersion=23 sonar.sources=src/main/java sonar.tests=src/test/java sonar.java.binaries=build/classes/java/main sonar.java.libraries=../lib/**/*.jar sonar.java.test.libraries=../lib/**/*.jar sonar.junit.reportPaths=build/test-results/test/ sonar.jacoco.reportPaths=build/jacoco/test.exec sonar.modules=application,my_library,my_tools # Encoding of the source code. Default is default system encoding sonar.sourceEncoding=UTF-8 sonar.java.source=1.8 sonar.links.ci=http://${my_jenkins}/view/job/MyCoolProject sonar.links.issue=http://${my_jira}/browse/MYPROJ
After we have done that we can submit our project to the SonarQube scanner using the jenkins SonarQube plugin and its “Execute SonarQube Scanner” build step.
Optional: Adding code coverage to our build
Even our gradle-based projects aim to be self-contained. That means we usually do not use repositories like mavenCentral for our dependencies but store them all in a lib directory along the project. If we want to add code coverage to such a project we need to add jacoco in the version corresponding to the jacoco-gradle-plugin to our libs in build.gradle
:
allprojects { apply plugin: 'java' apply plugin: 'jacoco' sourceCompatibility = 1.8 jacocoTestReport { reports { xml.enabled true } jacocoClasspath = files('../lib/org.jacoco.core-0.7.9.jar', '../lib/org.jacoco.report-0.7.9.jar', '../lib/org.jacoco.ant-0.7.9.jar', '../lib/asm-all-5.2.jar' ) } }
Gotchas
Our jenkins build job consists of 2 steps:
- Execute gradle
- Submit project to SonarQube’s scanner
By default gradle stops execution on failure. That means later tasks like jacocoTestReport are not executed if a test fails. We need to invoke gradle with the --continue
switch to always run all of our tasks.