Android, gradle and sonar analysis - Part II

In the previous write-up, we saw how to get an android project building in jenkins using gradle build script.

Let us now delve into how to do a sonar(qube) analysis of the android project and have jenkins automate it. I don't want to get into why sonar analysis or for that matter, code quality management.  (That is a separate topic in itself - you can start with this).

Sonar provides an android plugin to analyze android projects.  The plugin uses android lint data as well as analyzes manifest and resource files.

Now sonar analysis itself can be done in many ways.  In many of our earlier projects, we had used sonar runner which is recommended as the default launcher.   This was mainly because we had multi-module multi-language projects.  We need to have the sonar-runner software (which is different from sonar) and create a sonar-project.properties file.

Anyway, this one was a pure android project and since I was using gradle, I wanted to see if I could use gradle to run sonar analysis.  Yes, it is possible - courtesy gradle sonar-runner plugin.  The plugin is "incubating" (as I write this). sonarqube gradle plugin.  I have detailed how to do this in this post. I would suggest ignoring the next few section describing how to use gradle sonar-runner plugin and skip to the jenkins configuration part.

[Ignore Start]

The advantage of using the plugin is, you do not need either the sonar-runner software or a separate properties file.  The sonar configuration information is placed in the gradle build script itself.

The plugin documentation is detailed and it is straightforward to make the changes.  In my case, the relevant section of the build script looked like this.

apply plugin: "sonar-runner"
...
sonarRunner { 

    sonarProperties { 
        property "sonar.host.url", "http://my.sonar.url" 
        property "sonar.jdbc.url", "my.jdbc.url" 
        property "sonar.jdbc.driverClassName", "com.mysql.jdbc.Driver" 
        property "sonar.jdbc.username", "myuser" 
        property "sonar.jdbc.password", "*****" 
        property "sonar.login", "mylogin" 
        property "sonar.password", "****" 
        property "sonar.sources", "src" 
        property "sonar.binaries", "build/classes/debug" 
        property "sonar.profile", "Android Lint" 
        property "sonar.projectKey", "my.group:project-key" 
        property "sonar.projectName", "MyProject" 
        property "sonar.projectVersion", "1.0-SNAPSHOT" 
        property "sonar.projectDescription", "My Project description" 
        }
}

If you have used sonar before, most of the above properties will be self-explanatory.   A few lines on the others:

  • Our sonar instance needs authentication - hence sonar.login and sonar.password.
  • Since our android project code was not in "src/main/java", I had to specify the location in sonar.sources
  • Since gradle places the compiled classes in build/classes/debug and build/classes/release (rather than target/classes), I had to specify the sonar.binaries location. (Classes are required by findbugs)
  • Since we are analysing android project, I specified sonar.profile as Android Lint.
  • The last four properties above are required for us to identify our project correctly in sonar dashboard.


With the above changes, running

gradle sonarRunner

resulted in the sonar analysis being done and the results populated in the sonar dashboard.

[Ignore End]

Now it was a simple matter of adding this task to the jenkins build script so that it triggered an analysis after the build.

One drawback is that the task is run as part of the build step in jenkins and not a Post-build action.  This is because it is not possible to invoke a gradle script (or for that matter even an arbitrary shell command) in a jenkins Post-build action.

If sonar jenkins plugin is installed, you could run sonar-runner as a build step or do a maven analysis Post-build.

Another gotcha is the quality profile.  Android Lint is a Java language quality profile.   When this runs, no other Java language quality profile is invoked.  Now Android Lint has only android-specific rules and not the java rules.  The fix for this is to have Android Lint inherit from another java profile (Sonar way with findbugs in our case).



I got this tip from this nice blog post, which incidentally details how to do sonar analysis of android projects with maven.

In case you encountered a problem (like me), where the other Java language quality profiles had zero rules,  then it is due to a sonar bug.  The workaround is specified in the bug details and is expected to be fixed in the upcoming sonarqube 4.2 release.


Comments

  1. Thanks a lot for your blog post
    I've just done a little modification respect your configuration because I don't know why my analysis where empty despite android Lint was give correct results.
    apply plugin: "sonar-runner"

    sonarRunner {
    sonarProperties {
    property "sonar.host.url", "http://mysonar"
    property "sonar.jdbc.url", "jdbc:mysql://host:port/sonarqube?useUnicode=true"
    property "sonar.jdbc.driverClassName", "com.mysql.jdbc.Driver"
    property "sonar.profile", "Android Lint"
    property "sonar.projectName", "MyApp"
    property "sonar.projectKey", "com.example.myApp"
    property "sonar.projectVersion", "1.0.0-SNAPSHOT"
    property "sonar.language", "java"
    property "sonar.sources", "src"
    property "sonar.binaries", "build"
    property "sonar.android.lint.report", "build/outputs/lint-results.xml"
    }
    }

    subprojects {
    sonarRunner {
    sonarProperties {
    property "sonar.sourceEncoding", "UTF-8"
    property "sonar.sources", "src/main"
    }
    }
    }

    The most important was the sonar.android.lint.report and the sonar.sources in the subproject set to src/main

    Thanks a lot

    ReplyDelete
    Replies
    1. Hi,

      Thanks for your suggestion regarding sonar, but when i run gradle sonarRunner command through terminal I am getting error as given below

      INFO: ------------------------------------------------------------------------
      INFO: EXECUTION FAILURE
      INFO: ------------------------------------------------------------------------
      Total time: 18.213s
      Final Memory: 7M/110MERROR: Error during Sonar runner execution
      ERROR: Unable to execute Sonar
      ERROR: Caused by: Can not invoke method public java.lang.Class org.sonar.plugins.surefire.SurefireSensor.dependsUponCoverageSensors()
      ERROR:
      ERROR: To see the full stack trace of the errors, re-run SonarQube Runner with the -e switch.
      ERROR: Re-run SonarQube Runner using the -X switch to enable full debug logging.

      INFO: ------------------------------------------------------------------------
      :app:sonarRunner FAILED

      FAILURE: Build failed with an exception.

      =====================================

      If you have any solution regarding it, please provide me a proper solution for it.

      Thanks & Regards


      Delete
    2. This write-up is dated/obsolete - sonar-runner has been superseded by sonar-scanner. Follow steps in http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+Gradle - I will try to update this post suitably

      Delete

Post a Comment

Popular posts from this blog

Opening a safe deposit locker in SBI

Opening a Kannada Word document

Switching to Tatasky make my pack