After upgrading from SonarQube 4.0 to 4.5.1 sonar runner is reporting a missing source set directory

I’m using Gradle 2.2 (upgraded from Gradle 2.1) + sonar runner 2.3 (also tried with 2.4).

10:18:51.263 ERROR - Invalid value of sonar.tests for artifactinfo-web
INFO: ------------------------------------------------------------------------
INFO: EXECUTION FAILURE
INFO: ------------------------------------------------------------------------
Total time: 4.533s
Final Memory: 18M/582M
INFO: ------------------------------------------------------------------------
ERROR: Error during Sonar runner execution
ERROR: Unable to execute Sonar
ERROR: Caused by: The folder '/projecti/artifactinfo-web/src/componentTest/resources' does not exist for 'artifactinfo-web' (base directory = /project/artifactinfo-web)

The project uses a custom source set configured as shown below. For diagnosing I have already added a condition that only adds the folder when it really exists (which I didn’t have with Sonar 4.0). But still sonar runner complains about the directory.

subprojects {
    configurations {
        componentTestCompile.extendsFrom compile, testCompile
        componentTestRuntime.extendsFrom runtime, testRuntime, componentTestCompile
    }
      sourceSets {
        componentTest {
            java {
                srcDir 'src/componentTest/java'
            }
            groovy {
                srcDir 'src/componentTest/groovy'
            }
            def dir=new File(project.projectDir, 'src/componentTest/resources')
            println "$dir exists " + dir.exists()
            if (dir.exists()) {
                resources {
                    srcDir 'src/componentTest/resources'
                }
                println "Added " + dir
            }
            compileClasspath = sourceSets.main.output + configurations.componentTestCompile + sourceSets.sharedTest.output
            runtimeClasspath = output + compileClasspath + configurations.componentTestRuntime
        }
    }
      task componentTest(type: Test) {
        testClassesDir = sourceSets.componentTest.output.classesDir
        classpath = sourceSets.componentTest.runtimeClasspath
        jvmArgs += "-Dlogback.configurationFile=$logbackUri"
    }
      task commitStageComponentTest(type: Test) {
        testClassesDir = componentTest.testClassesDir
        classpath = componentTest.classpath
        useJUnit {
            includeCategories 'at.softwarecraftsmen.common.test.buildpipeline.CommitStage'
        }
        jvmArgs += "-Dlogback.configurationFile=$logbackUri"
    }
      dependencies {
        // add the CommitStage marker interface for the build pipeline test execution
        componentTestCompile project(':common-test')
    }
      check.dependsOn componentTest
      idea {
        module {
            //and some extra test source dirs
            testSourceDirs += file('src/componentTest/java')
            testSourceDirs += file('src/componentTest/groovy')
            testSourceDirs += file('src/componentTest/resources')
            // put additional dependencies on the classpath
            scopes.TEST.plus += [configurations.componentTestCompile]
            scopes.TEST.plus += [configurations.componentTestRuntime]
        }
    }
}

Also, sourceSets.componentTest.allSource.srcDirs is including the directory breaking sonar runner later.

subprojects {
    sonarRunner {
        sonarProperties {
            property 'sonar.sourceEncoding', 'UTF-8'
              println project.name + ":" + sourceSets.componentTest.allSource.srcDirs
              properties["sonar.tests"] += sourceSets.componentTest.allSource.srcDirs
            properties["sonar.tests"] += sourceSets.integrationTest.allSource.srcDirs
            properties["sonar.jacoco.reportPath"] = "$buildDir/jacoco/test.exec"
            properties["sonar.jacoco.itReportPath"] = "$buildDir/jacoco/integrationTest.exec"
            // In order to get cross-module coverage, each module has to write coverage to the same file and the option "reuseReports has to be used!
            //properties["sonar.dynamicAnalysis"] = "reuseReports"
              //Unfortunately the reportsPath property only takes a single path. So we can only get unit test results here
            property 'sonar.junit.reportsPath', test.reports.junitXml.destination
        }
    }
}

The question is, why does the directory appear when added to sonar.tests?

Reading the gradle sonar runner documentation it appears that it is not the responsibility of the runner to make sure only existing directories are added. Obviously earlier versions of the runner were not so strict about non-existing directories. I have added the following to the runner configuration:

properties["sonar.tests"] += sourceSets.componentTest.allSource.srcDirs.findAll { it.exists() }
properties["sonar.tests"] += sourceSets.integTest.allSource.srcDirs.findAll { it.exists() }

worked for me.

Than ks