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.

SonarQube

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.


Andranik Azizbekyan is a Senior Software Engineer at DISQO whose day-to-day job is making Survey Junkie application better for its users. Occasionally, you can see him answering a question in Stackoverflow, or writing a blog post. In his spare time, he reads newsletters related to new technologies, learns new stuff from open source projects, and plays with dogs that are crossing by on streets.