Gradle and SonarQube

If you are like me and like developing using a Test Driven Development (TDD) approach, then you need the ability to examine your code and test coverage. In a past article, I discussed how to use SonarQube to perform Python code inspection allowing you to see code test coverage. In this article, I’ll look at how to set up Gradle to talk to SonarQube.

The SonarRunner

SonarQube has a companion tool called the SonarRunner. The runner is what actually runs the unit tests (or integration tests) on your software, and then reports it to the SonarQube database. One of the nice things about the SonarRunner is that you can add it to just about any project that can be analyzed by SonarQube – regardless of whatever other lifecycle or build tools you may use. All you need to do is add a sonar-runner.properties file with the required information.

One problem however, is that the SonarRunner is yet another tool that is needed during the build process. If you maintain a continuous integration environment where, say, your nightly builds include an inspection run, then you know the pain of having to maintain yet another standalone binary package. Luckily, Gradle has a SonarRunner plugin that is incubating, and is stable enough to use.

Setting Up the Gradle Plugin

The SonarRunner plugin has been included in most recent distributions of Gradle. Applying the plugin requires one line:

apply plugin: sonar-runner

In order to get the runner talking to your local installation of Sonar, you will also need a sonarRunner configuration section in your build.gradle file (note – if you have an older version of Gradle this may not work for you, since older versions used slightly different properties). A minimal set of configuration properties is as follows:

sonarRunner {
    sonarProperties {
        property "sonar.host.url", "http://10.0.0.60:9000"
        property "sonar.jdbc.url", "jdbc:postgresql://10.0.0.60:5432/sonar"
        property "sonar.jdbc.driverClassName", "org.postgresql.Driver"
        property "sonar.jdbc.username", "mySonarUsername"
        property "sonar.jdbc.password", "mySonarPassword"
        property "sonar.projectKey", "MyJavaProject"
        property "sonar.projectName", "My Java Project"
        property "sonar.projectVersion", android.defaultConfig.versionName
        property "sonar.language", "java"
        property "sonar.sources", "src/main"
        property "sonar.binaries", "build"
    }
}

Here are some of the settings in more detail:

  • sonar.host.url – this is the URL to your Sonar host. Note that if you are trying to use a host that is protected by SSL, you will need some additional configuration information.
  • sonar.jdbc.url – this is the JDBC (database) URL. In my case, I was using PostgreSQL server, so I used the postgresql JDBC syntax. The 10.0.0.60 is my internal IP address, and 5432 is the port that the database listens on. Note that in the case of PostgreSQL, you need to explicitly tell it the addresses to listen on in your postgres.conf file, otherwise it defaults to listening on port 5432 only for localhost.
  • sonar.jdbc.driverClassName – should be fairly obvious that this is the driver it should be using for the database connection.
  • sonar.jdbc.username – this is the username used to access the database – not a username that you set up to access the front-end application (if you have authentication for SonarQube turned on).
  • sonar.jdbc.password – this is the password used to access the database – again, not a front-end application username password.
  • sonar.projectKey – a unique name used to identify the project.
  • sonar.projectName – the name of the project, more readable for us humans.
  • sonar.projectVersion – should be fairly obvious. In this instance, I have a second set of `android` properties which are describing my project. Instead of duplicating the version number, I just used it here instead.
  • sonar.language – tells Sonar what language you are analyzing.
  • sonar.sources – where the source files for the project are located. Make sure you keep this path separate from your test cases, otherwise you will have your tests included in the analysis.
  • sonar.binaries – where build artifacts are located.

Configuring JaCoCo

While the above configuration will get you up and running, you will be missing coverage information from your unit tests. To generate coverage reports, you will also need to apply the JaCoCo plugin:

apply plugin: jacoco

Then, you need to set two more Sonar Runner properties as follows (add them below sonar.binaries):

property 'sonar.jacoco.reportPath', "${buildDir}/jacoco/testDebug.exec"
property 'sonar.junit.reportsPath', "${buildDir}/test-results"

