diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/ConfigurableKtLintTask.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/ConfigurableKtLintTask.kt index e76eaaba..1086b127 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/ConfigurableKtLintTask.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/ConfigurableKtLintTask.kt @@ -1,13 +1,17 @@ package org.jmailen.gradle.kotlinter.tasks +import org.gradle.api.file.FileCollection import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.SourceTask import org.gradle.internal.exceptions.MultiCauseException import org.jmailen.gradle.kotlinter.KotlinterExtension.Companion.DEFAULT_DISABLED_RULES @@ -29,6 +33,12 @@ abstract class ConfigurableKtLintTask( @Input val disabledRules: ListProperty = objectFactory.listProperty(default = DEFAULT_DISABLED_RULES.toList()) + @get:InputFiles + @get:PathSensitive(PathSensitivity.RELATIVE) + internal val editorconfigFiles: FileCollection = objectFactory.fileCollection().apply { + from(projectLayout.findApplicableEditorConfigFiles().toList()) + } + @Internal protected fun getKtLintParams(): KtLintParams = KtLintParams( indentSize = indentSize.orNull, diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/EditorConfigUtils.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/EditorConfigUtils.kt new file mode 100644 index 00000000..b3f370d1 --- /dev/null +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/EditorConfigUtils.kt @@ -0,0 +1,31 @@ +package org.jmailen.gradle.kotlinter.tasks + +import org.gradle.api.file.ProjectLayout +import java.io.File + +internal fun ProjectLayout.findApplicableEditorConfigFiles(): Sequence { + val projectEditorConfig = projectDirectory.file(".editorconfig").asFile + + return generateSequence(seed = projectEditorConfig) { editorconfig -> + println("Invoked with $editorconfig") + if (editorconfig.isRootEditorConfig) { + null + } else { + editorconfig.parentFile?.parentFile?.resolve(".editorconfig") + } + } +} + +private val File.isRootEditorConfig: Boolean + get() { + if (!isFile || !canRead()) return false + + return useLines { lines -> + lines.any { line -> line.matches(editorConfigRootRegex) } + } + } + +/** + * According to https://editorconfig.org/ root-most EditorConfig file contains line with `root=true` + */ +private val editorConfigRootRegex = "^root\\s?=\\s?true".toRegex() diff --git a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt index 2655b900..5f0f77e1 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt @@ -3,6 +3,7 @@ package org.jmailen.gradle.kotlinter.functional import org.gradle.testkit.runner.TaskOutcome.FAILED import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE +import org.jmailen.gradle.kotlinter.functional.utils.editorConfig import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before @@ -14,6 +15,7 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { private lateinit var settingsFile: File private lateinit var buildFile: File private lateinit var sourceDir: File + private lateinit var editorconfigFile: File private val pathPattern = "(.*\\.kt):\\d+:\\d+".toRegex() @Before @@ -21,6 +23,7 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { settingsFile = testProjectDir.newFile("settings.gradle") buildFile = testProjectDir.newFile("build.gradle") sourceDir = testProjectDir.newFolder("src", "main", "kotlin") + editorconfigFile = testProjectDir.newFile(".editorconfig") } @Test @@ -120,6 +123,7 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { fun `tasks up-to-date checks`() { settingsFile() buildFile() + editorConfig() kotlinSourceFile( "CustomObject.kt", """ @@ -141,6 +145,14 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { build("formatKotlin").apply { assertEquals(SUCCESS, task(":formatKotlin")?.outcome) } + + editorconfigFile.appendText("content=updated") + build("lintKotlin").apply { + assertEquals(SUCCESS, task(":lintKotlin")?.outcome) + } + build("lintKotlin").apply { + assertEquals(UP_TO_DATE, task(":lintKotlin")?.outcome) + } } @Test @@ -178,6 +190,10 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { writeText("rootProject.name = 'kotlinter'") } + private fun editorConfig() = editorconfigFile.apply { + writeText(editorConfig) + } + private fun buildFile() = buildFile.apply { // language=groovy val buildscript =