Detekt

Code QualityLinterKotlinDevOpsStatic AnalysisAndroidJVMMultiplatform

DevOps Tool

Detekt

Overview

Detekt is a static code analysis tool specifically designed for the Kotlin programming language, aimed at improving Kotlin code quality and detecting code smells. Developed as an open-source tool by the Kotlin community, it supports Android, JVM, JS, Native, and multiplatform projects. With highly configurable rule sets, multiple report formats, custom rule creation capabilities, and IDE integration, it provides comprehensive code quality management for Kotlin development.

Details

Detekt serves as the standard static code analysis tool in the Kotlin ecosystem, developed community-driven. With deep understanding of Kotlin language characteristics, it promotes Kotlin-idiomatic code writing, helping build maintainable codebases.

Key Features

  • Comprehensive Code Analysis: Detection of code smells, anti-patterns, and potential bugs
  • Advanced Configuration: Rule set customization for project-specific requirements
  • Rich Report Formats: Support for HTML, Markdown, SARIF, XML (Checkstyle), and custom reports
  • Cross-platform Support: Complete support for Android, JVM, JS, Native, and multiplatform
  • Baseline Functionality: Gradual introduction support for legacy projects
  • Custom Rules: Project-specific rule creation and application capabilities
  • Complexity Reports: Measurement of cyclomatic complexity, lines of code, and code smell counts
  • IDE Integration: Real-time analysis in IntelliJ IDEA, Android Studio, etc.
  • ktlint Integration: Unified execution of code style enforcement and Detekt analysis

2025 Features

  • Kotlin 2.0 Support: Complete compatibility with latest Kotlin language features
  • Performance Improvements: Analysis speed optimization for large projects
  • Enhanced Baseline: More flexible baseline management functionality
  • Improved Reporting: More detailed and practical report generation

Pros and Cons

Pros

  • Deep language understanding and optimized analysis through Kotlin-specific design
  • Continuous improvement and updates by open-source community
  • Unified quality management across Android, JVM, and multiplatform development
  • Project-specific requirement support through highly configurable rules
  • Gradual improvement of legacy code through baseline functionality
  • Flexible quality status visualization through multiple report formats
  • Real-time quality feedback through IDE integration
  • Enterprise/project-specific standard support through custom rule creation
  • Centralized style and quality management through ktlint integration
  • Automated quality gates through CI/CD integration

Cons

  • Limited to Kotlin only, cannot be used for other language projects
  • Complexity of initial setup and learning costs
  • Long analysis times for large projects
  • Risk of development speed reduction due to excessive configuration
  • Heavy warning handling burden when applying to legacy code
  • Difficulty in understanding and properly configuring rule sets
  • Technical requirements for custom rule development
  • Maintenance burden from configuration file complexity
  • Handling false positives from some rules
  • Compatibility management due to Kotlin version dependencies

Reference Links

Code Examples

Installation and Basic Setup

Gradle Plugin Installation

// build.gradle.kts (recommended)
plugins {
    id("io.gitlab.arturbosch.detekt") version "1.23.6"
}

detekt {
    toolVersion = "1.23.6"
    config = files("config/detekt/detekt.yml")
    buildUponDefaultConfig = true
    allRules = false
    baseline = file("config/detekt/baseline.xml")
    parallel = true
}

dependencies {
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.6")
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-rules-libraries:1.23.6")
}

// build.gradle (Groovy)
plugins {
    id 'io.gitlab.arturbosch.detekt' version '1.23.6'
}

detekt {
    toolVersion = '1.23.6'
    config = files('config/detekt/detekt.yml')
    buildUponDefaultConfig = true
    allRules = false
    baseline = file('config/detekt/baseline.xml')
    parallel = true
}

Maven Configuration

<!-- pom.xml -->
<plugin>
    <groupId>com.github.ozsie</groupId>
    <artifactId>detekt-maven-plugin</artifactId>
    <version>1.23.6</version>
    <configuration>
        <config>config/detekt/detekt.yml</config>
        <baseline>config/detekt/baseline.xml</baseline>
        <parallel>true</parallel>
        <buildUponDefaultConfig>true</buildUponDefaultConfig>
    </configuration>
    <executions>
        <execution>
            <phase>verify</phase>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Command Line Usage

