Sonar Scan was failing for Gradle related multi-projects builds

I was trying to run sonarscan for gradle multiproject. I have running the scan from local using the command gradle sonar –info. Only one module it has analyzed and publish the results to sonarqube server. For the other modules it was not analyzing.

I was getting error for some modules like
The folder ‘src/test/java’ does not exist for ‘’ (base directory = /jenkinsapp/workspace/1.0-app-maven-gradle/dft)

13:56:21 > Task :dft:sonar FAILED

So after that i commented the sonar.sources and soner.tests in the sonar property file and started sonar scan ….it worked but only for one module.

The configuration related to sonar plugin and sonar properties in build.gradle file has given below:

plugins {

    // Declare the SonarQube plugin here but don't apply it automatically.

    // This makes the plugin available to all subprojects using the same version,

    // while allowing us to selectively apply it only to relevant modules (e.g., exclude 'bom' or root).

    id 'org.sonarqube' version '7.0.1.6134' apply false

}




allprojects {

    group = 'com.sai.qgt'

    version = '1.0.0.0-SNAPSHOT'




    repositories {

        maven {

            url = project.uri("http://8.8.8.8/repository/private")

            allowInsecureProtocol = true




            metadataSources {

                mavenPom()

                artifact()

                ignoreGradleMetadataRedirection()

            }

        }

    }

}




