SonarQube & Static Analysis for Kotlin Android Applications
SonarQube:
SonarQube is a universal tool for static code analysis that has become the industry standard.
Features of SonarQube :
•SonarQube offers code-quality management by suggesting what is wrong and helps us put it right.
•It provides a clean dashboard to address bugs, coding rules, test coverage, API documentation, code duplication, complexity, and many more things.
•Other code quality tools focus mainly on bugs and complexity but Sonar covers 7 sections of code quality:- Architecture and design, unit tests, duplicated code, potential bugs, complex code, coding standards, and comments.
•SonarQube supports 25+ languages as well and generates reports of code smells ,vulnerabilities and bugs.
SonarQube 7.9 added support for Kotlin language to analyze code quality of code developed in Kotlin.
SonarQube integration in Android :
Step 1 : Download the latest version of SonarQube and unzip it.
C:\_develop_android_studio\sonarqube-8.4.1.35646\sonarqube-8.4.1.35646
Step 2: open sonarQube directory folder and run server on the shell by using StartSonar.bat file.
C:\_develop_android_studio\sonarqube-8.4.1.35646\sonarqube-8.4.1.35646\bin\windows-x86–64
Note: There will be separate folder for each OS and the corresponding file to be run to start sonar server
Step 3: We can check server on the browser by using http://localhost:9000
log in the admin panel by using admin/admin credential.
Step 4: In project level build.gradle add the below classpath dependencies within buildscript
buildscript{
dependencies {
classpath “org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.0” }
}
Step 5: In app level build.gradle apply the below plugin
plugins{
id ‘org.sonarqube‘
}
Step 6: Once SonarQube is added in Android Application, its time to add the basic configuration for SonarQube in app level build.gradle
sonarqube {
properties {
property “sonar.projectName”, “TestApp”
property “sonar.projectKey”, “TestApp”
property “sonar.host.url”, “http://localhost:9000"
property “sonar.language”, “kotlin”
property “sonar.sources”, “src/main/java”
property “sonar.sourceEncoding”, “UTF-8”
property “sonar.login”, “admin”
property “sonar.password”, “admin”
property “sonar.coverage.exclusions”, “src/androidTest/java“
}
Step 7: Hit “Sync Now” to complete Sonarqube integration in Android app.
Generating and publishing report :
To generate a report in sonarqube dashboard, we need to run below Gradle command in the terminal:
gradlew sonarqube -Dsonar.host.url=http://localhost:9000/
The above command builds project on sonar server.
Once project is successfully build project in Android Studio terminal refresh sonar admin panel and you will see report with code smells and bugs.
Sonarqube code smells dashboard:
Static Analysis tools for Kotlin projects:
Detekt :
Is a static code analysis tool for the Kotlin programming language.
Features:
•Code smell analysis for your Kotlin projects.
•It provides code analysis related to Kotlin code styles, formatting ,exceptions ,naming convention and so on.
•Highly configurable rule sets
•Gradle plugin for code analysis via Gradle builds.
- Seamless integration with official SonarQube
Detekt integration for Kotlin project :
Step 1: In app level build.gradle apply the below plugin
plugins{
id(“io.gitlab.arturbosch.detekt”).version(“1.11.0-RC1”)
}
Step 2: sync the project and generate detekt.yml that contains ruleset using the below command:
gradlew detektGenerateConfig
Copy the generated yml file in any folder in the app as per convenience.
Note: The detekt.yml file can also be copied from detekt website rather than executing above command.
Step 3: Enable detekt in sonarqube .
Login into SonarQube (http://localhost:9000/)
Navigate to Administration > Marketplace > Search for detekt and install detekt plugin . Once installation is done restart SonarQube locally with “StartSonar.bat” .
Step 4: To make use of detekt rules ,we need to setup some properties like detekt.yml file path under
Administration > configuration > select detekt
Step 5: In the app level build.gradle add below configuration that contains path to the src files to be analyzed,path of detekt.yml and path where reports to be generated:
detekt {
toolVersion = “1.11.0-RC1”
input = files(“src/main/java”)
config = files(“$rootDir/config/detekt/detekt.yml”)
reports {
xml {
enabled = true // Enable/Disable XML report (default: true)
destination = file(“$buildDir/reports/detekt.xml”) // Path where XML report will be stored (default: `build/reports/detekt/detekt.xml`) }
html {
enabled = true // Enable/Disable HTML report (default: true)
destination = file(“$buildDir/reports/detekt.html”) // Path where HTML report will be stored (default: `build/reports/detekt/detekt.html`) }
txt {
enabled = true // Enable/Disable TXT report (default: true)
destination = file(“$buildDir/reports/detekt.txt”) // Path where TXT report will be stored (default: `build/reports/detekt/detekt.txt`) }
custom {
reportId = “CustomJsonReport” // The simple class name of your custom report.
destination = file(“$buildDir/reports/detekt.json”) // Path where report will be stored }}}
Note: Can create separate detekt.gradle file and can be included in the build.gradle as well
Step 6: Update the basic configuration for SonarQube in app level build.gradle in order to publish detekt results to sonarQube
sonarqube {
properties {
property “sonar.projectName”, “HiltApp”
property “sonar.projectKey”, “HiltApp”
property “sonar.host.url”, “http://localhost:9000"
property “sonar.language”, “kotlin”
property “sonar.sources”, “src/main/java”
property “sonar.sourceEncoding”, “UTF-8”
property “sonar.login”, “admin”
property “sonar.password”, “admin”
property “sonar.coverage.exclusions”, “src/androidTest/java”
property “detekt.sonar.kotlin.config.path”, “$rootDir/config/detekt/detekt.yml”
property “sonar.issuesReport.html.enable”, “true”
property “sonar.issuesReport.console.enable”, “true”
property “sonar.kotlin.detekt.reportPaths”, “$buildDir/reports/detekt.xml”
property “sonar.kotlin.detekt.reportPaths”, “$buildDir/reports/detekt.xml”
}}
Step 7: Run the below gradle command to locally check the detekt issues
gradlew check
The above command fails the build and reports code smells if any .Also writes the issues to the local configured report files.
Step 8: To post all the issues to SonarQube server run the below command:
gradlew sonarqube -Dsonar.host.url=http://localhost:9000/
The above posts all the reported issues to the SonarQube dashboard.
Using Git Hooks :
The above steps mentioned shows how to setup sonarqube locally.
What if we want our Sonar server set up that can be triggered with Git or on-demand ?
To improve development further we need to add a script that tells git to check the format before you commit your changes.
Git hooks:
Git hooks are programs you can place in a hooks(.git/hooks) directory to trigger actions at certain points in git’s execution.
For instance we run the below command to check for lint issues:
./gradlew lint
We want the above command to be executed before we actually commit /push our code. In order to do that, we need to do the following:
•Go to the .git/hooks folder of your repository.
•Create a file called pre-commit.
•Copy the following snippet in pre-commit :
#!/bin/bash
git stash -q --keep-index
echo "Running git pre-commit hook"
echo "Running Kotlin lint"
./gradlew ktlint
result=$?
if [ "$result" = 0 ] ; then
echo "Kotlin lint found no problems"
else
echo
"Problems found, files will not be committed."
echo "Writing to SonarQube"
./gradlew sonarqube -Dsonar.host.url=http://localhost:9000/
exit 1
fi
echo "Running detekt"
./gradlew check
RESULT=$?
if [ "$RESULT" = 0 ] ; then
echo "Detekt found no problems"
else
echo
"Problems found, files will not be committed."
exit 1
fi
echo "Running android lint"
./gradlew lint
result=$?
if [ "$result" = 0 ] ; then
echo "Android lint found no problems"
else
echo
"Problems found, files will not be committed."
exit 1
fi
echo "Writing to SonarQube"
./gradlew sonarqube -Dsonar.host.url=http://localhost:9000/
RESULT=$?
git stash pop -q
# return 1 exit code if running checks fails
[ $RESULT -ne 0 ] && exit 1
exit 0
When ever we try to commit the code lint checks will run and will display the issues.
The code that is added in pre-commit file does Ktlint checks ,Detekt checks, android lint and publishes issues to Sonarqube server that is setup locally.
Git Hooks need to be manually installed, they are not stored in a repository for all the users as .git folder is created locally.
In order to be available to all users create a folder “githooks/ folder” and save pre-commit file in that folder or we can create pre-commit file in the root directory.
Once gradle runs to build the application , pre-commit file needs to be copied to .git/hooks folder.
Add the below script in the app level build.gradle file:
android{
copy {
from “../pre-commit”
into “../.git/hooks”
fileMode 0777
}
Sample Application:
All the above steps mentioned are integrated as part of the sample application in the below Github link:
References:
https://github.com/detekt/detekt