# Download CLI
curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.6/detekt-cli-1.23.6-all.jar

# Basic execution
java -jar detekt-cli-1.23.6-all.jar --input path/to/project

# Specify configuration file
java -jar detekt-cli-1.23.6-all.jar --input path/to/project --config config/detekt.yml

# Generate report
java -jar detekt-cli-1.23.6-all.jar --input path/to/project --report html:report.html

# Multiple report formats
java -jar detekt-cli-1.23.6-all.jar --input path/to/project --report html:report.html --report xml:report.xml

Basic Execution Methods

Gradle Task Execution

# Basic analysis
./gradlew detekt

# Generate configuration file
./gradlew detektGenerateConfig

# Generate baseline
./gradlew detektBaseline

# Specific rule set only
./gradlew detekt -Ddetekt.config=config/custom-detekt.yml

# Detailed output
./gradlew detekt --info

# Parallel execution
./gradlew detekt --parallel

# All source sets
./gradlew detektMain detektTest

Configuration File (detekt.yml)

# config/detekt/detekt.yml
build:
  maxIssues: 0
  excludeCorrectable: false
  weights:
    complexity: 2
    LongParameterList: 1
    style: 1
    comments: 1

config:
  validation: true
  warningsAsErrors: false
  checkExhaustiveness: false
  excludes: ""

processors:
  active: true
  exclude:
    - 'DetektProgressListener'
  parallel: true

console-reports:
  active: true
  exclude:
    - 'ProjectStatisticsReport'
    - 'ComplexityReport'
    - 'NotificationReport'
    - 'FindingsReport'
    - 'FileBasedFindingsReport'

output-reports:
  active: true
  exclude:
    - 'TxtOutputReport'
  reports:
    - type: 'html'
      output: 'reports/detekt.html'
    - type: 'xml'
      output: 'reports/detekt.xml'
    - type: 'md'
      output: 'reports/detekt.md'

comments:
  active: true
  CommentOverPrivateFunction:
    active: false
  CommentOverPrivateProperty:
    active: false
  UndocumentedPublicClass:
    active: false
  UndocumentedPublicFunction:
    active: false

complexity:
  active: true
  ComplexCondition:
    active: true
    threshold: 4
  ComplexInterface:
    active: false
    threshold: 10
    includeStaticDeclarations: false
    includePrivateDeclarations: false
  CyclomaticComplexMethod:
    active: true
    threshold: 15
    ignoreSingleWhenExpression: false
    ignoreSimpleWhenEntries: false
    ignoreNestingFunctions: false
  LargeClass:
    active: true
    threshold: 600
  LongMethod:
    active: true
    threshold: 60
  LongParameterList:
    active: true
    functionThreshold: 6
    constructorThreshold: 7
    ignoreDefaultParameters: false
    ignoreDataClasses: true
    ignoreAnnotated: []

coroutines:
  active: true
  GlobalCoroutineUsage:
    active: false
  RedundantSuspendModifier:
    active: false
  SleepInsteadOfDelay:
    active: true
  SuspendFunWithFlowReturnType:
    active: true

empty-blocks:
  active: true
  EmptyCatchBlock:
    active: true
    allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
  EmptyClassBlock:
    active: true
  EmptyDefaultConstructor:
    active: true
  EmptyDoWhileBlock:
    active: true
  EmptyElseBlock:
    active: true
  EmptyFinallyBlock:
    active: true
  EmptyForBlock:
    active: true
  EmptyFunctionBlock:
    active: true
    ignoreOverridden: false
  EmptyIfBlock:
    active: true
  EmptyInitBlock:
    active: true
  EmptyKtFile:
    active: true
  EmptySecondaryConstructor:
    active: true
  EmptyTryBlock:
    active: true
  EmptyWhenBlock:
    active: true
  EmptyWhileBlock:
    active: true

