diff --git a/CHANGELOG.md b/CHANGELOG.md index 151c332e..0b02f7fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- ktlint 1.0 support [#708](https://github.com/JLLeitschuh/ktlint-gradle/pull/708) +- Allow editorconfig overrides in ktlint 0.49+ [#708](https://github.com/JLLeitschuh/ktlint-gradle/pull/708) - update latest version text file manually [#700](https://github.com/JLLeitschuh/ktlint-gradle/pull/700) ## [11.5.1] - 2023-08-07 diff --git a/README.md b/README.md index 077028e9..0a2c1654 100644 --- a/README.md +++ b/README.md @@ -271,6 +271,8 @@ object will be used. The version of ktlint used by default _may change_ between patch versions of this plugin. If you don't want to inherit these changes then make sure you lock your version here. +Consult the [ktlint release notes](https://github.com/pinterest/ktlint/releases) for more information about the differences between ktlint versions. +
Groovy @@ -287,6 +289,9 @@ ktlint { ignoreFailures = true enableExperimentalRules = true additionalEditorconfigFile = file("/some/additional/.editorconfig") // not supported with ktlint 0.47+ + additionalEditorconfig = [ // not supported until ktlint 0.49 + "max_line_length": "20" + ] disabledRules = ["final-newline"] // not supported with ktlint 0.48+ baseline = file("my-project-ktlint-baseline.xml") reporters { @@ -339,6 +344,11 @@ configure { ignoreFailures.set(true) enableExperimentalRules.set(true) additionalEditorconfigFile.set(file("/some/additional/.editorconfig")) // not supported with ktlint 0.47+ + additionalEditorconfig.set( // not supported until ktlint 0.49 + mapOf( + "max_line_length" to "20" + ) + ) disabledRules.set(setOf("final-newline")) // not supported with ktlint 0.48+ baseline.set(file("my-project-ktlint-baseline.xml")) reporters { diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 6b155721..f994340f 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -88,6 +88,9 @@ sourceSets { val adapter50 by creating { compileClasspath += adapter.output } + val adapter100 by creating { + compileClasspath += adapter.output + } val adapters = listOf( adapter, adapter34, @@ -97,7 +100,8 @@ sourceSets { adapter47, adapter48, adapter49, - adapter50 + adapter50, + adapter100 ) val main by getting { kotlin { @@ -121,7 +125,8 @@ val adapterSources = listOf( sourceSets.named("adapter47"), sourceSets.named("adapter48"), sourceSets.named("adapter49"), - sourceSets.named("adapter50") + sourceSets.named("adapter50"), + sourceSets.named("adapter100") ) tasks.named("shadowJar") { this.from(adapterSources.map { sourceSet -> sourceSet.map { it.output.classesDirs } }) @@ -159,6 +164,11 @@ dependencies { add("adapter50CompileOnly", "com.pinterest.ktlint:ktlint-ruleset-standard:0.50.0") add("adapter50CompileOnly", "com.pinterest.ktlint:ktlint-reporter-baseline:0.50.0") + add("adapter100CompileOnly", "com.pinterest.ktlint:ktlint-cli-reporter-core:1.0.0") + add("adapter100CompileOnly", "com.pinterest.ktlint:ktlint-rule-engine:1.0.0") + add("adapter100CompileOnly", "com.pinterest.ktlint:ktlint-ruleset-standard:1.0.0") + add("adapter100CompileOnly", "com.pinterest.ktlint:ktlint-cli-reporter-baseline:1.0.0") + compileOnly(libs.kotlin.gradle.plugin) compileOnly(libs.android.gradle.plugin) compileOnly(kotlin("stdlib-jdk8")) diff --git a/plugin/settings.gradle.kts b/plugin/settings.gradle.kts index ed652bc2..8325a104 100644 --- a/plugin/settings.gradle.kts +++ b/plugin/settings.gradle.kts @@ -2,7 +2,7 @@ pluginManagement { val latestRelease = file("VERSION_LATEST_RELEASE.txt").readText().trim() plugins { id("org.jlleitschuh.gradle.ktlint") version latestRelease - id("org.jetbrains.kotlin.jvm") version "1.7.21" + id("org.jetbrains.kotlin.jvm") version "1.9.0" id("com.gradle.plugin-publish") version "0.15.0" `java-gradle-plugin` `maven-publish` diff --git a/plugin/src/adapter100/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation100.kt b/plugin/src/adapter100/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation100.kt new file mode 100644 index 00000000..d3b60c6f --- /dev/null +++ b/plugin/src/adapter100/kotlin/org/jlleitschuh/gradle/ktlint/worker/KtLintInvocation100.kt @@ -0,0 +1,69 @@ +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.EditorConfigPropertyRegistry +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 java.io.File +import java.util.ServiceLoader + +class KtLintInvocation100( + private val engine: KtLintRuleEngine +) : KtLintInvocation { + companion object Factory : KtLintInvocationFactory { + fun initialize(editorConfigOverrides: Map): KtLintInvocation { + val ruleProviders = loadRuleSetsFromClasspathWithRuleSetProviderV3() + val editorConfigPropertyRegistry = EditorConfigPropertyRegistry(ruleProviders) + val engine = if (editorConfigOverrides.isEmpty()) { + KtLintRuleEngine(ruleProviders = ruleProviders) + } else { + KtLintRuleEngine( + ruleProviders = ruleProviders, + editorConfigOverride = EditorConfigOverride.from( + *editorConfigOverrides + .mapKeys { editorConfigPropertyRegistry.find(it.key) } + .entries + .map { it.key to it.value } + .toTypedArray() + ) + ) + } + return KtLintInvocation100(engine) + } + + private fun loadRuleSetsFromClasspathWithRuleSetProviderV3(): Set { + return ServiceLoader + .load(RuleSetProviderV3::class.java) + .flatMap { it.getRuleProviders() } + .toSet() + } + } + + override fun invokeLint(file: File): LintErrorResult { + val errors = mutableListOf>() + engine.lint(Code.fromFile(file)) { le: LintError -> + errors.add(le.toSerializable() to false) + } + return LintErrorResult(file, errors) + } + + override fun invokeFormat(file: File): Pair { + val errors = mutableListOf>() + val newCode = + engine.format(Code.fromFile(file)) { le, boolean -> + errors.add(le.toSerializable() to boolean) + } + return newCode to LintErrorResult(file, errors) + } + + override fun trimMemory() { + engine.trimMemory() + } +} + +internal fun LintError.toSerializable(): SerializableLintError { + return SerializableLintError(line, col, ruleId.value, detail, canBeAutoCorrected) +} 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..c84b9340 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,22 @@ 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 +66,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..f98bf2e0 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,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,22 @@ 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 +66,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..e1baf3cf 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/Configurations.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/Configurations.kt @@ -3,6 +3,7 @@ package org.jlleitschuh.gradle.ktlint import net.swiftzer.semver.SemVer import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.artifacts.component.ModuleComponentSelector import org.gradle.api.artifacts.component.ProjectComponentIdentifier @@ -36,22 +37,31 @@ internal fun createKtlintConfiguration(target: Project, extension: KtlintExtensi it.attribute(Bundling.BUNDLING_ATTRIBUTE, target.objects.named(Bundling::class.java, Bundling.EXTERNAL)) } - val dependencyProvider = target.provider { - val ktlintVersion = extension.version.get() - target.logger.info("Add dependency: ktlint version $ktlintVersion") - target.dependencies.create("${resolveGroup(ktlintVersion)}:ktlint:$ktlintVersion") - } - dependencies.addLater(dependencyProvider) + // Workaround for gradle 6 https://github.com/gradle/gradle/issues/13255 + val oldProp = target.objects.listProperty(Dependency::class.java) + dependencies.addAllLater( + oldProp.value( + extension.version.map { + if (SemVer.parse(it) < SemVer(1, 0, 0)) { + target.logger.info("Add dependency: ktlint version $it") + listOf(target.dependencies.create("com.pinterest:ktlint:$it")) + } else { + target.logger.info("Add dependencies: ktlint version $it") + listOf( + target.dependencies.create("com.pinterest.ktlint:ktlint-cli:$it"), + // this transitive dep was introduced in ktlint 1.0, but for some reason, it is not picked up automatically + target.dependencies.create("io.github.oshai:kotlin-logging:5.1.0") + ) + } + } + ) + ) } -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 + ktLintConfiguration: Configuration, + extension: KtlintExtension ): Configuration = target .configurations.maybeCreate(KTLINT_RULESET_CONFIGURATION_NAME).apply { description = KTLINT_RULESET_CONFIGURATION_DESCRIPTION @@ -61,6 +71,12 @@ internal fun createKtlintRulesetConfiguration( isVisible = false ensureConsistencyWith(target, ktLintConfiguration) + dependencies.addLater( + target.provider { + val ktlintVersion = extension.version.get() + target.dependencies.create("com.pinterest.ktlint:ktlint-ruleset-standard:$ktlintVersion") + } + ) } internal fun createKtLintReporterConfiguration( @@ -95,6 +111,21 @@ internal fun createKtLintReporterConfiguration( ) } } + + // Workaround for gradle 6 https://github.com/gradle/gradle/issues/13255 + val oldProp = target.objects.listProperty(Dependency::class.java) + dependencies.addAllLater( + oldProp.value( + extension.version.map { version -> + if (SemVer.parse(version) >= SemVer(1, 0, 0)) { + // this transitive dep was introduced in ktlint 1.0, but for some reason, it is not picked up automatically + listOf(target.dependencies.create("io.github.oshai:kotlin-logging:5.1.0")) + } else { + listOf() + } + } + ) + ) } internal fun createKtLintBaselineReporterConfiguration( @@ -113,25 +144,33 @@ internal fun createKtLintBaselineReporterConfiguration( ensureConsistencyWith(target, ktLintConfiguration) - withDependencies { - dependencies.addLater( - target.provider { + // withDependencies { + // Workaround for gradle 6 https://github.com/gradle/gradle/issues/13255 + val oldProp = target.objects.listProperty(Dependency::class.java) + dependencies.addAllLater( + oldProp.value( + extension.version.map { version -> val ktlintVersion = extension.version.get() - // Baseline reporter is only available starting 0.41.0 release - if (SemVer.parse(ktlintVersion) >= SemVer(0, 41, 0)) { - target.dependencies.create( - "com.pinterest.ktlint:ktlint-reporter-baseline:${extension.version.get()}" + val ktlintSemver = SemVer.parse(ktlintVersion) + if (ktlintSemver >= SemVer(1, 0, 0)) { + // Baseline reporter maven coordinates changed in 1.0 + listOf( + target.dependencies.create("com.pinterest.ktlint:ktlint-cli-reporter-baseline:$version"), + // this transitive dep was introduced in ktlint 1.0, but for some reason, it is not picked up automatically + target.dependencies.create("io.github.oshai:kotlin-logging:5.1.0") ) + } else if (SemVer.parse(ktlintVersion) >= SemVer(0, 41, 0)) { + // Baseline reporter is only available starting 0.41.0 release + listOf(target.dependencies.create("com.pinterest.ktlint:ktlint-reporter-baseline:$version")) } else { // Adding fake plain reporter as addLater() does not accept `null` value // Generate baseline tasks anyway will not run on KtLint versions < 0.41.0 - target.dependencies.create( - "com.pinterest.ktlint:ktlint-reporter-plain:${extension.version.get()}" - ) + listOf(target.dependencies.create("com.pinterest.ktlint:ktlint-reporter-plain:$version")) } } ) - } + ) + // } } private fun Configuration.ensureConsistencyWith( diff --git a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtLintCompatibility.kt b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtLintCompatibility.kt index 609221f4..889a31b9 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtLintCompatibility.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtLintCompatibility.kt @@ -12,6 +12,7 @@ import org.jlleitschuh.gradle.ktlint.worker.BaselineLoader46 import org.jlleitschuh.gradle.ktlint.worker.BaselineLoader47 import org.jlleitschuh.gradle.ktlint.worker.BaselineLoader48 import org.jlleitschuh.gradle.ktlint.worker.BaselineLoader49 +import org.jlleitschuh.gradle.ktlint.worker.KtLintInvocation100 import org.jlleitschuh.gradle.ktlint.worker.KtLintInvocation45 import org.jlleitschuh.gradle.ktlint.worker.KtLintInvocation46 import org.jlleitschuh.gradle.ktlint.worker.KtLintInvocation47 @@ -38,7 +39,7 @@ internal fun selectInvocation(version: String): KtLintInvocationFactory { KtLintInvocation50 } } else { - KtLintInvocation50 + KtLintInvocation100 } } 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..4b2a147a 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,11 @@ 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/KtlintPlugin.kt b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtlintPlugin.kt index 2daeb194..626b22a5 100644 --- a/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtlintPlugin.kt +++ b/plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/KtlintPlugin.kt @@ -165,7 +165,11 @@ open class KtlintPlugin : Plugin { } val ktlintConfiguration: Configuration = createKtlintConfiguration(target, extension) - val ktlintRulesetConfiguration: Configuration = createKtlintRulesetConfiguration(target, ktlintConfiguration) + val ktlintRulesetConfiguration: Configuration = createKtlintRulesetConfiguration( + target, + ktlintConfiguration, + extension + ) val ktlintReporterConfiguration: Configuration = createKtLintReporterConfiguration(target, extension, ktlintConfiguration) val ktlintBaselineReporterConfiguration: Configuration = createKtLintBaselineReporterConfiguration( target, 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..96f87e10 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 @@ -56,6 +57,9 @@ 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) @get:InputFiles @@ -285,6 +289,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..a22d60e9 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()) } + + is KtLintInvocation100.Factory -> { + ktlintInvokerFactory.initialize(parameters.additionalEditorconfig.get()) + } + else -> { throw GradleException("Incompatible ktlint version ${parameters.ktLintVersion}") } @@ -161,6 +172,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..25c115a7 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,48 @@ 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 (standard rule)") + @ParameterizedTest(name = "{0} with KtLint {1}: {displayName}") + @ArgumentsSource(SupportedKtlintVersionsProvider::class) + internal fun `Lint should use editorconfig override standard rule`( + 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, 0)) { + buildAndFail(CHECK_PARENT_TASK_NAME) { + assertThat(task(":$mainSourceSetCheckTaskName")?.outcome) + .`as`("additionalEditorconfig not supported until ktlint 0.49") + .isEqualTo(TaskOutcome.FAILED) + assertThat(output).contains("additionalEditorconfig not supported until ktlint 0.49") + } + } else if (SemVer.parse(ktLintVersion) < SemVer(1, 0)) { + buildAndFail(CHECK_PARENT_TASK_NAME) { + assertThat(task(":runKtlintCheckOverMainSourceSet")?.outcome) + .`as`("standard rules not supported by additionalEditorconfig until 1.0") + .isEqualTo(TaskOutcome.FAILED) + assertThat(output) + .contains("Property with name 'ktlint_standard_no-multi-spaces' is not found") } } else { build(CHECK_PARENT_TASK_NAME) { @@ -103,6 +144,42 @@ class KtLintSupportedVersionsTest : AbstractPluginTest() { } } + @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 = [ + "max_line_length": "20" + ] + """.trimIndent() + ) + withFailingMaxLineSources() + if (SemVer.parse(ktLintVersion) < SemVer(0, 49)) { + build(CHECK_PARENT_TASK_NAME) { + assertThat(task(":$mainSourceSetCheckTaskName")?.outcome).isEqualTo(TaskOutcome.SUCCESS) + assertThat(output).contains("additionalEditorconfig not supported until ktlint 0.49") + } + } else { + buildAndFail(CHECK_PARENT_TASK_NAME) { + assertThat(task(":$mainSourceSetCheckTaskName")?.outcome) + .`as`("additionalEditorconfig takes effect") + .isEqualTo(TaskOutcome.FAILED) + assertThat(output).doesNotContain("additionalEditorconfig not supported until ktlint 0.49") + assertThat(output).contains("Exceeded max line length (20) (cannot be auto-corrected)") + } + } + } + } + @DisplayName("Format should successfully finish on sources with style violations") @ParameterizedTest(name = "{0} with KtLint {1}: {displayName}") @ArgumentsSource(SupportedKtlintVersionsProvider::class) @@ -154,7 +231,8 @@ class KtLintSupportedVersionsTest : AbstractPluginTest() { "0.48.2", // "0.49.0" did not expose needed baseline classes "0.49.1", - "0.50.0" + "0.50.0", + "1.0.0" ).also { // "0.37.0" is failing on Windows machines that is fixed in the next version if (!OS.WINDOWS.isCurrentOs) it.add("0.37.0") diff --git a/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/testdsl/TestDsl.kt b/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/testdsl/TestDsl.kt index 97c2ae80..a4ec48f0 100644 --- a/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/testdsl/TestDsl.kt +++ b/plugin/src/test/kotlin/org/jlleitschuh/gradle/ktlint/testdsl/TestDsl.kt @@ -59,6 +59,18 @@ class TestProject( ) } + fun withFailingMaxLineSources() { + createSourceFile( + FAIL_SOURCE_FILE, + buildString { + append("val nameOfVariable =") + append("\n") + append(" listOf(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2)") + append("\n") + } + ) + } + fun withAdditionalEditorConfig() { createSourceFile( ADDITIONAL_EDITOR_CONFIG + "/.editorconfig",