From 059252a4755f6deefaa547eb5723a2bf3e30807e Mon Sep 17 00:00:00 2001 From: wakingrufus Date: Tue, 22 Aug 2023 16:20:06 -0500 Subject: [PATCH] Allow editorconfig overrides in ktlint 0.49+ --- .../ktlint/worker/KtLintInvocation46.kt | 3 +- .../ktlint/worker/KtLintInvocation49.kt | 38 ++++++++++++++++-- .../ktlint/worker/KtLintInvocation50.kt | 39 +++++++++++++++++-- .../gradle/ktlint/Configurations.kt | 7 +--- .../gradle/ktlint/KtlintExtension.kt | 5 +++ .../jlleitschuh/gradle/ktlint/TaskCreation.kt | 1 + .../ktlint/tasks/BaseKtLintCheckTask.kt | 4 ++ .../gradle/ktlint/worker/KtLintWorkAction.kt | 11 +++++- .../ktlint/KtLintSupportedVersionsTest.kt | 38 ++++++++++++++++-- 9 files changed, 126 insertions(+), 20 deletions(-) diff --git a/plugin/src/adapter46/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation46.kt b/plugin/src/adapter46/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation46.kt index 19ff2ff8..802e7ac8 100644 --- a/plugin/src/adapter46/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation46.kt +++ b/plugin/src/adapter46/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation46.kt @@ -2,6 +2,7 @@ package org.jlleitschuh.gradle.ktlint.worker import com.pinterest.ktlint.core.KtLint import com.pinterest.ktlint.core.LintError +import com.pinterest.ktlint.core.RuleSet import com.pinterest.ktlint.core.RuleSetProvider import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties import com.pinterest.ktlint.core.api.EditorConfigOverride @@ -10,7 +11,7 @@ import java.util.ServiceLoader class KtLintInvocation46( private val editorConfigPath: String?, - private val ruleSets: Set, + private val ruleSets: Set, private val userData: Map, private val debug: Boolean ) : KtLintInvocation { diff --git a/plugin/src/adapter49/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation49.kt b/plugin/src/adapter49/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation49.kt index 28c5bd04..9e6ebbe6 100644 --- a/plugin/src/adapter49/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation49.kt +++ b/plugin/src/adapter49/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation49.kt @@ -2,9 +2,11 @@ package org.jlleitschuh.gradle.ktlint.worker import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 import com.pinterest.ktlint.rule.engine.api.Code +import com.pinterest.ktlint.rule.engine.api.EditorConfigOverride import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine import com.pinterest.ktlint.rule.engine.api.LintError import com.pinterest.ktlint.rule.engine.core.api.RuleProvider +import com.pinterest.ktlint.rule.engine.core.api.editorconfig.EditorConfigProperty import java.io.File import java.util.ServiceLoader @@ -12,10 +14,20 @@ class KtLintInvocation49( private val engine: KtLintRuleEngine ) : KtLintInvocation { companion object Factory : KtLintInvocationFactory { - fun initialize(): KtLintInvocation { - val engine = KtLintRuleEngine( - ruleProviders = loadRuleSetsFromClasspathWithRuleSetProviderV3() - ) + fun initialize( editorConfigOverrides: Map): KtLintInvocation { + val ruleProviders = loadRuleSetsFromClasspathWithRuleSetProviderV3() + val engine = if(editorConfigOverrides.isEmpty()){ + KtLintRuleEngine(ruleProviders = ruleProviders) + } else { + KtLintRuleEngine( + ruleProviders = ruleProviders, + editorConfigOverride = EditorConfigOverride.from(*editorConfigOverrides + .mapKeys { ruleProviders.findEditorConfigProperty(it.key) } + .entries + .map { it.key to it.value } + .toTypedArray()) + ) + } return KtLintInvocation49(engine) } @@ -52,3 +64,21 @@ class KtLintInvocation49( internal fun LintError.toSerializable(): SerializableLintError { return SerializableLintError(line, col, ruleId.value, detail, canBeAutoCorrected) } + +private fun Set.findEditorConfigProperty(propertyName: String): EditorConfigProperty<*> { + val properties = + map { it.createNewRuleInstance() } + .flatMap { it.usesEditorConfigProperties } + .distinct() + return properties + .find { it.type.name == propertyName } + ?: throw RuntimeException( + properties + .map { it.type.name } + .sorted() + .joinToString( + prefix = "Property with name '$propertyName' is not found in any of given rules. Available properties:\n\t", + separator = "\n\t", + ) { "- $it" }, + ) +} diff --git a/plugin/src/adapter50/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation50.kt b/plugin/src/adapter50/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation50.kt index eb505023..3079c439 100644 --- a/plugin/src/adapter50/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation50.kt +++ b/plugin/src/adapter50/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation50.kt @@ -2,9 +2,12 @@ package org.jlleitschuh.gradle.ktlint.worker import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 import com.pinterest.ktlint.rule.engine.api.Code +import com.pinterest.ktlint.rule.engine.api.EditorConfigOverride +import com.pinterest.ktlint.rule.engine.api.EditorConfigOverride.Companion.plus import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine import com.pinterest.ktlint.rule.engine.api.LintError import com.pinterest.ktlint.rule.engine.core.api.RuleProvider +import com.pinterest.ktlint.rule.engine.core.api.editorconfig.EditorConfigProperty import java.io.File import java.util.ServiceLoader @@ -12,10 +15,20 @@ class KtLintInvocation50( private val engine: KtLintRuleEngine ) : KtLintInvocation { companion object Factory : KtLintInvocationFactory { - fun initialize(): KtLintInvocation { - val engine = KtLintRuleEngine( - ruleProviders = loadRuleSetsFromClasspathWithRuleSetProviderV3() - ) + fun initialize( editorConfigOverrides: Map): KtLintInvocation { + val ruleProviders = loadRuleSetsFromClasspathWithRuleSetProviderV3() + val engine = if(editorConfigOverrides.isEmpty()){ + KtLintRuleEngine(ruleProviders = ruleProviders) + } else { + KtLintRuleEngine( + ruleProviders = ruleProviders, + editorConfigOverride = EditorConfigOverride.from(*editorConfigOverrides + .mapKeys { ruleProviders.findEditorConfigProperty(it.key) } + .entries + .map { it.key to it.value } + .toTypedArray()) + ) + } return KtLintInvocation50(engine) } @@ -52,3 +65,21 @@ class KtLintInvocation50( internal fun LintError.toSerializable(): SerializableLintError { return SerializableLintError(line, col, ruleId.value, detail, canBeAutoCorrected) } + +private fun Set.findEditorConfigProperty(propertyName: String): EditorConfigProperty<*> { + val properties = + map { it.createNewRuleInstance() } + .flatMap { it.usesEditorConfigProperties } + .distinct() + return properties + .find { it.type.name == propertyName } + ?: throw RuntimeException( + properties + .map { it.type.name } + .sorted() + .joinToString( + prefix = "Property with name '$propertyName' is not found in any of given rules. Available properties:\n\t", + separator = "\n\t", + ) { "- $it" }, + ) +} diff --git a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/Configurations.kt b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/Configurations.kt index c7ea296a..babb741d 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/Configurations.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/Configurations.kt @@ -39,16 +39,11 @@ internal fun createKtlintConfiguration(target: Project, extension: KtlintExtensi val dependencyProvider = target.provider { val ktlintVersion = extension.version.get() target.logger.info("Add dependency: ktlint version $ktlintVersion") - target.dependencies.create("${resolveGroup(ktlintVersion)}:ktlint:$ktlintVersion") + target.dependencies.create("com.pinterest:ktlint:$ktlintVersion") } dependencies.addLater(dependencyProvider) } -private fun resolveGroup(ktlintVersion: String) = when { - SemVer.parse(ktlintVersion) < SemVer(0, 32, 0) -> "com.github.shyiko" - else -> "com.pinterest" -} - internal fun createKtlintRulesetConfiguration( target: Project, ktLintConfiguration: Configuration diff --git a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtlintExtension.kt b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtlintExtension.kt index 36fe4d3e..f45d8773 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtlintExtension.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtlintExtension.kt @@ -7,6 +7,7 @@ import org.gradle.api.file.ConfigurableFileTree import org.gradle.api.file.ProjectLayout import org.gradle.api.file.RegularFileProperty import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.util.PatternFilterable @@ -107,6 +108,10 @@ internal constructor( */ @Deprecated("not supported with ktlint 0.47+") val additionalEditorconfigFile: RegularFileProperty = objectFactory.fileProperty() + val additionalEditorconfig: MapProperty = + objectFactory.mapProperty(String::class.java, String::class.java).apply { + convention(emptyMap()) + } /** * Disable particular rules, by default enabled in ktlint, using rule id. diff --git a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/TaskCreation.kt b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/TaskCreation.kt index 0fed6554..1fc92109 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/TaskCreation.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/TaskCreation.kt @@ -131,6 +131,7 @@ private fun BaseKtLintCheckTask.configureBaseCheckTask( ktLintClasspath.setFrom(pluginHolder.ktlintConfiguration) ktLintVersion.set(pluginHolder.extension.version) additionalEditorconfigFile.set(pluginHolder.extension.additionalEditorconfigFile) + additionalEditorconfig.set(pluginHolder.extension.additionalEditorconfig) debug.set(pluginHolder.extension.debug) ruleSetsClasspath.setFrom(pluginHolder.ktlintRulesetConfiguration) android.set(pluginHolder.extension.android) diff --git a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/tasks/BaseKtLintCheckTask.kt b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/tasks/BaseKtLintCheckTask.kt index 7871cf78..3d28f485 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/tasks/BaseKtLintCheckTask.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/tasks/BaseKtLintCheckTask.kt @@ -12,6 +12,7 @@ import org.gradle.api.file.FileType import org.gradle.api.file.ProjectLayout import org.gradle.api.file.RegularFileProperty import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty import org.gradle.api.specs.Spec @@ -55,6 +56,8 @@ abstract class BaseKtLintCheckTask @Inject constructor( @get:Internal internal abstract val additionalEditorconfigFile: RegularFileProperty + @get:Internal + internal abstract val additionalEditorconfig: MapProperty @get:Incremental @get:PathSensitive(PathSensitivity.RELATIVE) @@ -285,6 +288,7 @@ abstract class BaseKtLintCheckTask @Inject constructor( params.disabledRules.set(disabledRules) params.debug.set(debug) params.additionalEditorconfigFile.set(additionalEditorconfigFile) + params.additionalEditorconfig.set(additionalEditorconfig) params.formatSource.set(formatSources) params.discoveredErrorsFile.set(discoveredErrors) params.ktLintVersion.set(ktLintVersion) diff --git a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintWorkAction.kt b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintWorkAction.kt index ec905088..4aa10255 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintWorkAction.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintWorkAction.kt @@ -6,6 +6,7 @@ import org.gradle.api.GradleException import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.RegularFileProperty import org.gradle.api.logging.Logging +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty import org.gradle.workers.WorkAction @@ -38,6 +39,11 @@ abstract class KtLintWorkAction : WorkAction { - ktlintInvokerFactory.initialize() + ktlintInvokerFactory.initialize(parameters.additionalEditorconfig.get()) } is KtLintInvocation50.Factory -> { - ktlintInvokerFactory.initialize() + ktlintInvokerFactory.initialize(parameters.additionalEditorconfig.get()) } else -> { throw GradleException("Incompatible ktlint version ${parameters.ktLintVersion}") @@ -161,6 +167,7 @@ abstract class KtLintWorkAction : WorkAction val debug: Property val additionalEditorconfigFile: RegularFileProperty + val additionalEditorconfig: MapProperty val formatSource: Property val discoveredErrorsFile: RegularFileProperty val ktLintVersion: Property diff --git a/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/KtLintSupportedVersionsTest.kt b/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/KtLintSupportedVersionsTest.kt index 05a49739..7eadc77c 100644 --- a/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/KtLintSupportedVersionsTest.kt +++ b/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/KtLintSupportedVersionsTest.kt @@ -72,10 +72,10 @@ class KtLintSupportedVersionsTest : AbstractPluginTest() { } } - @DisplayName("Lint should use editorconfig override") + @DisplayName("Lint should use editorconfig file override") @ParameterizedTest(name = "{0} with KtLint {1}: {displayName}") @ArgumentsSource(SupportedKtlintVersionsProvider::class) - internal fun `Lint should use editorconfig override`( + internal fun `Lint should use editorconfig file override`( gradleVersion: GradleVersion, ktLintVersion: String ) { @@ -93,7 +93,39 @@ class KtLintSupportedVersionsTest : AbstractPluginTest() { if (SemVer.parse(ktLintVersion) >= SemVer(0, 47)) { buildAndFail(CHECK_PARENT_TASK_NAME) { assertThat(task(":$mainSourceSetCheckTaskName")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output.contains("additionalEditorconfigFile no longer supported in ktlint 0.47+")) + assertThat(output).contains("additionalEditorconfigFile no longer supported in ktlint 0.47+") + } + } else { + build(CHECK_PARENT_TASK_NAME) { + assertThat(task(":$mainSourceSetCheckTaskName")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + } + } + } + } + + @DisplayName("Lint should use editorconfig override") + @ParameterizedTest(name = "{0} with KtLint {1}: {displayName}") + @ArgumentsSource(SupportedKtlintVersionsProvider::class) + internal fun `Lint should use editorconfig override`( + gradleVersion: GradleVersion, + ktLintVersion: String + ) { + project(gradleVersion) { + //language=Groovy + buildGradle.appendText( + """ + + ktlint.version = "$ktLintVersion" + ktlint.additionalEditorconfig = [ + "ktlint_standard_no-multi-spaces": "disabled" + ] + """.trimIndent() + ) + withFailingSources() + if (SemVer.parse(ktLintVersion) < SemVer(0, 49)) { + buildAndFail(CHECK_PARENT_TASK_NAME) { + assertThat(task(":$mainSourceSetCheckTaskName")?.outcome).isEqualTo(TaskOutcome.FAILED) + assertThat(output).contains("additionalEditorconfig not supported until ktlint 0.49") } } else { build(CHECK_PARENT_TASK_NAME) {