exceptions:
  active: true
  ExceptionRaisedInUnexpectedLocation:
    active: false
    methodNames: 'toString,hashCode,equals,finalize'
  InstanceOfCheckForException:
    active: false
  NotImplementedDeclaration:
    active: false
  PrintStackTrace:
    active: false
  RethrowCaughtException:
    active: false
  ReturnFromFinally:
    active: false
  SwallowedException:
    active: false
    ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException'
  ThrowingExceptionFromFinally:
    active: false
  ThrowingExceptionInMain:
    active: false
  ThrowingExceptionsWithoutMessageOrCause:
    active: false
    exceptions: 'IllegalArgumentException,IllegalStateException,IOException'
  TooGenericExceptionCaught:
    active: true
    excludes: ['src/test/**']
    exceptionNames:
      - ArrayIndexOutOfBoundsException
      - Error
      - Exception
      - IllegalMonitorStateException
      - NullPointerException
      - IndexOutOfBoundsException
      - RuntimeException
      - Throwable
    allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
  TooGenericExceptionThrown:
    active: true
    exceptionNames:
      - Error
      - Exception
      - Throwable
      - RuntimeException

formatting:
  active: true
  android: false
  autoCorrect: true
  AnnotationOnSeparateLine:
    active: false
    autoCorrect: true
  AnnotationSpacing:
    active: false
    autoCorrect: true
  ArgumentListWrapping:
    active: false
    autoCorrect: true
  ChainWrapping:
    active: true
    autoCorrect: true
  CommentSpacing:
    active: true
    autoCorrect: true
  EnumEntryNameCase:
    active: false
    autoCorrect: true
  Filename:
    active: true
  FinalNewline:
    active: true
    autoCorrect: true
  ImportOrdering:
    active: false
    autoCorrect: true
  Indentation:
    active: false
    autoCorrect: true
    indentSize: 4
    continuationIndentSize: 4
  MaximumLineLength:
    active: true
    maxLineLength: 120
  ModifierOrdering:
    active: true
    autoCorrect: true
  MultiLineIfElse:
    active: false
    autoCorrect: true
  NoBlankLineBeforeRbrace:
    active: true
    autoCorrect: true
  NoConsecutiveBlankLines:
    active: true
    autoCorrect: true
  NoEmptyClassBody:
    active: true
    autoCorrect: true
  NoEmptyFirstLineInMethodBlock:
    active: false
    autoCorrect: true
  NoLineBreakAfterElse:
    active: false
    autoCorrect: true
  NoLineBreakBeforeAssignment:
    active: false
    autoCorrect: true
  NoMultipleSpaces:
    active: true
    autoCorrect: true
  NoSemicolons:
    active: true
    autoCorrect: true
  NoTrailingSpaces:
    active: true
    autoCorrect: true
  NoUnitReturn:
    active: true
    autoCorrect: true
  NoUnusedImports:
    active: true
    autoCorrect: true
  NoWildcardImports:
    active: true
  PackageName:
    active: true
    autoCorrect: true
  ParameterListWrapping:
    active: false
    autoCorrect: true
  SpacingAroundColon:
    active: true
    autoCorrect: true
  SpacingAroundComma:
    active: true
    autoCorrect: true
  SpacingAroundCurly:
    active: true
    autoCorrect: true
  SpacingAroundDot:
    active: true
    autoCorrect: true
  SpacingAroundKeyword:
    active: true
    autoCorrect: true
  SpacingAroundOperators:
    active: true
    autoCorrect: true
  SpacingAroundParens:
    active: true
    autoCorrect: true
  SpacingAroundRangeOperator:
    active: true
    autoCorrect: true
  StringTemplate:
    active: true
    autoCorrect: true

