How to configure multi-module gradle SonarQube scan to only scan built artifacts

We are using the following SonarQube:

  • Version: Enterprise Edition v2025.2
  • Deployment: GKE
  • Gradle Sonar Plugin: 6.0.1.5171

Our project is a multi-module gradle repo with the following layout:

├── build.gradle
├── golang_services
│   ├── golang_service1
│   │   ├── build.gradle
│   ├── golang_service2
│   │   ├── build.gradle
├── java_services
│   ├── java_services1
│   │   ├── build.gradle
│   │   └── src
│   │       ├── main
│   │       └── test
│   ├── java_services2
│   │   ├── build.gradle
│   │   ├── build
│   │   │   ├── libs
│   │   │   │   ├── java_services2-0.1.0.jar
│   │   └── src
│   │       ├── main
│   │       └── test
│   ├── java_services3
│   │   ├── build.gradle
│   │   └── src
│   │       ├── main
│   │       └── test
│   ├── java_services4
│   │   ├── build.gradle
│   │   └── src
│   │       ├── main
│   │       └── test
├── shared
│   ├── build.gradle
│   ├── build
│   │   ├── libs
│   │   │   └── shared-1.0.0.jar
│   └── src
│       ├── main
│       └── test

We have multiple golang and java services with their own build.gradle files and a root build.gradle

There is a shared Java module is used by the golang_services and java_services.

As part of our CI process, we build only the modules that have changed in the PR and it’s dependent services.

So if java_services2 was updated, then the following modules are built:

  • java_services2
  • shared

We want to run a sonar scan only on the modules that were updated, and not on the entire multi-module project. For this, we use a custom logic which checks for the built artifacts and then skips the projects that did not have a JAR.

root build.gradle

subprojects {
    apply plugin: 'org.sonarqube'

    afterEvaluate { project ->
        def hasJars = hasBuiltJars(project)

        if (!hasJars) {
            sonar {
                skipProject = true
            } 
        } else {
        }
    }
  }
  
sonar {
    properties {
        property "sonar.projectName", "projectName"
        }
}

The approach we’re trying right now is to:

  • Get the list of modules that have built artefacts (shared-1.0.0.jar and java_services2-0.1.0.jar)
  • In the subprojects section, skip the modules that do not have JARs
  • Configure sonarqube to focus on the .java and .class files for shared and java_services2 modules

However gradle sonarqube is failing with the following error

Executed tasks: :sonar
File shared/src/test/java/shared/spring/services/ServiceImplTest.java can't be indexed twice. Please check that inclusion/exclusion patterns produce disjoint sets for main and test files

From my understanding, seems that the sonar scanner is scanning the shared module twice

  • when scanning the shared module
  • when scanning the java_services2 module, which has implemented the shared module

How can i configure SonarQube to do this selective scan only on the built artefacts and their files?

Hey there.

Have you considered making sure you’re taking advantage of incremental analysis instead of getting clever with excluding projects from the analysis.

In any case, I think that with your strategy, you just need to be more explicit about which folders should be indexed on each module, rather than relying on the defaults. This probably looks like this.

sonar {
  properties {
    property "sonar.sources", "src/main/java"
    property "sonar.tests", "src/test/java"
  }
}

If that doesn’t help, I’d be happy to help you if you can provide a small reproducer project that exhibits the issue!