Getting Sonar to reuse Cobertura reports in a multi-project analysis


(ben.pack) #1

I have a multi-project gradle build that I am trying to integrate with Sonar. Each subproject has an existing cobertura coverage file that I try to inform Sonar of, but the coverage doesn’t appear in Sonar unless I apply the Sonar plugin on each subproject. Unfortunately, this makes each subproject a top-level project in Sonar and I don’t benefit from a roll-up of all the metrics. Is there a way to apply the plugin on the root project and have all the subprojects send their code coverage analysis to Sonar?

Here’s an excerpt of the build.gradle file from the root project:

apply plugin: 'sonar'
  subprojects {
    sonar {
        project {
            sourceEncoding = "UTF-8"
        }
    }
}

And here is what appears in the build.gradle file for each subproject:

sonar {
    project.dynamicAnalysis = "reuseReports"
    project.coberturaReportPath = file("$buildDir/reports/cobertura/coverage.xml")
    project.testReportPath = file("$buildDir/test-results")
}

(Dan Stine) #2

I placed the sonar closure at the top-level of the root project, and the sub-projects were grouped in Sonar as desired, with one top-level project and multiple components.


(ben.pack) #3

I did that initially and I can get the sub-projects grouped in Sonar, but they don’t have the Cobertura coverage metrics. Do the subprojects in your build use cobertura? If so, do you mind sharing the Sonar closure you’re using?

I should also mention that the Cobertura coverage is defined on the subprojects, so there is no aggregate coverage metric for the overall project, just the subprojects.


(Dan Stine) #4

Oh, I didn’t realize you had already achieved grouping and that the only issue is Cobertura.

My top-level Sonar closure has only server{} and database{} sub-closures. I am not using Cobertura yet, so I guess posting it won’t be particularly useful. I am using Gradle 1.0-milestone-5 and Sonar 2.11.

I do want to integrate Cobertura eventually; I’d be interested to know about your approach. A quick search yielded this option: https://github.com/valkolovos/gradle_cobertura/wiki


(David Resnick) #5

I have the exact same problem and would like to solve this as well.

It seems that the sonar task finds the coverage.xml files (I can tell because it complains about some of the subprojects not having them) but no code shows coverage on the sonar server.


(ben.pack) #6

For Cobertura, I went with something like the approach outlined in the Gradle Cookbook.

I did figure out how to resolve the problem I was having after much experimenting. The top level closure in the root build.gradle needs to look something like this:

sonar {
    project {
        // Other settings here
        sourceEncoding = "UTF-8"
        dynamicAnalysis = "reuseReports"
    }
}

Then later in the same file I configure the subprojects I want to analyze with Sonar and other tools:

def projectsToAnalyze() {
    subprojects.findAll { project -> project.name != 'generated-sources' }
}
  configure(projectsToAnalyze()) {
    sonar {
        project.dynamicAnalysis = "reuseReports"
        project.coberturaReportPath = file("$buildDir/reports/cobertura/coverage.xml")
        project.testReportPath = file("$buildDir/test-results")
    }
}

It isn’t enough to have the subprojects tell Sonar to reuse the cobertura reports, the root has to do so as well.


(Bas Jansen) #7

Hi, I am having the same problem!

Ben, I tried your suggestion, but the output stays the same (no coverage and tests in Sonar).

Maybe you can help me?

I have the following:

sonar {
 server {
  url = ...
 }
   database {
  url = ...
  driverClassName = ...
  username = ...
         password = ...
 }
   project {
  sourceEncoding = "UTF-8"
  reuseReports = "reuseReports"
 }
}
  configure(subprojects) {
    sonar {
   project {
    coberturaReportPath = file("$reportsDir/tests/coverage.xml")
    testReportPath = file("$reportsDir/tests/junitreports") // for testng
    reuseReports = "reuseReports"
   }
    }
}

The paths are correct, because when configuring sonar on subproject level it works (but then I do not have 1 complete project in Sonar as you indicated in the issue)

Hope you can help!

Regards, Bas Jansen


(Bas Jansen) #8

This is weird!

When adding skip=true to the project block in the subprojects, it actually skips those projects.

So the configuration is set in the right way, but the report paths are not read by Sonar.

Looks like a bug to me…


(ben.pack) #9

My build script looks much the same except that my project blocks for both the main project and the subprojects use the ‘dynamicAnalysis’ as the key and ‘reuseReports’ as the value like so:

sonar {
    project {
        dynamicAnalysis = "reuseReports"
    }
}

The same appears in the subproject configuration block.


(Peter Niederwieser) #10

reuseReports is the default, so I don’t believe this makes a difference. sonar.project{} exists per project, even if you only apply the plugin to the root project (which is usually the right thing to do). This means that settings like sourceEncoding should be set for all projects to be analyzed, not just the root project.


(Peter Niederwieser) #11

What matters is where you apply the plugin. Usually the plugin should only be applied to the root project. This will still give you a sonar.project {} block per project. It doesn’t matter whether you configure these blocks from a parent project’s build script (with subprojects {}) or individually.


(Peter Niederwieser) #12

It’s dynamicAnalysis = “reuseReports”, but that’s the default anyway. Everything within sonar.project {} is per project. Therefore, settings like sourceEncoding should be set for all projects to be analyzed. Instead of configure(subprojects) {…} you can just say subprojects {…}.


(Peter Niederwieser) #13

This is the default so it won’t make a difference. Have a look at the GroovyDoc which documents all properties and their defaults.


(Peter Niederwieser) #14

My guess is that Sonar doesn’t handle Cobertura reports correctly when it comes to multi-project analysis. The Gradle Sonar plugin just passes the information on. If it works in the single-project case it’s rather unlikely (though of course not impossible) that it is a bug in the plugin.


(Bas Jansen) #15

Oh no… I must have overlooked that typo. Many thanks!

I did some more experimenting and it seems that ONLY when I configure dynamicAnalysis = “reuseReports” on the root, the subprojects will report tests results and coverage.

So now my implementation is:

sonar {
 server {
  ...
 }
   database {
  ...
 }
 project {
  dynamicAnalysis = "reuseReports"
  sourceEncoding = "UTF-8"
 }
}
  subprojects {
 sonar {
  project {
   coberturaReportPath = file("$reportsDir/tests/coverage.xml")
   testReportPath = file("$reportsDir/tests/junitreports")
   dynamicAnalysis = "reuseReports"
  }
 }
}

Still feels like a workaround…

Many thanks guys for your help!


(David Resnick) #16

I wanted to add thanks to Ben Packs help I got this working too.

It does seem that dynamicAnalysis=‘reuseReports’ is required.


(Peter Niederwieser) #17

I’ll have a look at this. Nevertheless, you should set sourceEncoding on all projects.


(Bas Jansen) #18

Ok, thanks for that hint!

Let me know if you need a tester :slight_smile:


(Peter Niederwieser) #19

Turns out that dynamicAnalysis only defaulted to reuseReports for projects that have the java plugin applied (which typically isn’t the case for the root project). This is fixed now. Thanks for the pointers!