naming:
  active: true
  ClassNaming:
    active: true
    excludes: ['src/test/**']
    classPattern: '[A-Z$][a-zA-Z0-9$]*'
  ConstructorParameterNaming:
    active: true
    excludes: ['src/test/**']
    parameterPattern: '[a-z][A-Za-z0-9]*'
    privateParameterPattern: '[a-z][A-Za-z0-9]*'
    excludeClassPattern: '$^'
    ignoreOverridden: true
  EnumNaming:
    active: true
    excludes: ['src/test/**']
    enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*'
  ForbiddenClassName:
    active: false
    excludes: ['src/test/**']
    forbiddenName: []
  FunctionMaxLength:
    active: false
    excludes: ['src/test/**']
    maximumFunctionNameLength: 30
  FunctionMinLength:
    active: false
    excludes: ['src/test/**']
    minimumFunctionNameLength: 3
  FunctionNaming:
    active: true
    excludes: ['src/test/**']
    functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$'
    excludeClassPattern: '$^'
    ignoreOverridden: true
    ignoreAnnotated: ['Composable']
  FunctionParameterNaming:
    active: true
    excludes: ['src/test/**']
    parameterPattern: '[a-z][A-Za-z0-9]*'
    excludeClassPattern: '$^'
    ignoreOverridden: true
  InvalidPackageDeclaration:
    active: false
  MemberNameEqualsClassName:
    active: true
    ignoreOverridden: true
  ObjectNaming:
    active: true
    excludes: ['src/test/**']
    constantPattern: '[A-Za-z][_A-Za-z0-9]*'
    propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
    privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'
  PackageNaming:
    active: true
    excludes: ['src/test/**']
    packagePattern: '^[a-z]+(\.[a-z][A-Za-z0-9]*)*$'
  TopLevelPropertyNaming:
    active: true
    excludes: ['src/test/**']
    constantPattern: '[A-Z][_A-Z0-9]*'
    propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
    privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'
  VariableMaxLength:
    active: false
    excludes: ['src/test/**']
    maximumVariableNameLength: 64
  VariableMinLength:
    active: false
    excludes: ['src/test/**']
    minimumVariableNameLength: 1
  VariableNaming:
    active: true
    excludes: ['src/test/**']
    variablePattern: '[a-z][A-Za-z0-9]*'
    privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
    excludeClassPattern: '$^'
    ignoreOverridden: true

performance:
  active: true
  ArrayPrimitive:
    active: false
  CouldBeSequence:
    active: false
    threshold: 3
  ForEachOnRange:
    active: true
    excludes: ['src/test/**']
  SpreadOperator:
    active: true
    excludes: ['src/test/**']
  UnnecessaryTemporaryInstantiation:
    active: true

potential-bugs:
  active: true
  AvoidReferentialEquality:
    active: false
    forbiddenTypePatterns:
      - 'kotlin.String'
  CastToNullableType:
    active: false
  Deprecation:
    active: false
  DontDowncastCollectionTypes:
    active: false
  DoubleMutabilityForCollection:
    active: false
  DuplicateCaseInWhenExpression:
    active: true
  EqualsAlwaysReturnsTrueOrFalse:
    active: false
  EqualsWithHashCodeExist:
    active: true
  ExplicitGarbageCollectionCall:
    active: true
  HasPlatformType:
    active: false
  IgnoredReturnValue:
    active: false
    restrictToAnnotatedMethods: true
    returnValueAnnotations: ['*.CheckReturnValue', '*.CheckResult']
  ImplicitDefaultLocale:
    active: false
  ImplicitUnitReturnType:
    active: false
    allowExplicitReturnType: true
  InvalidRange:
    active: false
  IteratorHasNextCallsNextMethod:
    active: false
  IteratorNotThrowingNoSuchElementException:
    active: false
  LateinitUsage:
    active: false
    excludes: ['src/test/**']
    excludeAnnotatedProperties: []
    ignoreOnClassesPattern: ""
  MapGetWithNotNullAssertionOperator:
    active: false
  MissingWhenCase:
    active: false
  NullableToStringCall:
    active: false
  RedundantElseInWhen:
    active: true
  UnconditionalJumpStatementInLoop:
    active: false
  UnnecessaryNotNullOperator:
    active: false
  UnnecessarySafeCall:
    active: false
  UnreachableCode:
    active: true
  UnsafeCallOnNullableType:
    active: false
  UnsafeCast:
    active: false
  UselessPostfixExpression:
    active: false
  WrongEqualsTypeParameter:
    active: false