You may have to adjust these depending on where jacoco is actually putting your results. Look for the exec file and the test-results paths after you run a build.

All Together

Putting it all together:

apply plugin: sonar-runner
apply plugin: jacoco
 
sonarRunner {
    sonarProperties {
        property "sonar.host.url", "http://10.0.0.60:9000"
        property "sonar.jdbc.url", "jdbc:postgresql://10.0.0.60:5432/sonar"
        property "sonar.jdbc.driverClassName", "org.postgresql.Driver"
        property "sonar.jdbc.username", "mySonarUsername"
        property "sonar.jdbc.password", "mySonarPassword"
        property "sonar.projectKey", "MyJavaProject"
        property "sonar.projectName", "My Java Project"
        property "sonar.projectVersion", android.defaultConfig.versionName
        property "sonar.language", "java"
        property "sonar.sources", "src/main"
        property "sonar.binaries", "build"
        property 'sonar.jacoco.reportPath', "${buildDir}/jacoco/testDebug.exec"
        property 'sonar.junit.reportsPath', "${buildDir}/test-results"
    }
}

You can now check out whether or not Gradle is configured correctly by looking at the tasks:

./gradlew tasks

You should see a new task called sonarRunner:

sonarRunner - Analyzes project ':app' and its subprojects with Sonar Runner.

To generate reports, you do the following:

./gradlew clean test sonarRunner

Gradle will clean the project, rebuild and run the unit tests. It will then perform a Sonar analysis, and post the results to your SonarQube instance. If everything is successful, you should see output similar to the following from Gradle:

17:30:40.937 INFO  - Sensor JaCoCoSensor...
17:30:40.965 INFO  - Analysing /home/thomas/AndroidStudioProjects/MyJavaProject/app/build/jacoco/testDebug.exec
17:30:41.598 INFO  - No information about coverage per test.
17:30:41.598 INFO  - Sensor JaCoCoSensor done: 661 ms
17:30:42.955 INFO  - Execute decorators...
17:30:45.010 INFO  - Store results in database
17:30:45.133 INFO  - ANALYSIS SUCCESSFUL, you can browse http://10.0.0.60:9000/dashboard/index/MyJavaProject
17:30:45.205 INFO  - Executing post-job class org.sonar.plugins.core.issue.notification.SendIssueNotificationsPostJob
17:30:45.210 INFO  - Executing post-job class org.sonar.plugins.core.batch.IndexProjectPostJob
17:30:45.266 INFO  - Executing post-job class org.sonar.plugins.dbcleaner.ProjectPurgePostJob
17:30:45.289 INFO  - -> Keep one snapshot per day between 2014-09-19 and 2014-10-16
17:30:45.291 INFO  - -> Keep one snapshot per week between 2013-10-18 and 2014-09-19
17:30:45.292 INFO  - -> Keep one snapshot per month between 2009-10-23 and 2013-10-18
17:30:45.294 INFO  - -> Delete data prior to: 2009-10-23
17:30:45.302 INFO  - -> Clean MyJavaProject [id=160]
17:30:45.309 INFO  - Clean snapshot 5368
 
BUILD SUCCESSFUL

And of course, browsing to your Sonar instance should reveal some good information about your project.

Summary

In this post, I discussed how to configure Gradle to run a Sonar analysis on your code, and post the results back to your SonarQube instance. In a future post, I’ll look at more of the SonarQube analysis results, and talk about common fixes for various problems.

Code Coverage with Coveralls

In an earlier post, I wrote about setting up SonarQube to assist with code inspection. While SonarQube has a number of advanced inspection features, one of its drawbacks is that you must have it running as a service before you can measure things like code test coverage. Impressively, a free service called Coveralls exists to perform code coverage reports. Like Travis CI, Coveralls is an online service that is free to use for open source projects that use GitHub. Setting it up involves:

  • Creating a Coveralls account
  • Adding your GitHub repository
  • Telling your CI service to post coverage information to it

