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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

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:

Android Studio Project View

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.

Note: Some of the coroutines rules are not active by default. To activate this rule, add the following code to detekt.yml above the 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:

Coroutine rule set enabled

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 reports and metrics

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:

  1. 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.
  2. This is an empty method. It falls in the empty-blocks rule set.
  3. This represents the exceptions rule set. This method throws an exception without a cause. The exception is also thrown from an unexpected location.
  4. You have a forEach loop on a range that leads to performance issues. detekt reports this under the performance rule set.
  5. 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 the potential-bugs rule set.

Run ./gradlew detekt command on the terminal and you'll see:

detekt report with more rule sets

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:

Remove long parameter list warning

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:

Empty Block Warning Removed

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.