style:
  active: true
  ClassOrdering:
    active: false
  CollapsibleIfStatements:
    active: false
  DataClassContainsFunction:
    active: false
    conversionFunctionPrefix: 'to'
  DataClassShouldBeImmutable:
    active: false
  DestructuringDeclarationWithTooManyEntries:
    active: false
    maxDestructuringEntries: 3
  EqualsNullCall:
    active: false
  EqualsOnSignChangingDataType:
    active: false
    enabled: true
  ExplicitCollectionElementAccessMethod:
    active: false
  ExplicitItLambdaParameter:
    active: false
  ExpressionBodySyntax:
    active: false
    includeLineWrapping: false
  ForbiddenComment:
    active: true
    values: ['TODO:', 'FIXME:', 'STOPSHIP:']
    allowedPatterns: ""
  ForbiddenImport:
    active: false
    imports: []
    forbiddenPatterns: ""
  ForbiddenMethodCall:
    active: false
    methods: []
  ForbiddenPublicDataClass:
    active: false
    excludes: ['src/test/**']
  ForbiddenVoid:
    active: false
    ignoreOverridden: false
    ignoreUsageInGenerics: false
  FunctionOnlyReturningConstant:
    active: false
    ignoreOverridableFunction: true
    excludedFunctions: 'describeContents'
    excludeAnnotatedFunction: ['dagger.Provides']
  LibraryCodeMustSpecifyReturnType:
    active: false
  LibraryEntitiesShouldNotBePublic:
    active: false
  LoopWithTooManyJumpStatements:
    active: false
    maxJumpCount: 1
  MagicNumber:
    active: true
    excludes: ['src/test/**']
    ignoreNumbers: ['-1', '0', '1', '2']
    ignoreHashCodeFunction: true
    ignorePropertyDeclaration: false
    ignoreLocalVariableDeclaration: false
    ignoreConstantDeclaration: true
    ignoreCompanionObjectPropertyDeclaration: true
    ignoreAnnotation: false
    ignoreNamedArgument: true
    ignoreEnums: false
    ignoreRanges: false
  MandatoryBracesIfStatements:
    active: false
  MandatoryBracesLoops:
    active: false
  MaxLineLength:
    active: true
    maxLineLength: 120
    excludePackageStatements: true
    excludeImportStatements: true
    excludeCommentStatements: false
  MayBeConst:
    active: false
  ModifierOrder:
    active: true
  NestedClassesVisibility:
    active: false
  NewLineAtEndOfFile:
    active: true
  NoTabs:
    active: false
  OptionalAbstractKeyword:
    active: true
  OptionalUnit:
    active: false
  OptionalWhenBraces:
    active: false
  PreferToOverPairSyntax:
    active: false
  ProtectedMemberInFinalClass:
    active: false
  RedundantExplicitType:
    active: false
  RedundantHigherOrderMapUsage:
    active: false
  RedundantVisibilityModifierRule:
    active: false
  ReturnCount:
    active: true
    max: 2
    excludedFunctions: "equals"
    excludeLabeled: false
    excludeReturnFromLambda: true
    excludeGuardClauses: false
  SafeCast:
    active: true
  SerialVersionUIDInSerializableClass:
    active: false
  SpacingBetweenPackageAndImports:
    active: false
  ThrowsCount:
    active: true
    max: 2
    excludeGuardClauses: false
  TrailingWhitespace:
    active: false
  UnderscoresInNumericLiterals:
    active: false
    acceptableDecimalLength: 5
  UnnecessaryAbstractClass:
    active: false
    excludeAnnotatedClasses: ['dagger.Module']
  UnnecessaryAnnotationUseSiteTarget:
    active: false
  UnnecessaryApply:
    active: false
  UnnecessaryInheritance:
    active: false
  UnnecessaryLet:
    active: false
  UnnecessaryParentheses:
    active: false
  UntilInsteadOfRangeTo:
    active: false
  UnusedImports:
    active: false
  UnusedPrivateClass:
    active: false
  UnusedPrivateMember:
    active: false
    allowedNames: "(_|ignored|expected|serialVersionUID)"
  UseArrayLiteralsInAnnotations:
    active: false
  UseCheckOrError:
    active: false
  UseDataClass:
    active: false
    excludeAnnotatedClasses: []
    allowVars: false
  UseEmptyCounterpart:
    active: false
  UseIfEmptyOrIfBlank:
    active: false
  UseIfInsteadOfWhen:
    active: false
  UseIsNullOrEmpty:
    active: false
  UseOrEmpty:
    active: false
  UseRequire:
    active: false
  UseRequireNotNull:
    active: false
  UselessCallOnNotNull:
    active: false
  UtilityClassWithPublicConstructor:
    active: false
  VarCouldBeVal:
    active: false
  WildcardImport:
    active: true
    excludes: ['src/test/**']
    excludeImports: ['java.util.*', 'kotlinx.android.synthetic.*']

