From a88d650bcec15f1e7ec14125974554a84c7a164b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Kwiecin=CC=81ski?= Date: Mon, 27 Jun 2022 20:47:46 +0200 Subject: [PATCH] Clear ktlint caches when `.editorconfig` changes --- .../kotlinter/support/EditorConfigUtils.kt | 55 ++++++++++++++++++ .../support/KtLintEditoConfigOverrides.kt | 15 ----- .../kotlinter/tasks/ConfigurableKtLintTask.kt | 7 +++ .../kotlinter/tasks/EditorConfigUtils.kt | 30 ---------- .../gradle/kotlinter/tasks/FormatTask.kt | 4 +- .../gradle/kotlinter/tasks/LintTask.kt | 4 +- .../tasks/format/FormatWorkerAction.kt | 6 ++ .../tasks/format/FormatWorkerParameters.kt | 1 + .../kotlinter/tasks/lint/LintWorkerAction.kt | 5 ++ .../tasks/lint/LintWorkerParameters.kt | 1 + .../kotlinter/functional/EditorConfigTest.kt | 56 +++++++++++++++++-- 11 files changed, 131 insertions(+), 53 deletions(-) create mode 100644 src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt delete mode 100644 src/main/kotlin/org/jmailen/gradle/kotlinter/support/KtLintEditoConfigOverrides.kt delete mode 100644 src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/EditorConfigUtils.kt diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt new file mode 100644 index 00000000..3e31d8b4 --- /dev/null +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt @@ -0,0 +1,55 @@ +package org.jmailen.gradle.kotlinter.support + +import com.pinterest.ktlint.core.KtLint +import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties +import com.pinterest.ktlint.core.api.EditorConfigOverride +import org.gradle.api.file.ProjectLayout +import org.gradle.api.logging.Logger +import org.gradle.api.provider.Property +import java.io.File + +internal fun editorConfigOverride(ktLintParams: KtLintParams): EditorConfigOverride { + val rules = ktLintParams.disabledRules + + return if (rules.isEmpty()) { + EditorConfigOverride.emptyEditorConfigOverride + } else { + EditorConfigOverride.from(DefaultEditorConfigProperties.disabledRulesProperty to rules.joinToString(separator = ",")) + } +} + +internal fun resetEditorconfigCacheIfNeeded( + wasEditorConfigChanged: Property, + logger: Logger, +) { + if (wasEditorConfigChanged.get()) { + logger.info("Editorconfig changed, resetting KtLint caches") + KtLint.trimMemory() // Calling trimMemory() will also reset internal loaded `.editorconfig` cache + } +} + +internal fun ProjectLayout.findApplicableEditorConfigFiles(): Sequence { + val projectEditorConfig = projectDirectory.file(".editorconfig").asFile + + return generateSequence(seed = projectEditorConfig) { 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/main/kotlin/org/jmailen/gradle/kotlinter/support/KtLintEditoConfigOverrides.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/support/KtLintEditoConfigOverrides.kt deleted file mode 100644 index a06dc3ce..00000000 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/support/KtLintEditoConfigOverrides.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.jmailen.gradle.kotlinter.support - -import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties.disabledRulesProperty -import com.pinterest.ktlint.core.api.EditorConfigOverride -import com.pinterest.ktlint.core.api.EditorConfigOverride.Companion.emptyEditorConfigOverride - -internal fun editorConfigOverride(ktLintParams: KtLintParams): EditorConfigOverride { - val rules = ktLintParams.disabledRules - - return if (rules.isEmpty()) { - emptyEditorConfigOverride - } else { - EditorConfigOverride.from(disabledRulesProperty to rules.joinToString(separator = ",")) - } -} 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 fd918c2d..73286488 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/ConfigurableKtLintTask.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/ConfigurableKtLintTask.kt @@ -13,9 +13,12 @@ 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.gradle.work.Incremental +import org.gradle.work.InputChanges import org.jmailen.gradle.kotlinter.KotlinterExtension.Companion.DEFAULT_DISABLED_RULES import org.jmailen.gradle.kotlinter.KotlinterExtension.Companion.DEFAULT_EXPERIMENTAL_RULES import org.jmailen.gradle.kotlinter.support.KtLintParams +import org.jmailen.gradle.kotlinter.support.findApplicableEditorConfigFiles abstract class ConfigurableKtLintTask( projectLayout: ProjectLayout, @@ -30,6 +33,7 @@ abstract class ConfigurableKtLintTask( @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE) + @get:Incremental internal val editorconfigFiles: FileCollection = objectFactory.fileCollection().apply { from(projectLayout.findApplicableEditorConfigFiles().toList()) } @@ -39,6 +43,9 @@ abstract class ConfigurableKtLintTask( experimentalRules = experimentalRules.get(), disabledRules = disabledRules.get() ) + + protected fun wasEditorconfigChanged(inputChanges: InputChanges) = + inputChanges.isIncremental && inputChanges.getFileChanges(editorconfigFiles).any() } internal inline fun ObjectFactory.property(default: T? = null): Property = diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/EditorConfigUtils.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/EditorConfigUtils.kt deleted file mode 100644 index 343a9eae..00000000 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/EditorConfigUtils.kt +++ /dev/null @@ -1,30 +0,0 @@ -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 -> - 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/main/kotlin/org/jmailen/gradle/kotlinter/tasks/FormatTask.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/FormatTask.kt index cae4f0c6..d65c9375 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/FormatTask.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/FormatTask.kt @@ -7,6 +7,7 @@ import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction +import org.gradle.work.InputChanges import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import org.jmailen.gradle.kotlinter.support.KotlinterError @@ -31,7 +32,7 @@ open class FormatTask @Inject constructor( } @TaskAction - fun run() { + fun run(inputChanges: InputChanges) { val result = with(workerExecutor.noIsolation()) { submit(FormatWorkerAction::class.java) { p -> p.name.set(name) @@ -39,6 +40,7 @@ open class FormatTask @Inject constructor( p.projectDirectory.set(projectLayout.projectDirectory.asFile) p.ktLintParams.set(getKtLintParams()) p.output.set(report) + p.wasEditorConfigChanged.set(wasEditorconfigChanged(inputChanges)) } runCatching { await() } } diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt index c0aa674d..edd26171 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt @@ -13,6 +13,7 @@ import org.gradle.api.tasks.OutputFiles import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction +import org.gradle.work.InputChanges import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import org.jmailen.gradle.kotlinter.KotlinterExtension.Companion.DEFAULT_IGNORE_FAILURES @@ -43,7 +44,7 @@ open class LintTask @Inject constructor( val ignoreFailures: Property = objectFactory.property(default = DEFAULT_IGNORE_FAILURES) @TaskAction - fun run() { + fun run(inputChanges: InputChanges) { val result = with(workerExecutor.noIsolation()) { submit(LintWorkerAction::class.java) { p -> p.name.set(name) @@ -51,6 +52,7 @@ open class LintTask @Inject constructor( p.projectDirectory.set(projectLayout.projectDirectory.asFile) p.reporters.putAll(reports) p.ktLintParams.set(getKtLintParams()) + p.wasEditorConfigChanged.set(wasEditorconfigChanged(inputChanges)) } runCatching { await() } } diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt index f41174af..96076a42 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt @@ -12,6 +12,7 @@ import org.jmailen.gradle.kotlinter.support.KotlinterError import org.jmailen.gradle.kotlinter.support.KtLintParams import org.jmailen.gradle.kotlinter.support.defaultRuleSetProviders import org.jmailen.gradle.kotlinter.support.editorConfigOverride +import org.jmailen.gradle.kotlinter.support.resetEditorconfigCacheIfNeeded import org.jmailen.gradle.kotlinter.support.resolveRuleSets import org.jmailen.gradle.kotlinter.tasks.FormatTask import java.io.File @@ -25,6 +26,11 @@ abstract class FormatWorkerAction : WorkAction { private val output: File? = parameters.output.asFile.orNull override fun execute() { + resetEditorconfigCacheIfNeeded( + wasEditorConfigChanged = parameters.wasEditorConfigChanged, + logger = logger, + ) + val fixes = mutableListOf() try { files.forEach { file -> diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerParameters.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerParameters.kt index 684b1c2e..3f02d1c3 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerParameters.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerParameters.kt @@ -8,6 +8,7 @@ import org.jmailen.gradle.kotlinter.support.KtLintParams interface FormatWorkerParameters : WorkParameters { val name: Property + val wasEditorConfigChanged: Property val files: ConfigurableFileCollection val projectDirectory: RegularFileProperty val ktLintParams: Property diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt index 1b53527e..0d4cd805 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt @@ -15,6 +15,7 @@ import org.jmailen.gradle.kotlinter.support.defaultRuleSetProviders import org.jmailen.gradle.kotlinter.support.editorConfigOverride import org.jmailen.gradle.kotlinter.support.reporterFor import org.jmailen.gradle.kotlinter.support.reporterPathFor +import org.jmailen.gradle.kotlinter.support.resetEditorconfigCacheIfNeeded import org.jmailen.gradle.kotlinter.support.resolveRuleSets import org.jmailen.gradle.kotlinter.tasks.LintTask import java.io.File @@ -30,6 +31,10 @@ abstract class LintWorkerAction : WorkAction { private val ktLintParams: KtLintParams = parameters.ktLintParams.get() override fun execute() { + resetEditorconfigCacheIfNeeded( + wasEditorConfigChanged = parameters.wasEditorConfigChanged, + logger = logger, + ) var hasError = false try { diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt index cd7def3b..2fd74e94 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt @@ -10,6 +10,7 @@ import java.io.File interface LintWorkerParameters : WorkParameters { val name: Property + val wasEditorConfigChanged: Property val files: ConfigurableFileCollection val projectDirectory: RegularFileProperty val reporters: MapProperty diff --git a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt index 3f74abce..4e67545c 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt @@ -6,6 +6,7 @@ import org.jmailen.gradle.kotlinter.functional.utils.kotlinClass import org.jmailen.gradle.kotlinter.functional.utils.resolve import org.jmailen.gradle.kotlinter.functional.utils.settingsFile import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test @@ -100,18 +101,59 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { assertTrue(output.contains("[indent] Unexpected indentation (2) (should be 6)")) } } + @Test - fun `editorconfig changes are taken into account on task re-runs`() { + fun `editorconfig changes are taken into account on lint task re-runs`() { projectRoot.resolve(".editorconfig") { - writeText(editorConfig) + writeText( + """ + [*.{kt,kts}] + disabled_rules=filename + """.trimIndent(), + ) } - projectRoot.resolve("src/main/kotlin/FileName.kt") { writeText(kotlinClass("DifferentClassName")) } - buildAndFail("lintKotlin").apply { + build("lintKotlin").apply { + assertEquals(TaskOutcome.SUCCESS, task(":lintKotlinMain")?.outcome) + assertFalse(output.contains("resetting KtLint caches")) + } + + projectRoot.resolve(".editorconfig") { + writeText(editorConfig) + } + buildAndFail("lintKotlin", "--info").apply { assertEquals(TaskOutcome.FAILED, task(":lintKotlinMain")?.outcome) assertTrue(output.contains("[filename] File 'FileName.kt' contains a single top level declaration")) + assertTrue(output.contains("resetting KtLint caches")) + } + + projectRoot.resolve("src/main/kotlin/FileName.kt") { + writeText(kotlinClass("FileName")) + } + build("lintKotlin").apply { + assertEquals(TaskOutcome.SUCCESS, task(":lintKotlinMain")?.outcome) + assertFalse(output.contains("resetting KtLint caches")) + } + build("lintKotlin").apply { + assertEquals(TaskOutcome.UP_TO_DATE, task(":lintKotlinMain")?.outcome) + assertFalse(output.contains("resetting KtLint caches")) + } + } + + @Test + fun `editorconfig changes are ignored for format task re-runs`() { + projectRoot.resolve(".editorconfig") { + writeText(editorConfig) + } + + projectRoot.resolve("src/main/kotlin/FileName.kt") { + writeText(kotlinClass("DifferentClassName")) + } + build("formatKotlin").apply { + assertEquals(TaskOutcome.SUCCESS, task(":formatKotlinMain")?.outcome) + assertTrue(output.contains("Format could not fix > [filename] File 'FileName.kt' contains a single top level declaration")) } projectRoot.resolve(".editorconfig") { @@ -122,8 +164,10 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { """.trimIndent(), ) } - build("lintKotlin").apply { - assertEquals(TaskOutcome.SUCCESS, task(":lintKotlinMain")?.outcome) + build("formatKotlin", "--info").apply { + assertEquals(TaskOutcome.SUCCESS, task(":formatKotlinMain")?.outcome) + assertTrue(output.contains("Format could not fix")) + assertFalse(output.contains("resetting KtLint caches")) } } }