Integrating detekt in the Workflow
Learn how to integrate the powerful detekt tool in Android app development to help detect and prevent code smells during the development process. By Harun Wangereka.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Integrating detekt in the Workflow
30 mins
- Getting Started
- Understanding detekt
- Adding detekt To Your Project
- Adding to New Projects
- Running detekt Terminal Command
- Adding to Existing Projects
- Looking at detekt Rule Sets
- Configuring detekt
- Adding a Rule Set
- Breaking More Rule Sets
- Suppressing Issues
- Writing Custom detekt Rules
- Adding Your Own Rule to detekt
- Testing Your Custom Rule
- Using the Custom Rule in Your Project
- Looking at Custom Processors to detekt
- Integrating detekt With GitHub Actions
- Integrating detekt With Your IDE
- Where to Go From Here?
Configuring detekt
One of the features of detekt is the high ability to customize it to your own needs. Moreover, it gives you the ability to easily enable or disable rules in your project.
detekt uses a YAML style configuration file for setting up reports, processors, build failures, rule set and rule properties.
In the starter app, switch to project view and you’ll see detekt.yml as shown below:
Open detekt.yml. It contains some rule sets and rules properties — for example, the comments
section:
comments:
active: true
excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
CommentOverPrivateFunction:
active: false
CommentOverPrivateProperty:
active: false
EndOfSentenceFormat:
active: false
endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!:]$)
UndocumentedPublicClass:
active: false
searchInNestedClass: true
searchInInnerClass: true
searchInInnerObject: true
searchInInnerInterface: true
UndocumentedPublicFunction:
active: false
As you can see, in order to enable or disable a given rule, you just have to set the boolean value active: true/false
.
In the code above, you have the configurations for the comments
rule set, which is set to be active. There's an extra property for listing the files you'd want to exclude while reporting the issues. In this example, you exclude test and androidTest directories. Below this, you further set the properties for the individual rules in the rule sets. For instance, UndocumentedPublicFunction
is not active. detekt won't report this in your codebase.
You can customize detekt.yml according to your project requirements.
For this specific configuration to be read by detekt, you'll need to add this file to your plugin configuration. To do this, navigate to the project-level build.gradle file. Add this below your apply
line:
subprojects {
apply plugin: "io.gitlab.arturbosch.detekt"
detekt {
config = files("${project.rootDir}/detekt.yml")
parallel = true
}
}
Here, you specify the configuration file for detekt. It will no longer use the default configurations. You can enable the rules or disable them in detekt.yml. This configuration applies to all sub-projects in your project.
You've seen available configuration options for detekt. Next, you'll add more methods that violate rule sets. You'll see how detekt reports these violations.
Adding a Rule Set
Locate the MainActivity class. Add the following coroutineTestRules
function below onCreate
:
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
private suspend fun coroutineTestRules() {
GlobalScope.launch {
delay(2000)
}
}
Be sure to add the imports above at the top of the file or when the IDE prompts you to do so. This method tests the coroutines rule set.
It's a bad practice to use GlobalScope
in an activity. detekt will raise an issue on this.
Finally, call this function at the end of the onCreate
method:
runBlocking { coroutineTestRules() }
Resolve the imports once the IDE prompts you. Here, you call your coroutineTestRules()
method inside runBlocking
. You have to call suspend
methods inside coroutines or other suspend methods.
comments
section:
coroutines:
active: true
GlobalCoroutineUsage:
active: true
Here, you set the coroutines
rule set to be active. You also enable the GlobalCoroutineUsage
rule in the process. Now, run the ./gradlew detekt
command on your terminal. Your results will be as follows:
In the image, you can see the report from the terminal now includes the coroutines
rule set. It shows the debt and the file with the GlobalCoroutineUsage
. The report has additional details at the bottom as shown:
detekt.yml has additional configuration at the top. These settings specify the reports you'll get and the project complexity report from detekt. You'll look at this later on in this tutorial.
Breaking More Rule Sets
Add the following code below your coroutineTestRules
function in the MainActivity class:
// 1
private fun complexMethod(name: String, email: String, phone: String,
address: String, zipCode: String, city: String, country: String): String {
return name
}
// 2
private fun emptyMethod() {}
// 3
override fun toString(): String {
throw IllegalStateException()
}
// 4
fun performanceIssues() {
(1..19).forEach {
print(it.toString())
}
}
// 5
fun potentialBugs() {
val test = when ("type") {
"main" -> 1
"main" -> 2
else -> 3
}
}
Here's a breakdown of the code above:
- This is an example of a complex method. The method has seven parameters that exceed the maximum six parameters set by detekt. You can change this number in the configuration file too.
- This is an empty method. It falls in the
empty-blocks
rule set. - This represents the
exceptions
rule set. This method throws an exception without a cause. The exception is also thrown from an unexpected location. - You have a
forEach
loop on a range that leads to performance issues. detekt reports this under theperformance
rule set. - You have a
when
condition that has two similar states. This can lead to a bug in your app. detekt reports such cases as code smells under thepotential-bugs
rule set.
Run ./gradlew detekt
command on the terminal and you'll see:
You've learned about the rule sets in different scenarios. What about cases when detekt detects too much? At times you may need to disable a certain rule on a specific method and not the whole project. For such cases, you need to suppress the issues. In the next section, you'll look at how to suppress issues.
Suppressing Issues
To prevent detekt from displaying an issue on a specific method, you can use the @Suppress
annotation. Above complexMethod()
add the following annotation:
@Suppress("LongParameterList")
Run ./gradlew detekt
command on the terminal and you'll see the following:
From the image, you can see detekt doesn't complain about the LongParameterList
rule anymore. This will only apply to this method. If you had another file or class with a complex method, detekt would still report the issue.
To see this in action, add this new method below potentialBugs()
:
@Suppress("EmptyFunctionBlock")
private fun suppressedWarning() {
}
In this method, you suppress EmptyFunctionBlock
rule. Run ./gradlew detekt
command on the terminal and you'll see:
The report doesn't have EmptyFunctionBlock
issue on suppressedWarning()
, but on emptyMethod()
it's still shown.
So far, you've learned how to use the rules available on the detekt plugin. With your projects, you might need to detect more code smells that are not part of detekt. You'll learn how to do that next.