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.