Publishing detekt reports to Gitlab

In my previous posts on code quality, I wrote about my experience on how we could set up detekt to get code quality reports on Android projects and about my danger-detekt-kotlin plugin to deliver violations to the developers in merge request comments. Actually, there's almost nothing that is Android specific, so they could be used as a guide to implement such things in any Kotlin projects with Gradle.

In this post, we will talk about GitLab. We use GitLab as our main platform to store git repositories and CI/CD. While implementing CI we added detekt so each merge request code is analyzed using well-defined rules. It's used to keep our code quality within acceptable boundaries as we prohibit introducing new violations in new MRs. In the end, it produces a code quality report.

But how to work with this report? Of course, any violation found is the reason to break the pipeline. But how to say developer what went wrong? We don't want our developers to checkout and run the same checks on their local machines, right?

Danger

Danger (danger-kotlin in particular) is a multi-purpose thing. It's just a utility, which can comment in Merge Requests. This is a pro and con at the same moment. We limited by comment format, but we are really flexible in terms of configuration. I've already written steps to set up Danger in my previous posts, so you could find them there. Let's not repeat ourselves. What are the alternatives?

Code Quality Reports

GitLab supports code quality reports in Code Climate format out-of-box. Unfortunately, there are no other formats supported. There's the 3 years old issue about adding SARIF support, so there's hope, but no options now. In theory, this is the most convenient option because it may have nice integrations with the platform. Here's GitLab documentation on this topic. Keep in mind its sub-features availability depends on the pricing tier. Gitlab has Free < Premium < Ultimate tiers. Let's see what features they may offer.

Features

Code Quality Widget

Available for everyone on the Free tier.

Here is the widget which is shown in Merge Requests below the description on pipeline complete.

Code Quality

Available for everyone if your tier is the Premium at least.

GitLab has a separate page for pipeline details, doesn't matter if the pipeline is started from Merge Request or not. So this feature is about the tab Code Quality on this pipeline page. It's pretty much the same as Widget, but for any pipeline.

Code Quality in diff view

Available for the Ultimate tier only.

Now that's what we talking about. Code quality violations could be shown inline in the Merge Request diff view, right below the line where it's found.

Options

Custom Detekt reporter

There is GitLab Report Detekt Plugin which implements a custom Code Climate reporter right from detekt. You could use it in detekt configuration like that.

repositories {
    maven(url = "https://gitlab.com/api/v4/projects/25796063/packages/maven")
}

dependencies {
    detektPlugins("com.gitlab.cromefire:detekt-gitlab-report:0.3.1")
}

tasks.withType<Detekt> {
	reports {
		custom {
			reportId = "DetektGitlabReport"
			outputLocation.set(file("$buildDir/reports/detekt/code-climate.json"))
		}
	}
}

Or use the same idea to write your own reporter, it's pretty straightforward. To use it on our CI pipeline we just call detekt as before. Also do not forget to change keywords to gather artifacts in this GitLab CI job.

check:  
  script:  
    - ./gradlew detekt
  artifacts:  
    reports:  
      codequality: build/reports/detekt/code-climate.json

This approach has the one big downside. It implies we have one report per module and not one merged report per project. Detekt has out-of-box support of merging XMl and SARIF formats, but not any custom reporter.

Convert

The other option is to convert detekt output from its Checkstyle XML or SARIF JSON formats to CodeClimate JSON. There's a library tomasbjerre/violations-lib which could parse code quality reports from dozens of formats and get SARIF or CodeClimate on the output.

I've written this small convention.violations.gradle.kts plugin to this logic setting up. You may get more information on convention plugins here in the official Gradle docs or here in my first post for example.

import se.bjurr.violations.gradle.plugin.ViolationsTask

plugins {
    id("se.bjurr.violations.violations-gradle-plugin")
}

val outputReportFile = file("$buildDir/reports/detekt/code-climate.json")

tasks.register<ViolationsTask>("violations") {
    doFirst {
        outputReportFile.parentFile.mkdirs()
    }
    codeClimateFile = outputReportFile
    violations = listOf(
        listOf("SARIF", buildDir.path, ".*/reports/detekt/report.sarif", "sarif"),
    )
}

So basically, this way I've just registered Gradle violations task to get SARIF reports from detekt output and set the code climate file to be my final output.

I used this library's Gradle plugin se.bjurr.violations:violations-gradle-plugin:1.52.2 in this sample.

Of course, to use this task you need to apply this convention plugin. You may use the plugins block of the root build.gradle.

plugins {
    id("convention.violations")
}

The usage is simple. Just call gradle violations task after gradle detekt.

check:  
  script:  
    - ./gradlew detekt
    - ./gradlew violations
  artifacts:  
    reports:  
      codequality: build/reports/detekt/code-climate.json

Conclusion

I believe there will be a time we will live in a world where all such services will use one standard for code quality reports. But for now, we need to help them a little bit to get such an awesome result.