Analysing Gradle Java project with Sonarqube in Jenkins pipeline cannot execute Jacoco reports properly

Versions:
SonarQube: 7.9
SonarJava plugin: 5.13.1
Java: 11
Gradle: 5.5

I’m trying to make SonarQube analysis of Gitlab Repo with Gradle/Java project using declarative Jenkins Pipeline.
gradle and jdk are from Docker Image.

This is the JenkinsFile:

@Library('jenkins-shared')_
pipeline {
    agent {
        docker {
            image 'gradle:5.5-jdk11'
        }
    }
    stages {
        stage('build && SonarQube analysis') {
            steps {
                withSonarQubeEnv('sonar.tools.****) {
                 script {
                     cmd.withNexusCredentials {
                            sh 'gradle --info sonarqube  -Dsonar.projectKey=catalog-service -Dsonar.junit.reportPaths=./build/test-results/test -Dsonar.binaries=./build/classes -Dsonar.coverage.jacoco.xmlReportPaths=./build/reports/jacoco/test/html/index.html'
                        }
                }
            }
        }
    }
        stage("Quality Gate") {
            steps {
                timeout(time: 1, unit: 'HOURS') {
                    // Parameter indicates whether to set pipeline to UNSTABLE if Quality Gate fails
                    // true = set pipeline to UNSTABLE, false = don't
                    // Requires SonarScanner for Jenkins 2.7+
                    waitForQualityGate abortPipeline: true
                }
            }
        }
    }
}

build.gradle configs:
service.parent.api:

buildscript {

    ext {
        springBootVersion = '2.1.4.RELEASE'
        springDependency = '1.0.7.RELEASE'
        lombokPlugin = '3.5.1'
		sonarPlugin = '2.7.1'
        buildTime = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date())
    }
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
        classpath "io.spring.gradle:dependency-management-plugin:${springDependency}"
        classpath "io.freefair.gradle:lombok-plugin:${lombokPlugin}"
		classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:${sonarPlugin}"
    }

}

allprojects {
   apply plugin: 'java'
   apply plugin: org.springframework.boot.gradle.plugin.SpringBootPlugin
   apply plugin: io.spring.gradle.dependencymanagement.DependencyManagementPlugin
   apply plugin: io.freefair.gradle.plugins.lombok.LombokPlugin
   apply plugin: 'jacoco'
   apply plugin: 'maven-publish'
   apply plugin: 'idea'
   apply plugin: org.sonarqube.gradle.SonarQubePlugin

    // java plugin settings
    sourceCompatibility = 11.0
    targetCompatibility = 11.0

    // default group for maven artifacts
    group = '***'

    ext {
        // dependency versions
        jacksonVersion = '2.9.8'
        swaggerVersion = '2.0.8'

        validationApiVersion = '2.0.1.Final'
        hibernateValidatorVersion = '6.0.17.Final'
        javaxElVersion = '3.0.1-b11'

        // test frameworks
        junitVersion = '5.4.2'
        assertjVersion = '3.12.1'
        mockitoVersion = '2.26.0'
        wireMockVersion = '2.23.2'

        // build verification
        jaCoCoVersion = '0.8.4'
    }

    //hack to fix IntelliJ plugin problem with spring boot plugin
    ext['junit-jupiter.version'] = junitVersion

    dependencies {
        // SpringBoot2 stuff
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter-log4j2'

        runtime 'org.springframework.boot:spring-boot-starter-tomcat'

        // Auto-mapper
        implementation 'org.modelmapper:modelmapper:2.3.0'

        // Include Jackson support for Java8 date types
        implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
        // Bean validation (JSR 310)
        implementation "javax.validation:validation-api:${validationApiVersion}"

        // Add javax.validation implementation
        implementation "org.hibernate.validator:hibernate-validator:${hibernateValidatorVersion}"
        implementation "org.glassfish:javax.el:${javaxElVersion}"

        // Core unit test libraries
        testImplementation "org.junit.jupiter:junit-jupiter:${junitVersion}"
        testImplementation "org.assertj:assertj-core:${assertjVersion}"
        testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"

        testImplementation "org.mockito:mockito-junit-jupiter:${mockitoVersion}"
        testImplementation "org.mockito:mockito-core:${mockitoVersion}"

        // Component tests libraries
        testImplementation 'org.springframework.boot:spring-boot-starter-test'

    }

    configurations {
        all {
            exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
        }
    }

    repositories {
        maven { url "***" }
        mavenCentral()
        mavenLocal()
    }

    afterEvaluate { project ->

        publishing {
         

        jacocoTestCoverageVerification {
            // exclude SpringBoot main class from coverage rules validation
            violationRules.rules.each { rule ->
                rule.setExcludes(["${springBoot.mainClassName}"] + rule.excludes)
            }
        }

    }

    test {
        useJUnitPlatform()
        // allow up to 4 parallel test runs
        if (project.hasProperty("maxParallelTests")) {
            maxParallelForks = maxParallelTests
        }
        // disable default Gradle test reports in favour to JaCoCo
        reports.html.enabled = false
        // make sure test report is updated upon test run completion
        finalizedBy jacocoTestReport
    }

    check {
        dependsOn jacocoTestCoverageVerification
    }

    jacoco {
        toolVersion = jaCoCoVersion
    }

    jacocoTestCoverageVerification {
        violationRules {
        rule {
            element = 'CLASS'
            limit {
                counter = 'LINE'
                value = 'COVEREDRATIO'
                minimum = 1.0
            }
        }
        rule {
            element = 'CLASS'
            limit {
                counter = 'BRANCH'
                value = 'COVEREDRATIO'
                minimum = 1.0
            }
        }
    }
}

}

When I try to run this Jenkins pipeline, the following error occurs:

> Task :sonarqube FAILED
JaCoCo report task detected, but XML report is not enabled or it was not produced. Coverage for this task will not be reported.
Caching disabled for task ':sonarqube' because:
  Build cache is disabled
Task ':sonarqube' is not up-to-date because:
  Task has not declared any outputs despite executing actions.
JaCoCo report task detected, but XML report is not enabled or it was not produced. Coverage for this task will not be reported.
User cache: ?/.sonar/cache
:sonarqube (Thread[Execution worker for ':',5,main]) completed. Took 0.221 secs.

Full Exception Stacktrace:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':sonarqube'.
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.accept(ExecuteActionsTaskExecuter.java:148)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.accept(ExecuteActionsTaskExecuter.java:145)
	at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:191)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:138)
	at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionStateTaskExecuter.execute(ResolveBeforeExecutionStateTaskExecuter.java:75)
	at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:108)
	at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionOutputsTaskExecuter.execute(ResolveBeforeExecutionOutputsTaskExecuter.java:67)
	at org.gradle.api.internal.tasks.execution.ResolveAfterPreviousExecutionStateTaskExecuter.execute(ResolveAfterPreviousExecutionStateTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:94)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:95)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:73)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:49)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:49)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:43)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:355)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:336)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:322)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:134)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:129)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:202)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:193)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:129)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: org.sonarsource.scanner.api.internal.ScannerException: Unable to execute SonarQube
	at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.lambda$createLauncher$0(IsolatedLauncherFactory.java:85)
	at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.createLauncher(IsolatedLauncherFactory.java:74)
	at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.createLauncher(IsolatedLauncherFactory.java:70)
	at org.sonarsource.scanner.api.EmbeddedScanner.doStart(EmbeddedScanner.java:181)
	at org.sonarsource.scanner.api.EmbeddedScanner.start(EmbeddedScanner.java:122)
	at org.sonarqube.gradle.SonarQubeTask.run(SonarQubeTask.java:99)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:103)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:48)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:41)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
	at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:702)
	at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:669)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$5.run(ExecuteActionsTaskExecuter.java:401)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92)
	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:390)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:373)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$200(ExecuteActionsTaskExecuter.java:79)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:210)
	at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$1(ExecuteStep.java:33)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:33)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:58)
	at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:35)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:33)
	at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:39)
	at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
	at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
	at org.gradle.internal.execution.steps.CatchExceptionStep.execute(CatchExceptionStep.java:35)
	at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:45)
	at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:31)
	at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:201)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:70)
	at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:45)
	at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:49)
	at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:43)
	at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:32)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:96)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:89)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:54)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:77)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:90)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:48)
	at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:117)
	... 35 more