Advertisements

Creating an Account

Creating an account involves logging in to Coveralls using your GitHub credentials – it’s that simple. For the sake of completeness, if you ever wish to stop using Coveralls, you can simply revoke Coveralls as an application from your GitHub account by clicking on Settings and then Applications. Under Authorized Applications you can see what other third party applications have access to your GitHub repositories. Simply click on the Revoke button if you wish to remove access.

coveralls-github-authorization

Adding Your GitHub Repository

Once you have created a Coveralls account and are signed in, click on the Repos link in the top navigation bar, and then Add Repo. You will be taken to a listing of all your current repositories. Simply switch On the repositories that you want Coveralls to keep track of.

coveralls-github-repo

Posting to Coveralls

Things can get slightly more complicated depending on the CI solution you are using and the language that your project is coded in. Luckily, the Coveralls documentation has very easy to use instructions on getting your project talking to Coveralls. For me, I was interested in getting my Java Chip 8 emulator hooked up. The project is already being built by Travis-CI so all I needed to do was get it to post the test results coverage to Coveralls.

The answer was a Gradle Plugin. Adding a dependency to Gradle is quite simple – it involves editing the build.gradle file, and inserting the named dependency with it’s groupId, artifactId and version into the list of dependencies (I spoke more about it in a previous post here). To make this work, you must first apply the Coveralls plugin by adding the following to the top of your configuration file:

apply plugin: 'coveralls'

Next comes the actual Coveralls dependency. The dependency goes in a slightly different spot, since the plugin isn’t actually a dependency for the software itself. In my previous post, I mentioned how there was a section called buildscript in the Gradle configuration file. This section is used to indicate dependencies during the build phase. By placing the plugin here, it will get included at compile time, but will not get packaged into the fat jar:

buildscript {
    repositories {
        mavenCentral()
    }
 
    dependencies {
        classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:0.3.0'
    }
}

Two other small changes to the build.gradle file are also needed in order for everything to work. The first is to enable the JaCoCo code coverage plugin. This is done by adding the following line:

apply plugin: 'jacoco'

Next, you must tell the plugin what reports you want to generate:

jacocoTestReport {
    reports {
        xml.enabled = true
        html.enabled = true
    }
}

That takes care of the configuration needed on the Gradle end of things. You can test that you have things configured right by doing a gradle tasks to check what tasks are available to Gradle. You should see both coveralls and jacocoTestReport as available tasks in the Other section.

Next up is to modify the .travis.yaml configuration file. The following code gets Travis to generate the JaCoCo coverage reports, and then post them to coveralls:

after_success:
  - gradle jacocoTestReport coveralls

That’s all that is needed. Pushing both modified files should force Travis to rebuild the project, and then post to Coveralls. To make sure everything is working correctly, you can watch Travis build your project, and troubleshoot from there.

Browsing Your Coverage Report

Coveralls displays a list of all your repositories and the current coverage for each one:

coveralls-report1

That’s helpful, but it’s more helpful to find out where you are lacking coverage. Luckily, Coveralls lets you see that too. Clicking on the repository name will take you into a more detailed report, outlining the change to code coverage based upon each commit:

coveralls-report2

This is slightly more useful information, but we’re not done yet. Clicking on the build number will take you into a more detailed report. By scrolling down to the bottom of the report, you can see a breakdown of coverage by file:

coveralls-report3

This is the type of report we want! Clicking on a file will reveal another report where tested lines will show up in green, and untested lines will show up in red:

coveralls-report4

You can use this information to help you determine what lines you are testing, and what lines you are not.

Conclusions

Coveralls provides a convenient, online service that will let you view your test coverage through a simple web interface. Like Travis, Coveralls also supports testing private repositories for a price. If you are looking to do simple code inspection, and need some place to start, Coveralls provides a simple way to get up and running without the need to run your own service.