subprojects {

    if (project.name != 'bom') {

        apply plugin: 'java-library' // apply Java plugin to all submodules by default

        apply plugin: 'maven-publish'

        apply plugin: 'jacoco'

        apply plugin: 'org.sonarqube'




        sonar {

            properties {

                property "sonar.host.url", "https://sonar.sai.com"

                property "sonar.projectKey", "sai.qgt.app-gradle"

                property "sonar.projectName", "sai-qgt.app-gradle"

                property "sonar.token", "sai_12345672abcdef50a62"

                //property "sonar.sources", "src/main/java"

                //property "sonar.tests", "src/test/java"

                // Add other required properties here

            }

        }


Let me know any other details. Need to provide. Thanks

Hey there.

I think what you really want to do is apply sonar once to the root project of the hierarchy. This would mean your build.gradle looks more like this.

plugins {
    id 'org.sonarqube' version '7.0.1.6134' // Add SonarQube plugin at root level only
}

allprojects {
    group = 'com.sai.qgt'
    version = '1.0.0.0-SNAPSHOT'

    repositories {
        maven {
            url = project.uri("http://8.8.8.8/repository/private")
            allowInsecureProtocol = true

            metadataSources {
                mavenPom()
                artifact()
                ignoreGradleMetadataRedirection()
            }
        }
    }
}

subprojects {
    if (project.name != 'bom') {
        apply plugin: 'java-library'
        apply plugin: 'maven-publish'
        apply plugin: 'jacoco'
        // REMOVED: apply plugin: 'org.sonarqube' - no longer needed in subprojects
    }
}

// Configure SonarQube once at root level
sonar {
    properties {
        property "sonar.host.url", "https://sonar.sai.com"
        property "sonar.projectKey", "sai.qgt.app-gradle"
        property "sonar.projectName", "sai-qgt.app-gradle"
        property "sonar.token", "sai_12345672abcdef50a62"
    }
}

// Explicitly skip the BOM project
project(":bom") {
    sonar {
        skipProject = true
    }
}

The way you have it setup now runs analysis for each module individually with the same project key, and then sends it to SonarQube rewriting the previous analysis.

Hi Colin,

Thank you.

”The way you have it setup now runs analysis for each module individually with the same project key, and then sends it to SonarQube rewriting the previous analysis.”

Yes it was running analysis for each module. But, if a particular module task is failed the build is getting failed. The build is getting failed when there is no source file present in the module. So have modified the build.gradle in such a way is there is no source file skip that module and run analysis for the remaining modules. Please let me know if the configuration related to sonar is correctly mentioned in the build.gradle file. Any changes need to do in the build.gradle best practices. Any suggestions please let me know…

Thanks ….

plugins {

    // Declare the SonarQube plugin here but don't apply it automatically.

    // This makes the plugin available to all subprojects using the same version,

    // while allowing us to selectively apply it only to relevant modules (e.g., exclude 'bom' or root).

    id 'org.sonarqube' version '7.0.1.6134' apply false

}




allprojects {

    group = 'com.sai.http'

    version = '1.0.0.0-SNAPSHOT'




    repositories {

        maven {

            url = project.uri("http://8.8.8.8/repository/private")

            allowInsecureProtocol = true




            metadataSources {

                mavenPom()

                artifact()

                ignoreGradleMetadataRedirection()

            }

        }

    }

}




subprojects { subproject ->

    def javaSrcDir = new File(subproject.projectDir, "src/main/java")

    def testSrcDir = new File(subproject.projectDir, "src/test/java")

    def hasSources = javaSrcDir.exists() || testSrcDir.exists()




    if (subproject.name != 'bom' && hasSources) {

            println "Configuring ${subproject.name}"

            subproject.apply plugin: 'org.sonarqube'




            subproject.sonarqube {

                properties {

                    property "sonar.host.url", "https://sonar.sai.com"

                    property "sonar.projectKey", "sai.qet.app-gradle"

                    property "sonar.projectName", "sai-qet.app-gradle"

                    property "sonar.token", "sai_123456gegccbcburs"

                    property "sonar.sources", "src/main/java"

                    property "sonar.tests", "src/test/java"

                

                }

            }

        }




    if (subproject.name != 'bom') {

        println "Configuring ${subproject.name}"




        subproject.apply plugin: 'java-library'

        subproject.apply plugin: 'maven-publish'

        subproject.apply plugin: 'jacoco'

You really need to be running the Gradle plugin on the root hierarchy, and using skipProject for projects that should be skipped.

// Explicitly skip the BOM project
project(":bom") {
    sonar {
        skipProject = true
    }
}

You can probably work in your if (hasSources) to do this programatically.

// Programmatically skip projects without sources
subprojects { subproject ->
    def javaSrcDir = new File(subproject.projectDir, "src/main/java")
    def testSrcDir = new File(subproject.projectDir, "src/test/java")
    def hasSources = javaSrcDir.exists() || testSrcDir.exists()
    
    if (!hasSources || subproject.name == 'bom') {
        subproject.sonar {
            skipProject = true
        }
    }
}

(I have not tested this, it’s just an example)

No need to make it more complicated than that. :slight_smile:

Hi Colin,

Thanks.
Now the build is getting success in local. Sonarscan was analysing the modules that contains both the src/main/java and src/test/java.

But while checking the reports in sonarqube dashboard it is not as expected. Only for one module I can able to see the reports. Under the project → code → only one module results were showing. And also it was not displaying the module name, there was an src folder inside src folder (we can see the module name) there is folder related to that module.

I am missing anything in the configuration part in the build.gradle file. I want the module name should be seen once i go into the project in the sonarqube. There will be multiple modules. The structure which is in localshould be like that in the sonarqube also. There was one maven sonarbuild which will use pom.xml file for the project all the modules names will be present and inside that module we can see what it has scanned. It will be in the structured format.

Eg: project → Code → module 1, module 2, module 3, module 4, etc…
inside module 1 → plugin → submodules → src/main/java or src/test/java

I mean whatever in the svn repo structure it will be same in the maven gradle project.

Will gradle sonar got failed if a particular module doesn’t contain either src/main/java or src/test/java one of them? I have seen in maven buils it was skipped but in the gradle it was failing.

So i have used this configuration if the subproject contains both main and test run the scan …

subprojects { subproject →

def javaSrcDir = new File(subproject.projectDir, "src/main/java")

def testSrcDir = new File(subproject.projectDir, "src/test/java")

def hasSources = javaSrcDir.exists() && testSrcDir.exists()

Before this i have used or (||) operation it was also getting failed so that i have used &&.

def hasSources = javaSrcDir.exists() || testSrcDir.exists().

This is my configuration. Can you help me on this whether anything need to change to get correct results publish to sonarqube.

plugins {

    // Declare the SonarQube plugin here but don't apply it automatically.

    // This makes the plugin available to all subprojects using the same version,

    // while allowing us to selectively apply it only to relevant modules (e.g., exclude 'bom' or root).

    id 'org.sonarqube' version '7.0.1.6134' apply false

}




allprojects {

    group = 'com.sai.egn'

    version = '1.0.0.0-SNAPSHOT'




    repositories {

        maven {

            url = project.uri("http://8.8.8.8/repository/private")

            allowInsecureProtocol = true




            metadataSources {

                mavenPom()

                artifact()

                ignoreGradleMetadataRedirection()

            }

        }

    }

}




subprojects { subproject ->

    def javaSrcDir = new File(subproject.projectDir, "src/main/java")

    def testSrcDir = new File(subproject.projectDir, "src/test/java")

    def hasSources = javaSrcDir.exists() && testSrcDir.exists()

    println "Evaluating ${subproject.name}   +   hasSources=${hasSources}"

    if (subproject.name != 'bom' && hasSources) {

            println "Configuring ${subproject.name}"

            subproject.apply plugin: 'org.sonarqube'




            subproject.sonarqube {

                properties {

                    property "sonar.host.url", "https://sonar.sai.com"

                    property "sonar.projectKey", "sai.dft.app-gradle"

                    property "sonar.projectName", "sai-dft.app-gradle"

                    property "sonar.token", "sqp_123456789987654321"

                    property "sonar.sources", "src/main/java"

                    property "sonar.tests", "src/test/java"

                    property "sonar.scm.disabled", "true"

                }

            }

        }




    if (subproject.name != 'bom') {

        println "Configuring ${subproject.name}"




        subproject.apply plugin: 'java-library'

        subproject.apply plugin: 'maven-publish'

        subproject.apply plugin: 'jacoco'

Build is getting pass in local and results were not showing for all the modules. only one module it was showing.

Do I need to specify anything how the analysis will look in the sonarqube dashboard. In a structured format how the svn is having or maven sonar is having.

Could you please help me on this. Thanks

You’re still running analysis on each subproject individually. You want the gradle task (sonar) applied at the root of the hierarchy, and it should run exactly once. Just like in my example from earlier:

// Configure SonarQube once at root level
sonar {
    properties {
        property "sonar.host.url", "https://sonar.sai.com"
        property "sonar.projectKey", "sai.qgt.app-gradle"
        property "sonar.projectName", "sai-qgt.app-gradle"
        property "sonar.token", "sai_12345672abcdef50a62"
    }
}

// Programmatically skip projects without sources
subprojects { subproject ->
    def javaSrcDir = new File(subproject.projectDir, "src/main/java")
    def testSrcDir = new File(subproject.projectDir, "src/test/java")
    def hasSources = javaSrcDir.exists() || testSrcDir.exists()
    
    if (!hasSources || subproject.name == 'bom') {
        subproject.sonar {
            skipProject = true
        }
    }
}

Hi Colin,

I understand now. Sorry, I might have overlooked this earlier.

Now I placed the sonarqube properties in top-level outside subproject block.
While running the sonar scan using “gradle sonarqube –info” command the build was failing. in the build.gradle file there was a plugin block where i have defined the sonarqube plugin. If i remove that apply false the build is getting passed but the results were not publishing to the sonarqube.

If the sonar properties was inside the subprojects the results were publishing to sonarqube but it get overwriten by the last subproject sonar task. I expect to see each task, upload their results under the same Sonarqube project but in a separate module/folder.

There was one job which runs sonarscan for the same project but that project is maven related all the modules will have pom.xml and a parent pom at root level. And there we are using one project key. All the modules are publishing in a single sonarqube project.

Will this be achievable in gradle project aswell? Else do we need to have a one project per module in the sonar interface.

And also for sonar analysis jacoco plugin also should be mentioned in the build.gradle file correct? I was using this line under sonar property is it enough or need to add anything more related to jacoco. like appllying the jacoco plugin in root level under plugin block……

property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/reports/jacoco/rootJacocoReport.xml"
**
`plugins {

id 'org.sonarqube' version '7.0.1.6134' apply false

}`
**

plugins {

    id 'org.sonarqube' version '7.0.1.6134' apply false

}




allprojects {

    group = 'com.sai.dft'

    version = '1.0.0.0-SNAPSHOT'




    repositories {

        maven {

            url = project.uri("http://8.8.8.8/repository/private")

            allowInsecureProtocol = true




            metadataSources {

                mavenPom()

                artifact()

                ignoreGradleMetadataRedirection()

            }

        }

    }

}

sonarqube {

    properties {

        property "sonar.host.url", "https://sonar.sai.com"

        property "sonar.projectKey", "sai.dft.app-gradle"

        property "sonar.projectName", "sai-dft.app-gradle"

        property "sonar.token", "sqp_123456789987654321"

        property "sonar.scm.disabled", "true"

        property "sonar.projectBaseDir", rootDir

        property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/reports/jacoco/rootJacocoReport.xml"

        // property "sonar.sources", "src/main/java"

        // property "sonar.tests", "src/test/java"

        // property "sonar.projectVersion", "1.0"

        // Make each subproject appear as a separate module/folder

        // property "sonar.modules", subprojects.collect { it.name }.join(',')  

    }

}



subprojects { subproject ->

    def javaSrcDir = new File(subproject.projectDir, "src/main/java")

    def testSrcDir = new File(subproject.projectDir, "src/test/java")

    def hasSources = javaSrcDir.exists() && testSrcDir.exists()

    println "Evaluating ${subproject.name}   +   hasSources=${hasSources}"

    if (subproject.name != 'bom' && hasSources) {

            println "Configuring ${subproject.name}"

            subproject.apply plugin: 'org.sonarqube'

       

    }




    if (subproject.name != 'bom') {

        println "Configuring ${subproject.name}"




        subproject.apply plugin: 'java-library'

        subproject.apply plugin: 'maven-publish'

        subproject.apply plugin: 'jacoco'

Can you please help me on this if we can achieve, to see each task, upload their results under the same Sonarqube project but in a separate module/folder.

Or if not, what will be the next approach.

Thank you

What was the failure?