diff --git a/build.gradle.kts b/build.gradle.kts index 9b21b01b..60ca4e8d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,6 +33,7 @@ plugins { id("org.jetbrains.intellij.platform") version "2.19.0" id("org.jetbrains.grammarkit") version "2023.3.0.4" id("checkstyle") + id("jacoco") id("com.avast.gradle.docker-compose") version "0.17.21" id("org.jetbrains.kotlin.jvm") version "2.4.21" id("idea") @@ -147,6 +148,26 @@ tasks { // Forward the experimental grammar-engine flag so CI can run the whole suite twice: once on the // original engine and once with -Dsystemd.unit.grammarParseEngine=true (see GrammarOptionValue). systemProperty("systemd.unit.grammarParseEngine", System.getProperty("systemd.unit.grammarParseEngine", "false")) + // Coverage for CI trends. The IntelliJ test framework loads classes through its own class loaders, which + // JaCoCo only records with includeNoLocationClasses; jdk.internal is excluded because instrumenting it + // breaks the JVM. + configure { + isIncludeNoLocationClasses = true + excludes = listOf("jdk.internal.*") + } + } + + jacocoTestReport { + // Only reports on existing execution data (run `test` first); CI publishes the XML with the Coverage plugin. + reports { + xml.required = true + html.required = true + csv.required = false + } + // Generated lexer/parser/PSI code would only dilute the numbers. + classDirectories.setFrom(files(classDirectories.files.map { + fileTree(it) { exclude("**/generated/**", "**/psi/impl/**") } + })) } } diff --git a/ci/release.Jenkinsfile b/ci/release.Jenkinsfile index 0e168df8..c98ae7ca 100644 --- a/ci/release.Jenkinsfile +++ b/ci/release.Jenkinsfile @@ -414,7 +414,7 @@ pipeline { sh(""" mkdir -p ./build ./generate-changelog > build/CHANGELOG - ./gradlew --no-daemon -I ./build-cache-init.gradle.kts -I ./repo-cache-init.gradle.kts --build-cache build buildPlugin -PbuildScan + ./gradlew --no-daemon -I ./build-cache-init.gradle.kts -I ./repo-cache-init.gradle.kts --build-cache build buildPlugin jacocoTestReport -PbuildScan """) script { if (env.BRANCH_NAME ==~ /^([0-9][0-9][0-9]\.x)$/) { @@ -452,6 +452,22 @@ pipeline { archiveArtifacts artifacts: 'build/reports/**' } } + } + post { + // Runs even when tests fail, so failing tests and coverage still land in the trends. + always { + junit testResults: 'build/test-results/test/*.xml', allowEmptyResults: true + // Coverage is informational: a reporting problem marks the build unstable rather than failing it + // (and blocking the release). + catchError(buildResult: 'UNSTABLE', stageResult: 'UNSTABLE') { + script { + if (fileExists('build/reports/jacoco/test/jacocoTestReport.xml')) { + recordCoverage(tools: [[parser: 'JACOCO', pattern: 'build/reports/jacoco/test/jacocoTestReport.xml']], + sourceDirectories: [[path: 'src/main/kotlin'], [path: 'src/main/java']]) + } + } + } + } } } stage("Unit Tests (new grammar engine)") { @@ -472,6 +488,11 @@ pipeline { ./gradlew --no-daemon -I ./build-cache-init.gradle.kts -I ./repo-cache-init.gradle.kts --build-cache test -Dsystemd.unit.grammarParseEngine=true """) } + post { + always { + junit testResults: 'build/test-results/test/*.xml', allowEmptyResults: true + } + } } } }