How to setup sonar for multi-module gradle project

Hi,

We am working on splitting out our gradle build for a multi module gradle project. Previously we used to build the whole repo together using a build.gradle at the top level and sonarqube works fine but now we want to build submodules in the repo with their own build.gradle files. The issue we are hitting is with integrating sonarqube for submodules.

  1. When I am keeping sonarqube property in top level and nested level build.gradle, I am hitting this error:
    File abc/src/main/java/abc.java can’t be indexed twice. Please check that inclusion/exclusion patterns produce disjoint sets for main and test files

  2. When I removed sonarqube property from the top level and only having it at the nested level, I am getting this error:
    sonarqubeSonarQube server [http://localhost:9000] can not be reached

    even though sonar.host.url is specified in nested level build.gradle

I am trying to build my submodule with this command:
gradle :abc:build sonarqube -Dsonar.login=USERNAME -Dsonar.password=PASSWORD -Dsonar.branch.name=​test -Dsonar.projectVersion=test -Dsonar.sources=abc/src/main/java

Repo structure:

project:
	build.gradle
	abc/:
		build.gradle
		src/main/java
		.....
	xyz/:
		build.gradle
		src/main/java
		.....

Can someone please help me in setting sonarqube correctly for our submodule builds?

Hi @Nitish,

Welcome to the Community!

Yes, multi-module Gradle projects can be a bit painful to set up. I’m assuming you’re using a Gradle multi-project build? I experimented with this a few months ago; here’s what worked for me.

In the top-level build.gradle I have two blocks:

sonarqube {
    properties {
        property "sonar.host.url", "http://<hostname>:<port>"
        property "sonar.sourceEncoding", "UTF-8"
        property "sonar.projectName", "Example Gradle multi-project"
        property "sonar.projectKey", "my-example-gradle-multi-project"
    }
}

...

subprojects {
    version = '1.0'
    sonarqube {
        properties {
            property "sonar.sources", "src/main"
            property "sonar.tests", "src/test"
            // I was testing with JaCoCo, so the next line is not needed if you're using some other tool
            property "sonar.coverage.jacoco.xmlReportPaths", "../build/reports/jacoco/codeCoverageReport/codeCoverageReport.xml"
            property "sonar.host.url", "http://<hostname>:<port>"
        }
    }
}

Then in the top-level settings.gradle file I have:

rootProject.name = 'example_gradle_multi_project'
include 'abc'
include 'xyz'

Nothing needed at the abc/build.gradle or xyz/build.gradle level :slight_smile:

Let me know whether this works for you.

Regards,

Cameron.

2 Likes

I’ve also been looking for a best practice way to set-up a multi-module gradle project, but found that I end up with one project per module in the sonar interface. This is a problem when some projects contain API modules (with no tests, and therefore no test coverage), and implementation modules (with tests, and therefore test coverage).

When I say I want 90% coverage, and I want it to mean “across the multi-module project as a whole”.
how do I do that?

Hi @pebble_statue,

SonarQube coverage is per project. So in your situation you need to either analyze the multi-module project as a single SonarQube project, or if you’re a commercial customer use an Application to aggregate the individual projects, which will also calculate overall coverage.

Regards,

Cameron.

I eventually managed to track the multi-module kotlin project as a single project in sonarcloud.

The only resource that I found helpful is https://github.com/triplem/gradle-by-example/.

Everything else is a choose-your-own-hell adventure.

1 Like

hello, how to skip unit test and androidtest in gradle properties

Hi Cameron
I have multi-module Gradle projects similar to the example. I can analyze every module with Sonarqube, but not exactly the way I want.

sonarqube.gradle :

apply plugin: "org.sonarqube"

sonarqube {
    properties {
        property "sonar.host.url", "http://<hostname>:<port>"
        property "sonar.sourceEncoding", "UTF-8"
        property "sonar.projectName", "Example Gradle multi-project"
     //   property "sonar.projectKey", "my-example-gradle-multi-project" // Removed key for every module can be run
    }
}

abc/build.gradle :

apply from: "$rootDir/sonarqube.gradle"

xyz/build.gradle :

apply from: "$rootDir/sonarqube.gradle"

When I want to analyze the modules in the project, I write to the terminal :
./gradlew sonarqube
This way , I am able to run and analyze each module as a different project. This is ok.

But My problem :
I want to run only 1 module among the modules. But I cant.Can I run a single module I want ?

I’ve tried : ./gradlew -Dsonar.sources=/Users/Name/StudioProjects/Proje/Module/src/main/... sonarqube

In this way, only one module is analyzed but other all modules set empty analysis (“…this projects is empty.”)
I dont want this :

Hi,

Thanks. It seems to be working with jacoco and detekt, but doesn’t work with owasp dependency check (org.owasp.dependencycheck)

My config is

subprojects {
    apply {
        plugin("org.jetbrains.kotlin.jvm")
        plugin("io.gitlab.arturbosch.detekt")
        plugin("org.sonarqube")
        plugin("org.owasp.dependencycheck")
        plugin("jacoco")
    }

    dependencies {
        detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:" + System.getenv("GRADLE_DETEKT_VER") ?: "1.22.0")
    }

    jacoco {
        toolVersion = System.getenv("GRADLE_JACOCO_VER") ?: "0.8.8"
    }

    tasks.jacocoTestReport {
        reports {
            xml.required.set(true)
        }
    }

    tasks.withType<Test> {
        useJUnitPlatform()
        finalizedBy("jacocoTestReport")
    }

    dependencyCheck {
        format = "ALL"
    }

    sonarqube {
        properties {
            property ("sonar.host.url", System.getenv("SONARQUBE_URL") ?: "")
            property ("sonar.token", System.getenv("SONARQUBE_TOKEN") ?: "")

            property ("sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml,build/reports/jacoco/test/jacocoTestReport.xml")

            property ("sonar.dependencyCheck.jsonReportPath", "build/reports/dependency-check-report.json")
            property ("sonar.dependencyCheck.htmlReportPath", "build/reports/dependency-check-report.html")
            
            property ("sonar.kotlin.detekt.reportPaths", "build/reports/detekt/detekt.xml")
        }
    }

    detekt {
        // Version of Detekt that will be used. When unspecified the latest detekt
        // version found will be used. Override to stay on the same version.
        toolVersion = System.getenv("GRADLE_DETEKT_VER") ?: "1.22.0"

        // If set to `true` the build does not fail when the
        // maxIssues count was reached. Defaults to `false`.
        ignoreFailures = true
    }
}

Had anybody solved this issue already?

Thank you in advance.

Solved. I should have used dependecyCheckAggregate