This Gradle plugin transforms XML reports produced by tools such as SpotBugs and Checkstyle into JSON in the format expected by GitLab, so that findings can be shown in the merge request code quality widget.
The plugin only reads XML produced by other tools. Configure the SpotBugs and/or Checkstyle Gradle plugins (or any setup that writes compatible XML) so reports exist before check runs.
Default input locations match the layout used by the official Gradle plugins: build/reports/spotbugs/main.xml and build/reports/checkstyle/main.xml. The SpotBugs Gradle plugin only emits XML when the XML report is explicitly enabled, so make sure your build does that:
spotbugs {
// ...
}
tasks.named<com.github.spotbugs.snom.SpotBugsTask>("spotbugsMain") {
reports.create("xml") { required.set(true) }
}If your reports live elsewhere, override the generateGitLabCodeQualityReport task properties (see Advanced configuration).
The plugin attaches to any project that has a JVM toolchain plugin applied — java, java-library, application, org.jetbrains.kotlin.jvm, etc. Add this plugin to your build.gradle.kts (or build.gradle):
plugins {
java
id("io.github.dnalchemist.gitlab-code-quality") version "1.1.0"
}By default the plugin reads:
-
build/reports/spotbugs/main.xml -
build/reports/checkstyle/main.xml
and writes:
-
build/gl-code-quality-report.json
when the check lifecycle runs (the generateGitLabCodeQualityReport task is attached to check).
If the XML files are missing or empty, the task still completes and logs that no report was found.
|
Note
|
build/gl-code-quality-report.json is always written, including when no findings are detected. In that case its content is an empty JSON array []. This keeps GitLab CI’s reports:codequality artifact pattern stable across runs — it does not fail an MR with "artifact not found" just because the build was clean. If you prefer "no file = no findings" semantics, delete the file in a CI step when the array is empty.
|
If you do not want the report task wired into check — for example when spotbugsMain runs with ignoreFailures = false and you want the GitLab JSON to be produced even when SpotBugs reports a failure — disable the auto-wiring and run the task explicitly:
gitlabCodeQuality {
wireIntoCheck.set(false)
}Then call ./gradlew check generateGitLabCodeQualityReport (or run the task in your CI step that always executes, regardless of check outcome).
All options are properties on the generateGitLabCodeQualityReport task. Example:
import io.github.dnalchemist.gitlab.codequality.GenerateGitLabCodeQualityReportTask
tasks.named<GenerateGitLabCodeQualityReportTask>("generateGitLabCodeQualityReport") {
spotbugsEnabled.set(true)
spotbugsInputFile.set(layout.buildDirectory.file("reports/spotbugs/main.xml"))
checkstyleEnabled.set(true)
checkstyleInputFile.set(layout.buildDirectory.file("reports/checkstyle/main.xml"))
outputFile.set(layout.buildDirectory.file("gl-code-quality-report.json"))
}The plugin looks up source directories for SpotBugs path resolution from sourceSets.main.java.srcDirs. That works on plain java / java-library / org.jetbrains.kotlin.jvm setups, but Android (com.android.application, com.android.library) and Kotlin Multiplatform projects do not register a main source set on JavaPluginExtension. In that case set sourceRoots explicitly so SpotBugs paths can still be resolved relative to the git root:
tasks.named<GenerateGitLabCodeQualityReportTask>("generateGitLabCodeQualityReport") {
// Android
sourceRoots.setFrom(file("src/main/java"), file("src/main/kotlin"))
// Or Kotlin Multiplatform — pick the source sets whose findings you want resolved
// sourceRoots.setFrom(
// kotlin.sourceSets.getByName("commonMain").kotlin.srcDirs,
// kotlin.sourceSets.getByName("jvmMain").kotlin.srcDirs,
// )
}Use setFrom(...) to replace the auto-detected default; from(...) would just append.
If sourceRoots resolves to an empty list, the SpotBugs portion of the report falls back to the raw sourcepath from the XML — fingerprints stay valid, but file paths in the GitLab widget will not be relative to the repo root.
Apply the plugin in subprojects that run SpotBugs/Checkstyle. Each project produces its own JSON file under its build/ directory.
GitLab accepts one code quality file per job (see this issue). Merge reports with jq, for example:
build:
stage: build
image: ...
before_script:
- apt-get update && apt-get install -y jq
script:
- ./gradlew check
after_script:
- find . -name gl-code-quality-report.json -print0 | xargs -0 cat | jq -s "add" > merged-gl-code-quality-report.json
artifacts:
reports:
codequality:
- merged-gl-code-quality-report.jsonSnapshots are published to the Sonatype Central Portal snapshots repository. Add that repository for plugin resolution in settings.gradle.kts, then apply the snapshot version in your build script:
// settings.gradle.kts
pluginManagement {
repositories {
gradlePluginPortal()
maven {
url = uri("https://central.sonatype.com/repository/maven-snapshots/")
mavenContent { snapshotsOnly() }
}
}
}// build.gradle.kts
plugins {
java
id("io.github.dnalchemist.gitlab-code-quality") version "1.2.0-SNAPSHOT"
}