In this article, we’re going to set up SonarQube for an Android project. At DISQO, we are working on a multi-module, multi-flavor 100% Kotlin Android app. I’ve spent a good amount of time writing just a couple dozen lines of code because:
- SonarQube documentation is not straightforward. There is no clear indication of which properties should be used, and which should be omitted.
- There are only a few examples of this type of Android project. The ones that do exist are mostly related to Java or are using SonarQube properties that are obsolete, like
sonar.jacoco.reportPaths
.
Let’s start with JaCoCo before we set up SonarQube.
Set Up JaCoCo
We’ll first setup JaCoCo, a tool that will helps us generate coverage reports for the code base. Reports generated will contain detailed information about the classes and paths covered by tests. In the top-most build.gradle
file, add JaCoCo to classpath
.
buildscript { repositories { ... } dependencies { ... classpath "org.jacoco:org.jacoco.core:0.8.5" } }
|
Inside the project, create a jacoco.gradle
file with content from this gist.
Now inside each module’s build.gradle
file, apply the newly created jacoco.gradle
using the following.
apply from: "$project.rootDir/jacoco.gradle"
|
Now you’ll be able to generate JaCoCo coverage reports. Assuming the flavor name is dev
, a report is created using this simple terminal command.
./gradlew clean testDevDebugUnitTestCoverage
|
Set Up SonarQube
SonarQube must be run locally or on a remote machine. To learn to do this, refer to SonarQube’s instructions. Once you have SonarQube running, add the following classpath
in the root build.gradle
file.
buildscript { repositories { ... } dependencies { ... classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8" } }
|
Inside the project, create a sonar.gradle
file with the following content.
apply plugin: "org.sonarqube"
sonarqube { properties { property "sonar.host.url", "https://sonarqube.yourcompany.com" property "sonar.login", "your fancy key" property "sonar.projectName", "Your Awesome Project Name" property "sonar.projectKey", "my-test-project" property "sonar.projectVersion", "1.0.0" property "sonar.sourceEncoding", "UTF-8" property "sonar.java.coveragePlugin", "jacoco" // taken from `jacoco.gradle` property "sonar.coverage.exclusions", "**/test/**,**/androidTest/**,**/R.class,**/BuildConfig.*,**/Manifest*.*,**/*Test*.*,**/com/example/databinding/*,**/com/example/generated/callback/*,**/*Dto*.*,**/android/databinding/*,**/androidx/databinding/*,**/di/module/*,**/*MapperImpl*.*,**/BuildConfig.*,**/*Component*.*,**/*BR*.*,**/Manifest*.*,**/*Companion*.*,**/*Module.*,**/*Dagger*.*,**/*MembersInjector*.*,**/*Extensions*.*,**/InputMethodManagerLeaks.*,**/*_Factory*.*,**/*_Provide*Factory*.*" } }
// task named `testDevDebugUnitTestCoverage` is created inside `jacoco.gradle` tasks.sonarqube.dependsOn ":app:testDevDebugUnitTestCoverage"
|
Then apply the newly created sonar.gradle
to the project. Add the following line inside root build.gradle
.
apply from: "$project.rootDir/sonar.gradle"
|
Add the SonarQube plugin to all sub-projects using the subprojects
DSL inside the top-most build.gradle
file.
subprojects { apply plugin: "org.sonarqube" sonarqube { properties { property "sonar.coverage.jacoco.xmlReportPaths", "$projectDir.parentFile.path/app/build/reports/jacoco/testDevDebugUnitTestCoverage/testDevDebugUnitTestCoverage.xml" } } }
|
As a result, root the build.gradle
file should be similar to the following.
apply from: "$project.rootDir/sonar.gradle"
buildscript { repositories { ... } dependencies { ... classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8" } }
allprojects { ... }
subprojects { apply plugin: "org.sonarqube" sonarqube { properties { property "sonar.coverage.jacoco.xmlReportPaths", "$projectDir.parentFile.path/app/build/reports/jacoco/testDevDebugUnitTestCoverage/testDevDebugUnitTestCoverage.xml" } } ... }
|
The Result
If your project is set up correctly, it should look like the following.
Join DISQO
If building powerful Android applications on a modern tech stack sounds like a dream job to you, check us out at DISQO. We are hiring!
Andranik Azizbekian is a Senior Software Engineer at DISQO, and originally published this article on Medium.