Speeding up the detekt task in a multi-project Gradle build.

Posted on 2020-02-12
4 mins to read

I’m going to tell you how to significantly speed up the detekt task in a multi-project Gradle build.
Precise numbers vary depending on many factors, of course.
In my case, in a build with 56 subprojects and ~7000 lines of code, it was about 10 times faster.

Tasks in a multi-project Gradle builds are usually defined on a per-project basis.
It means that every project will have its own unique instance of a task.
Here is an example for detekt:

As you see, build takes about a minute.
But what I see are three issues.

Gradle has to instantiate 56 identical tasks here.
And for detekt it means spawning a new process 56 times, parsing the config file 56 times (because processes cannot share in-memory parsed config), configuring embedded Kotlin compiler infrastructure that is used to parse the source 56 times, and, probably, doing more things 56 times, once per task.
Take a look at the sources: Detekt.kt and DetektInvoker.kt:

Perhaps it’s possible to improve this behavior, but it’s not trivial.
I hope one day it will be more efficient, though.

After the execution, you will have 56 different reports.
It’s hard to navigate between them.

The maxIssues configuration parameter is applied to every project separately.
So, if you have it set to 10, it means “ten issues in every subproject” instead of “ten issues total”.
Though, it’s ok for some people.

Luckily, it’s super easy to fix!
All you need to do is to apply the detekt plugin to the root project and configure a single “detekt all” task with the scope of the whole project:

And what is super cool about this setup is that now you have a single report file that is easy to analyze.
The maxIssues setting is now applied to the whole build, so it’s now “ten issues total”.
Finally, the new detektAll task does not interfere with the standard detekt behavior described in the first scenario: you can still execute the detekt task as described previously.