mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 11:23:10 +02:00
Add CI coverage summaries and aggregate JaCoCo report (#6451)
This commit is contained in:
+125
-1
@@ -438,7 +438,7 @@ subprojects {
|
||||
}
|
||||
|
||||
tasks.named("bootRun") {
|
||||
jvmArgs = [
|
||||
def runtimeArgs = [
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:MaxGCPauseMillis=200",
|
||||
"-XX:G1HeapRegionSize=4m",
|
||||
@@ -447,6 +447,53 @@ subprojects {
|
||||
"-XX:+UseCompactObjectHeaders",
|
||||
"--enable-native-access=ALL-UNNAMED"
|
||||
]
|
||||
|
||||
// Optional JaCoCo agent for e2e/cucumber backend coverage.
|
||||
//
|
||||
// Enabled with `-PjacocoAgent=true`. The default destfile lives
|
||||
// outside the source tree so it doesn't poison a normal bootRun
|
||||
// for a developer who forgot to pass the property. Override
|
||||
// both with `-PjacocoExec=/path/to.exec` if you need a custom
|
||||
// location (e.g. when sharing it with the Playwright runner).
|
||||
if (rootProject.hasProperty('jacocoAgent') &&
|
||||
rootProject.property('jacocoAgent').toString() == 'true') {
|
||||
def agentJar = rootProject.layout.buildDirectory
|
||||
.file('jacoco/jacocoagent.jar').get().asFile.absolutePath
|
||||
def execFile = (rootProject.findProperty('jacocoExec') ?:
|
||||
rootProject.layout.projectDirectory
|
||||
.file('.test-state/playwright/jacoco.exec').asFile.absolutePath
|
||||
).toString()
|
||||
// The JaCoCo agent argument is a comma-separated key=value list,
|
||||
// so a path that itself contains ',' or '=' would smuggle extra
|
||||
// agent options (e.g. -PjacocoExec='out.exec,sessionid=evil').
|
||||
// Today the value only comes from our own CI workflows, but
|
||||
// validating defensively is cheap and silences Aikido.
|
||||
//
|
||||
// Control characters are checked via String.contains rather
|
||||
// than inside a slashy regex character class - a literal NULL
|
||||
// accidentally landing in the regex killed Groovy parsing on
|
||||
// the previous attempt.
|
||||
def hasBadChar = execFile.find(/[,= ]/) != null ||
|
||||
execFile.contains('\r') ||
|
||||
execFile.contains('\n') ||
|
||||
execFile.contains('\t')
|
||||
if (hasBadChar) {
|
||||
throw new GradleException(
|
||||
"jacocoExec='" + execFile + "' contains characters " +
|
||||
"(',', '=', whitespace, or control chars) that " +
|
||||
"would break -javaagent option parsing. Choose " +
|
||||
"a different path."
|
||||
)
|
||||
}
|
||||
runtimeArgs.add("-javaagent:${agentJar}=destfile=${execFile},output=file,append=false,dumponexit=true")
|
||||
dependsOn(rootProject.tasks.named('copyJacocoAgent'))
|
||||
doFirst {
|
||||
new File(execFile).parentFile?.mkdirs()
|
||||
logger.lifecycle("JaCoCo agent attached: ${execFile}")
|
||||
}
|
||||
}
|
||||
|
||||
jvmArgs = runtimeArgs
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -627,3 +674,80 @@ tasks.withType(Test).configureEach {
|
||||
// Half of available CPUs is a safe default; bump if your tests are I/O-bound.
|
||||
maxParallelForks = Math.max(1, (Runtime.runtime.availableProcessors().intdiv(2)) as int)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// JaCoCo helpers used by CI for cucumber + Playwright (live backend) coverage.
|
||||
//
|
||||
// These let CI attach the JaCoCo agent to a running Spring Boot process
|
||||
// (gradle bootRun or the docker image, via JAVA_TOOL_OPTIONS) and then turn
|
||||
// the resulting .exec dump back into HTML + XML reports without anyone
|
||||
// hand-installing the JaCoCo CLI.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
configurations {
|
||||
jacocoRuntimeAgent
|
||||
jacocoCli
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// The :runtime classifier on org.jacoco.agent IS the agent jar - no
|
||||
// unzipping required. Kept on the version the plugin already picks so
|
||||
// agent + reporter line up exactly.
|
||||
jacocoRuntimeAgent "org.jacoco:org.jacoco.agent:${jacoco.toolVersion}:runtime"
|
||||
jacocoCli "org.jacoco:org.jacoco.cli:${jacoco.toolVersion}"
|
||||
}
|
||||
|
||||
tasks.register('copyJacocoAgent', Copy) {
|
||||
group = 'verification'
|
||||
description = 'Copies the JaCoCo runtime agent jar to build/jacoco/jacocoagent.jar.'
|
||||
from configurations.jacocoRuntimeAgent
|
||||
into layout.buildDirectory.dir('jacoco')
|
||||
rename { 'jacocoagent.jar' }
|
||||
}
|
||||
|
||||
// Aggregates an externally-produced .exec (e.g. from e2e:live or the cucumber
|
||||
// docker container) against this project's compiled classes + sources.
|
||||
//
|
||||
// Inputs are configured via -P properties so the same task works for every
|
||||
// caller:
|
||||
//
|
||||
// ./gradlew jacocoReportFromExec -PexecFile=.test-state/playwright/jacoco.exec \
|
||||
// -PreportDir=build/reports/jacoco/e2e-live
|
||||
tasks.register('jacocoReportFromExec', JacocoReport) {
|
||||
group = 'verification'
|
||||
description = 'Generates a JaCoCo HTML+XML report from an externally captured .exec.'
|
||||
|
||||
def execProp = project.findProperty('execFile') ?: project.findProperty('execFiles')
|
||||
def reportProp = project.findProperty('reportDir') ?: "build/reports/jacoco/external"
|
||||
|
||||
executionData fileTree(rootProject.rootDir) {
|
||||
if (execProp) {
|
||||
include execProp.toString().split(',').collect { it.trim() }
|
||||
} else {
|
||||
// Sensible defaults so the task is usable without props.
|
||||
include '.test-state/**/*.exec'
|
||||
include 'coverage-tools/exec/*.exec'
|
||||
include 'testing/cucumber-coverage/*.exec'
|
||||
}
|
||||
}
|
||||
|
||||
// Pull compiled classes + sources from every subproject so the report is
|
||||
// an aggregate. JaCoCo silently skips classes that have no matching .exec
|
||||
// probes, so this is safe even when only a subset of code was exercised.
|
||||
classDirectories.setFrom(files(subprojects.collect { sub ->
|
||||
sub.fileTree(dir: "${sub.buildDir}/classes/java/main", excludes: [
|
||||
'**/generated/**',
|
||||
])
|
||||
}))
|
||||
sourceDirectories.setFrom(files(subprojects.collect { sub ->
|
||||
"${sub.projectDir}/src/main/java"
|
||||
}))
|
||||
|
||||
reports {
|
||||
xml.required.set(true)
|
||||
html.required.set(true)
|
||||
csv.required.set(false)
|
||||
xml.outputLocation.set(layout.projectDirectory.file("${reportProp}/jacocoTestReport.xml"))
|
||||
html.outputLocation.set(layout.projectDirectory.dir("${reportProp}/html"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user