From 2e3144e5808dc4bc38b00e2236dbae74b510b4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wasylkowski?= Date: Sun, 1 Jan 2023 20:27:45 +0100 Subject: [PATCH] Update KtLint to 0.48.1 --- build.gradle.kts | 2 +- .../kotlinter/support/EditorConfigUtils.kt | 34 +++++++-- .../gradle/kotlinter/tasks/LintTask.kt | 2 +- .../tasks/format/FormatWorkerAction.kt | 69 +++++++------------ .../kotlinter/tasks/lint/LintWorkerAction.kt | 48 ++++--------- .../tasks/lint/LintWorkerParameters.kt | 2 +- .../kotlinter/functional/EditorConfigTest.kt | 6 +- .../kotlinter/functional/ExtensionTest.kt | 9 ++- .../kotlinter/functional/KotlinProjectTest.kt | 32 +++++++++ .../gradle/kotlinter/support/RuleSetsTest.kt | 18 ++--- 10 files changed, 121 insertions(+), 101 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1d5a42ce..ae2cfd35 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ description = projectDescription object Versions { const val androidTools = "7.3.1" const val junit = "5.9.1" - const val ktlint = "0.47.1" + const val ktlint = "0.48.1" const val mockitoKotlin = "4.1.0" } diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt index a415f1cb..ecdf0ad2 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt @@ -1,8 +1,11 @@ package org.jmailen.gradle.kotlinter.support -import com.pinterest.ktlint.core.KtLint -import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties +import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.api.EditorConfigOverride +import com.pinterest.ktlint.core.api.EditorConfigOverride.Companion.EMPTY_EDITOR_CONFIG_OVERRIDE +import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import org.ec4j.core.model.PropertyType +import org.ec4j.core.model.PropertyType.PropertyValueParser.IDENTITY_VALUE_PARSER import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.ProjectLayout import org.gradle.api.logging.Logger @@ -12,20 +15,39 @@ internal fun editorConfigOverride(ktLintParams: KtLintParams): EditorConfigOverr val rules = ktLintParams.disabledRules return if (rules.isEmpty()) { - EditorConfigOverride.emptyEditorConfigOverride + EMPTY_EDITOR_CONFIG_OVERRIDE } else { - EditorConfigOverride.from(DefaultEditorConfigProperties.ktlintDisabledRulesProperty to rules.joinToString(separator = ",")) + rules + .asSequence() + .map(::getKtlintRulePropertyName) + .map { propertyName -> + EditorConfigProperty( + type = PropertyType(propertyName, "Rule to be disabled", IDENTITY_VALUE_PARSER), + defaultValue = "disabled", + ) + } + .map { it to "disabled" } + .toList() + .toTypedArray() + .let { EditorConfigOverride.from(*it) } } } -internal fun resetEditorconfigCacheIfNeeded( +private fun getKtlintRulePropertyName(ruleName: String) = + if (ruleName.contains(':')) { // Rule from a non-standard rule set + "ktlint_${ruleName.replace(':', '_')}" + } else { + "ktlint_standard_$ruleName" + } + +internal fun KtLintRuleEngine.resetEditorconfigCacheIfNeeded( changedEditorconfigFiles: ConfigurableFileCollection, logger: Logger, ) { val changedFiles = changedEditorconfigFiles.files if (changedFiles.any()) { logger.info("Editorconfig changed, resetting KtLint caches") - changedFiles.map(File::toPath).forEach(KtLint::reloadEditorConfigFile) + changedFiles.map(File::toPath).forEach(::reloadEditorConfigFile) } } 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 ba03305b..f294144b 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt @@ -52,7 +52,7 @@ open class LintTask @Inject constructor( p.projectDirectory.set(projectLayout.projectDirectory.asFile) p.reporters.putAll(reports) p.ktLintParams.set(getKtLintParams()) - p.changedEditorconfigFiles.from(getChangedEditorconfigFiles(inputChanges)) + p.changedEditorConfigFiles.from(getChangedEditorconfigFiles(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 5b411fa6..1d502305 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 @@ -1,8 +1,6 @@ package org.jmailen.gradle.kotlinter.tasks.format -import com.pinterest.ktlint.core.KtLint -import com.pinterest.ktlint.core.LintError -import com.pinterest.ktlint.core.RuleProvider +import com.pinterest.ktlint.core.KtLintRuleEngine import org.gradle.api.logging.LogLevel import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging @@ -26,7 +24,12 @@ abstract class FormatWorkerAction : WorkAction { private val output: File? = parameters.output.asFile.orNull override fun execute() { - resetEditorconfigCacheIfNeeded( + val ktLintEngine = KtLintRuleEngine( + ruleProviders = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules), + editorConfigOverride = editorConfigOverride(ktLintParams), + ) + + ktLintEngine.resetEditorconfigCacheIfNeeded( changedEditorconfigFiles = parameters.changedEditorConfigFiles, logger = logger, ) @@ -34,32 +37,27 @@ abstract class FormatWorkerAction : WorkAction { val fixes = mutableListOf() try { files.forEach { file -> - val ruleSets = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules) val sourceText = file.readText() val relativePath = file.toRelativeString(projectDirectory) logger.log(LogLevel.DEBUG, "$name checking format: $relativePath") - when (file.extension) { - "kt" -> this::formatKt - "kts" -> this::formatKts - else -> { - logger.log(LogLevel.DEBUG, "$name ignoring non Kotlin file: $relativePath") - null - } - }?.let { formatFunc -> - val formattedText = formatFunc.invoke(file, ruleSets) { error, corrected -> - val msg = when (corrected) { - true -> "${file.path}:${error.line}:${error.col}: Format fixed > [${error.ruleId}] ${error.detail}" - false -> "${file.path}:${error.line}:${error.col}: Format could not fix > [${error.ruleId}] ${error.detail}" - } - logger.log(LogLevel.QUIET, msg) - fixes.add(msg) - } - if (!formattedText.contentEquals(sourceText)) { - logger.log(LogLevel.QUIET, "${file.path}: Format fixed") - file.writeText(formattedText) + if (file.extension !in supportedExtensions) { + logger.log(LogLevel.DEBUG, "$name ignoring non Kotlin file: $relativePath") + return@forEach + } + + val formattedText = ktLintEngine.format(file.toPath()) { error, corrected -> + val msg = when (corrected) { + true -> "${file.path}:${error.line}:${error.col}: Format fixed > [${error.ruleId}] ${error.detail}" + false -> "${file.path}:${error.line}:${error.col}: Format could not fix > [${error.ruleId}] ${error.detail}" } + logger.log(LogLevel.QUIET, msg) + fixes.add(msg) + } + if (!formattedText.contentEquals(sourceText)) { + logger.log(LogLevel.QUIET, "${file.path}: Format fixed") + file.writeText(formattedText) } } } catch (t: Throwable) { @@ -73,27 +71,6 @@ abstract class FormatWorkerAction : WorkAction { }, ) } - - private fun formatKt(file: File, ruleSets: Set, onError: ErrorHandler) = - format(file, ruleSets, onError, false) - - private fun formatKts(file: File, ruleSets: Set, onError: ErrorHandler) = - format(file, ruleSets, onError, true) - - private fun format(file: File, ruleProviders: Set, onError: ErrorHandler, script: Boolean): String { - return KtLint.format( - KtLint.ExperimentalParams( - fileName = file.path, - text = file.readText(), - ruleProviders = ruleProviders, - script = script, - editorConfigOverride = editorConfigOverride(ktLintParams), - cb = { error, corrected -> - onError(error, corrected) - }, - ), - ) - } } -typealias ErrorHandler = (error: LintError, corrected: Boolean) -> Unit +private val supportedExtensions = setOf("kt", "kts") 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 914792a0..82d363c6 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 @@ -1,9 +1,7 @@ package org.jmailen.gradle.kotlinter.tasks.lint -import com.pinterest.ktlint.core.KtLint -import com.pinterest.ktlint.core.LintError +import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.Reporter -import com.pinterest.ktlint.core.RuleProvider import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging import org.gradle.internal.logging.slf4j.DefaultContextAwareTaskLogger @@ -31,8 +29,13 @@ abstract class LintWorkerAction : WorkAction { private val ktLintParams: KtLintParams = parameters.ktLintParams.get() override fun execute() { - resetEditorconfigCacheIfNeeded( - changedEditorconfigFiles = parameters.changedEditorconfigFiles, + val ktLintEngine = KtLintRuleEngine( + ruleProviders = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules), + editorConfigOverride = editorConfigOverride(ktLintParams), + ) + + ktLintEngine.resetEditorconfigCacheIfNeeded( + changedEditorconfigFiles = parameters.changedEditorConfigFiles, logger = logger, ) var hasError = false @@ -40,19 +43,16 @@ abstract class LintWorkerAction : WorkAction { try { reporters.onEach { it.beforeAll() } files.forEach { file -> - val ruleSets = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules) val relativePath = file.toRelativeString(projectDirectory) reporters.onEach { it.before(relativePath) } logger.debug("$name linting: $relativePath") - val lintFunc = when (file.extension) { - "kt" -> ::lintKt - "kts" -> ::lintKts - else -> { - logger.debug("$name ignoring non Kotlin file: $relativePath") - null - } + + if (file.extension !in supportedExtensions) { + logger.debug("$name ignoring non Kotlin file: $relativePath") + return@forEach } - lintFunc?.invoke(file, ruleSets) { error -> + + ktLintEngine.lint(file.toPath()) { error -> hasError = true reporters.onEach { reporter -> // some reporters want relative paths, some want absolute @@ -72,24 +72,6 @@ abstract class LintWorkerAction : WorkAction { throw LintFailure("kotlin source failed lint check") } } - - private fun lintKt(file: File, ruleSets: Set, onError: (error: LintError) -> Unit) = - lint(file, ruleSets, onError, false) - - private fun lintKts(file: File, ruleSets: Set, onError: (error: LintError) -> Unit) = - lint(file, ruleSets, onError, true) - - private fun lint(file: File, ruleProviders: Set, onError: ErrorHandler, script: Boolean) = - KtLint.lint( - KtLint.ExperimentalParams( - fileName = file.path, - text = file.readText(), - ruleProviders = ruleProviders, - script = script, - editorConfigOverride = editorConfigOverride(ktLintParams), - cb = { error, _ -> onError(error) }, - ), - ) } -typealias ErrorHandler = (error: LintError) -> Unit +private val supportedExtensions = setOf("kt", "kts") 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 82b375b8..f060af66 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,7 +10,7 @@ import java.io.File interface LintWorkerParameters : WorkParameters { val name: Property - val changedEditorconfigFiles: ConfigurableFileCollection + val changedEditorConfigFiles: ConfigurableFileCollection 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 7e96c657..97912817 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt @@ -60,7 +60,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { // language=editorconfig """ [*.{kt,kts}] - ktlint_disabled_rules = filename + ktlint_standard_filename = disabled """.trimIndent(), ) } @@ -111,7 +111,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { // language=editorconfig """ [*.{kt,kts}] - ktlint_disabled_rules = filename + ktlint_standard_filename = disabled """.trimIndent(), ) } @@ -164,7 +164,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { // language=editorconfig """ [*.{kt,kts}] - ktlint_disabled_rules = filename + ktlint_standard_filename = disabled """.trimIndent(), ) } diff --git a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/ExtensionTest.kt b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/ExtensionTest.kt index 42521eda..607d0eac 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/ExtensionTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/ExtensionTest.kt @@ -84,7 +84,8 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { val script = """ kotlinter { - disabledRules = ["filename"] + experimentalRules = true + disabledRules = ["filename", "experimental:unnecessary-parentheses-before-trailing-lambda"] } """.trimIndent() appendText(script) @@ -92,6 +93,12 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { projectRoot.resolve("src/main/kotlin/FileName.kt") { writeText(kotlinClass("DifferentClassName")) } + projectRoot.resolve("src/main/kotlin/UnnecessaryParentheses.kt") { + writeText(""" + val failing = "should not have '()'".count() { it == 'x' } + + """.trimIndent()) + } build("lintKotlin").apply { assertEquals(TaskOutcome.SUCCESS, task(":lintKotlinMain")?.outcome) 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 f1d0deff..7b27cf04 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt @@ -55,6 +55,38 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { } } + @Test + fun `lintKotlinMain fails when lint errors for experimental rules are detected`() { + settingsFile() + buildFile() + + buildFile.appendText( + """ + + kotlinter { + experimentalRules = true + } + """.trimIndent(), + ) + + kotlinSourceFile( + "ExperimentalRuleViolations.kt", + """ + val variable = "should not contain '()'".count() { it == 'x' } + + """.trimIndent(), + ) + + buildAndFail("lintKotlinMain").apply { + assertTrue(output.contains(".*ExperimentalRuleViolation.kt.* Lint error > \\[.*] Empty parentheses \"\\{\"".toRegex())) + output.lines().filter { it.contains("Lint error") }.forEach { line -> + val filePath = pathPattern.find(line)?.groups?.get(1)?.value.orEmpty() + assertTrue(File(filePath).exists()) + } + assertEquals(FAILED, task(":lintKotlinMain")?.outcome) + } + } + @Test fun `lintKotlinMain succeeds when no lint errors detected`() { settingsFile() diff --git a/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt b/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt index 033989d3..a609c15c 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt @@ -1,12 +1,13 @@ package org.jmailen.gradle.kotlinter.support -import com.pinterest.ktlint.core.KtLint +import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.RuleProvider import com.pinterest.ktlint.core.RuleSetProviderV2 import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test +import java.io.File class RuleSetsTest { @@ -34,10 +35,11 @@ class RuleSetsTest { @Test fun `test compatibility`() { - KtLint.lint( - KtLint.ExperimentalParams( - fileName = "/tmp/src/test/KotlinClass.kt", - text = """ + KtLintRuleEngine( + ruleProviders = resolveRuleProviders(defaultRuleSetProviders), + ).lint( + filePath = File("/tmp/src/test/KotlinClass.kt").toPath(), + code = """ package test class KotlinClass { @@ -46,10 +48,8 @@ class RuleSetsTest { } } - """.trimIndent(), - ruleProviders = resolveRuleProviders(defaultRuleSetProviders), - cb = { _, _ -> }, - ), + """.trimIndent(), + callback = { _ -> }, ) } }