JLLeitschuh / ktlint-gradle

A ktlint gradle plugin
MIT License
1.46k stars 160 forks source link

Ktlint Fails to Detect Formatting Issues in Nested Modules #740

Closed houssemzaier closed 8 months ago

houssemzaier commented 8 months ago

Description

I have encountered an issue with Ktlint where it inconsistently detects formatting problems in my project. Specifically, when running KtlintFormat or KtlinCheck, it only works for some of my modules. This inconsistency becomes apparent when compared with the results from running Detekt, which correctly identifies formatting issues that Ktlint misses.

Steps to Reproduce

  1. My project structure includes modules grouped into nested folders.
  2. I run ./gradlew modules:infrastructure:shared:ktlintCheck (or modules:infrastructure:shared:ktlintFormat), which results in a false positive, indicating no issues.
  3. Running ./gradlew modules:infrastructure:shared:detekt subsequently reveals formatting issues, indicating that Ktlint did not detect these during its run.

Expected Behavior

Ktlint should consistently detect formatting issues across all modules, regardless of their nesting or grouping within the project structure.

Actual Behavior

Ktlint fails to detect formatting issues in certain nested modules, which are however detected by Detekt.

Additional Context

Here is an example of the output from Detekt, showing formatting issues that Ktlint missed:

Task :modules:infrastructure:shared:detekt FAILED

C:\Users\houss\AndroidProjects\dst-gpt-mobileapp\modules\infrastructure\shared\src\main\kotlin\com\yara\ygt\infrastructure\repository\SharedRepositoryImpl.kt:

Line 62: Unexpected indentation (17) (should be 8) [Indentation] Line 72: Unexpected indentation (12) (should be 8) [Indentation] Line 70: Needless blank line(s) [NoConsecutiveBlankLines]

Manual formatting using IntelliJ shortcuts resolves these issues, suggesting that the problem lies with Ktlint's module parsing or fetching mechanism.

I believe this issue might be related to how Ktlint handles modules that are organized into folders. It would be greatly beneficial if this could be investigated and resolved.

Thank you for your attention to this matter.

JLLeitschuh commented 8 months ago

Are you sure that the configuration of ktlint-gradle matches the config detected by detekt? Are you able to create a minimal reproducer?

houssemzaier commented 8 months ago

Absolutely certain, the issue is solely with this nested module. For other Android modules, both ktlintand detektwork properly. Additionally, I've verified that all modules share a centralized Gradle configuration, which rules out any issues due to a missed declaration. I can share my screen with you for a quick review, but I'm unable to share the actual code.

wakingrufus commented 8 months ago

Absolutely certain, the issue is solely with this nested module. For other Android modules, both ktlintand detektwork properly. Additionally, I've verified that all modules share a centralized Gradle configuration, which rules out any issues due to a missed declaration. I can share my screen with you for a quick review, but I'm unable to share the actual code.

Would you be able to share just the gradle files by chance?

houssemzaier commented 8 months ago

modules/infrastructure/shared/build.gradle.kts ❌ this one is skipped

plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
    id("org.jetbrains.kotlin.plugin.serialization")
    id("com.google.devtools.ksp")
    id("com.google.dagger.hilt.android")
    id("kotlin-kapt")
    alias(libs.plugins.org.jlleitschuh.gradle.ktlint)
    alias(libs.plugins.io.gitlab.arturbosch.detekt)
}
apply(from = "${project.rootDir}/static-analysis/ktlint/ktlint.gradle")
apply(from = "${project.rootDir}/static-analysis/detekt/detekt.gradle")
.....

modules/domain/build.gradle.kts ✔️ this one is not skipped, it's a jvm library, not an android library

plugins {
    id("org.jetbrains.kotlin.jvm")
    id("org.jetbrains.kotlin.plugin.serialization")
    alias(libs.plugins.org.jlleitschuh.gradle.ktlint)
    alias(libs.plugins.io.gitlab.arturbosch.detekt)
}
apply(from = "${project.rootDir}/static-analysis/ktlint/ktlint.gradle")
apply(from = "${project.rootDir}/static-analysis/detekt/detekt.gradle")

modules/infrastructure/shared/build.gradle.kts ❌ this one is also skipped

plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
    id("org.jetbrains.kotlin.plugin.serialization")
    id("com.google.devtools.ksp")
    id("com.google.dagger.hilt.android")
    id("kotlin-kapt")
    alias(libs.plugins.org.jlleitschuh.gradle.ktlint)
    alias(libs.plugins.io.gitlab.arturbosch.detekt)
}
apply(from = "${project.rootDir}/static-analysis/ktlint/ktlint.gradle")
apply(from = "${project.rootDir}/static-analysis/detekt/detekt.gradle")

modules/presentation/build.gradle.kts ❌ this one is also skipped

plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
    id("com.google.devtools.ksp")
    id("com.google.dagger.hilt.android")
    id("kotlin-kapt")
    alias(libs.plugins.org.jlleitschuh.gradle.ktlint)
    alias(libs.plugins.io.gitlab.arturbosch.detekt)
}
apply(from = "${project.rootDir}/static-analysis/ktlint/ktlint.gradle")
apply(from = "${project.rootDir}/static-analysis/detekt/detekt.gradle")

modules/design-system/build.gradle.kts ❌ this one is also skipped

plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
    alias(libs.plugins.org.jlleitschuh.gradle.ktlint)
    alias(libs.plugins.io.gitlab.arturbosch.detekt)
}
apply(from = "${project.rootDir}/static-analysis/ktlint/ktlint.gradle")
apply(from = "${project.rootDir}/static-analysis/detekt/detekt.gradle")

apps/ygt/build.gradle this module is working ✔️ , it's an apk module, not an Android library

the root gradle file build.gradle

plugins {
  alias(libs.plugins.com.android.application) apply false
  alias(libs.plugins.com.android.library) apply false
  alias(libs.plugins.org.jetbrains.kotlin.jvm) apply false
  alias(libs.plugins.org.jetbrains.kotlin.android) apply false
  alias(libs.plugins.org.jetbrains.kotlin.serialization) apply false
  alias(libs.plugins.com.google.gms.google.services) apply false
  alias(libs.plugins.com.google.firebase.crashlytics) apply false
  alias(libs.plugins.com.google.devtools.ksp) apply false
  alias(libs.plugins.com.google.dagger.hilt.android) apply false
  alias(libs.plugins.org.jlleitschuh.gradle.ktlint)
  alias(libs.plugins.io.gitlab.arturbosch.detekt)
}

apply from: "$project.rootDir/static-analysis/config/baseline-tasks.gradle.kts"
apply from: "$project.rootDir/productivity/tasks.gradle.kts"

static-analysis/ktlint/ktlint.gradle the configuration file

ktlint {
    version = libs.versions.ktlint.cli.get()
    debug = true
    verbose = true
    android = true
    outputToConsole = true
    outputColorName = "RED"
    enableExperimentalRules = true
    reporters {
        reporter "plain"
        reporter "checkstyle"
        reporter "sarif"
    }
}

So basically the android library are skipped from Ktlint but not from Detekt, the JVM pure library is working fine and also the APK Android library.

wakingrufus commented 8 months ago

I think you might be hitting a bug I just fixed. Can you try with ktlint-gradle 12.1.0?

houssemzaier commented 8 months ago

I tried the 12.1.0 and it fixed that indeed. Thanks @wakingrufus & thanks @JLLeitschuh for your help too

wakingrufus commented 8 months ago

Great! I'm glad that worked.