Android Project Configuration

Android Configuration Example

// app/build.gradle.kts
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("io.gitlab.arturbosch.detekt")
}

android {
    compileSdk 34
    
    defaultConfig {
        minSdk 21
        targetSdk 34
    }
}

detekt {
    toolVersion = "1.23.6"
    config = files("$projectDir/config/detekt/detekt.yml")
    buildUponDefaultConfig = true
    allRules = false
    baseline = file("$projectDir/config/detekt/baseline.xml")
    parallel = true
    
    source = files(
        "src/main/java",
        "src/main/kotlin",
        "src/test/java", 
        "src/test/kotlin"
    )
}

dependencies {
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.6")
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-rules-libraries:1.23.6")
}

tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
    // Target version of the generated JVM bytecode
    jvmTarget = "1.8"
}

tasks.withType<io.gitlab.arturbosch.detekt.DetektCreateBaselineTask>().configureEach {
    jvmTarget = "1.8"
}

Multiplatform Project Configuration

Kotlin Multiplatform Configuration

// build.gradle.kts (root project)
plugins {
    kotlin("multiplatform") version "1.9.10"
    id("io.gitlab.arturbosch.detekt") version "1.23.6"
}

kotlin {
    jvm()
    js(IR) {
        browser()
        nodejs()
    }
    
    iosX64()
    iosArm64()
    iosSimulatorArm64()
    
    sourceSets {
        val commonMain by getting
        val commonTest by getting
        val jvmMain by getting
        val jvmTest by getting
        val jsMain by getting
        val jsTest by getting
        val iosMain by creating
        val iosTest by creating
    }
}

detekt {
    source = files(
        "src/commonMain/kotlin",
        "src/commonTest/kotlin",
        "src/jvmMain/kotlin",
        "src/jvmTest/kotlin",
        "src/jsMain/kotlin",
        "src/jsTest/kotlin",
        "src/iosMain/kotlin",
        "src/iosTest/kotlin"
    )
    parallel = true
    config = files("detekt-config.yml")
    buildUponDefaultConfig = true
}

IDE Integration Configuration

IntelliJ IDEA / Android Studio Configuration

# Plugin installation
# File → Settings → Plugins → Search for "Detekt" and install

# Configuration steps
# File → Settings → Tools → Detekt
# Configuration file: Specify detekt.yml in project root
# Enable Detekt: ✓
# Enable on-the-fly inspection: ✓

# External Tools configuration (optional)
# File → Settings → Tools → External Tools → Add
Name: Detekt
Description: Kotlin static analysis
Program: ./gradlew
Arguments: detekt
Working directory: $ProjectFileDir$

VS Code Configuration

// .vscode/settings.json
{
  "kotlin.compiler.jvm.target": "1.8",
  "kotlin.detekt.enabled": true,
  "kotlin.detekt.configPath": "config/detekt/detekt.yml",
  "[kotlin]": {
    "editor.defaultFormatter": "fwcd.kotlin",
    "editor.formatOnSave": true,
    "editor.rulers": [120]
  }
}

// tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Detekt Check",
      "type": "shell",
      "command": "./gradlew",
      "args": ["detekt"],
      "group": "build",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared"
      }
    },
    {
      "label": "Detekt Baseline",
      "type": "shell",
      "command": "./gradlew",
      "args": ["detektBaseline"],
      "group": "build"
    }
  ]
}

CI/CD Integration Examples

GitHub Actions