Caused by: java.lang.IllegalStateException: Fail to create temp file in ?/.sonar/cache/_tmp
	at org.sonarsource.scanner.api.internal.cache.FileCache.newTempFile(FileCache.java:138)
	at org.sonarsource.scanner.api.internal.cache.FileCache.get(FileCache.java:83)
	at org.sonarsource.scanner.api.internal.JarDownloader.lambda$getScannerEngineFiles$0(JarDownloader.java:60)
	at org.sonarsource.scanner.api.internal.JarDownloader.getScannerEngineFiles(JarDownloader.java:61)
	at org.sonarsource.scanner.api.internal.JarDownloader.download(JarDownloader.java:53)
	at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.lambda$createLauncher$0(IsolatedLauncherFactory.java:76)
	... 95 more
Caused by: java.nio.file.NoSuchFileException: ?/.sonar/cache/_tmp/fileCache13115931649191674401.tmp
	at org.sonarsource.scanner.api.internal.cache.FileCache.newTempFile(FileCache.java:136)
	... 100 more

Every other task completes successfully. Even when I run jacocoTestConverageVerification or check, it always runs successfully except the task Sonarqube.

hello @Patrik_Polacek,

I think the problem is that gradle fails to create temporary directory, you can see it in the stacktrace

Caused by: java.lang.IllegalStateException: Fail to create temp file in ?/.sonar/cache/_tmp

Are the filesystem privileges correct? You can change the location of the working directory using sonar.working.directory property if needed.

Another issue (but this is not causing the failure) is that you are passing html JaCoCo report. You should use XML format instead.

Thank you. Is there easy way how to generate reports from jacoco in xml format instead of html ? I have fixed the error with privileges, but test coverage isn’t showing within Sonarqube. Currently, I cannot find xml reports, only html ones.

Yes, you can configure jacocoTestReport task like this


    jacocoTestReport {
        reports {
            xml.enabled true
            csv.enabled false
            html.enabled false
        }
    }

See more in JaCoCo plugin doc https://docs.gradle.org/current/userguide/jacoco_plugin.html