# .github/workflows/detekt.yml
name: Detekt

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  detekt:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup JDK
      uses: actions/setup-java@v4
      with:
        java-version: '11'
        distribution: 'temurin'
    
    - name: Setup Gradle
      uses: gradle/gradle-build-action@v2
    
    - name: Run Detekt
      run: ./gradlew detekt
    
    - name: Upload Detekt reports
      uses: actions/upload-artifact@v4
      if: always()
      with:
        name: detekt-reports
        path: |
          build/reports/detekt/
          */build/reports/detekt/
    
    - name: Annotate PR with Detekt results
      uses: lcollins/detekt-action@v1
      if: github.event_name == 'pull_request'
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        detekt_config_path: config/detekt/detekt.yml

GitLab CI/CD

# .gitlab-ci.yml
stages:
  - quality

detekt:
  stage: quality
  image: openjdk:11-jdk
  before_script:
    - chmod +x ./gradlew
  script:
    - ./gradlew detekt
    - ./gradlew detekt --continue || true  # Generate reports even if issues found
  artifacts:
    reports:
      codequality: build/reports/detekt/detekt.sarif
    paths:
      - build/reports/detekt/
    expire_in: 1 week
  only:
    - main
    - develop
    - merge_requests

Custom Rule Creation

Custom Rule Example

// custom-rules/src/main/kotlin/CustomRuleSet.kt
package com.example.detekt.rules

import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.RuleSet
import io.gitlab.arturbosch.detekt.api.RuleSetProvider

class CustomRuleSetProvider : RuleSetProvider {
    override val ruleSetId: String = "custom-rules"
    
    override fun instance(config: Config): RuleSet {
        return RuleSet(
            ruleSetId,
            listOf(
                NoHardcodedStringsRule(config),
                ProperLogTagUsage(config),
                AvoidSystemPrintRule(config)
            )
        )
    }
}

// NoHardcodedStringsRule.kt
class NoHardcodedStringsRule(config: Config) : Rule(config) {
    override val issue = Issue(
        javaClass.simpleName,
        Severity.Warning,
        "Hardcoded strings should be avoided, use string resources instead",
        Debt.FIVE_MINS
    )
    
    override fun visitStringTemplateExpression(expression: KtStringTemplateExpression) {
        super.visitStringTemplateExpression(expression)
        
        if (expression.entries.size == 1 && expression.entries[0] is KtLiteralStringTemplateEntry) {
            val text = expression.entries[0].text
            if (text.length > 10 && !isInTestFile(expression)) {
                report(CodeSmell(issue, Entity.from(expression), "Hardcoded string found: $text"))
            }
        }
    }
    
    private fun isInTestFile(element: PsiElement): Boolean {
        return element.containingFile?.virtualFile?.path?.contains("/test/") == true
    }
}

Applying Custom Rules

# detekt.yml
custom-rules:
  active: true
  NoHardcodedStringsRule:
    active: true
  ProperLogTagUsage:
    active: true
    maxTagLength: 23
  AvoidSystemPrintRule:
    active: true
    excludes: ['src/test/**']

Baseline and Gradual Introduction

Baseline Generation and Management

# Initial baseline generation
./gradlew detektBaseline

# Update baseline
./gradlew detektBaseline --update-baseline

# Check ignoring baseline
./gradlew detekt --auto-correct

Gradual Introduction Strategy

// Gradle task for gradually enabling rules
tasks.register("detektGradual") {
    group = "verification"
    description = "Run detekt with gradually increasing rule strictness"
    
    doLast {
        val phases = listOf("phase1.yml", "phase2.yml", "phase3.yml")
        phases.forEach { phase ->
            exec {
                commandLine("./gradlew", "detekt", "--config", "config/detekt/$phase")
            }
        }
    }
}

Troubleshooting

Common Issues and Solutions

# Memory shortage
export GRADLE_OPTS="-Xmx2g -XX:MaxMetaspaceSize=512m"
./gradlew detekt

# Access conflicts during parallel execution
./gradlew detekt --no-parallel

# Configuration file validation
./gradlew detektGenerateConfig
diff detekt-default.yml config/detekt/detekt.yml

# Clear cache
./gradlew clean
rm -rf ~/.gradle/caches/modules-2/files-2.1/io.gitlab.arturbosch.detekt/

# Dependency verification
./gradlew dependencies --configuration detektPlugins

# Debug execution
./gradlew detekt --info --stacktrace