diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 85491eb..228304e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,13 +5,16 @@ gradle-doctor = "0.8.1" google-agp = "8.0.1" maven-junit = "5.9.3" maven-assertj = "3.24.2" -maven-ktlint = "0.48.2" +maven-ktlint = "0.49.1" maven-commons = "2.11.0" [libraries] agp-gradle = { module = "com.android.tools.build:gradle", version.ref = "google-agp" } kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin" } -ktlint-core = { module = "com.pinterest.ktlint:ktlint-core", version.ref = "maven-ktlint" } +ktlint-rule-engine = { module = "com.pinterest.ktlint:ktlint-rule-engine", version.ref = "maven-ktlint" } +ktlint-cli-ruleset-core = { module = "com.pinterest.ktlint:ktlint-cli-ruleset-core", version.ref = "maven-ktlint" } +ktlint-cli-reporter = { module = "com.pinterest.ktlint:ktlint-cli-reporter", version.ref = "maven-ktlint" } +ktlint-reporter-baseline = { module = "com.pinterest.ktlint:ktlint-reporter-baseline", version.ref = "maven-ktlint" } junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "maven-junit" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "maven-junit" } assertj-core = { module = "org.assertj:assertj-core", version.ref = "maven-assertj" } diff --git a/ktlint-gradle-plugin/build.gradle b/ktlint-gradle-plugin/build.gradle index 7488422..1dac4a1 100644 --- a/ktlint-gradle-plugin/build.gradle +++ b/ktlint-gradle-plugin/build.gradle @@ -12,7 +12,6 @@ description = "Lint and formatting for Kotlin using ktlint with configuration-fr configurations { register("testRuntimeDependencies") { - extendsFrom(compileOnly) attributes { // KGP publishes multiple variants https://kotlinlang.org/docs/whatsnew17.html#support-for-gradle-plugin-variants attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.class, Usage.JAVA_RUNTIME)) @@ -32,12 +31,19 @@ configurations { dependencies { compileOnly(libs.kotlin.gradle) compileOnly(libs.agp.gradle) - compileOnly(libs.ktlint.core) + compileOnly(libs.ktlint.rule.engine) + compileOnly(libs.ktlint.cli.ruleset.core) + compileOnly(libs.ktlint.cli.reporter) + compileOnly(libs.ktlint.reporter.baseline) testRuntimeOnly(libs.junit.jupiter.engine) + testImplementation(libs.junit.jupiter.api) testImplementation(libs.commons.io) testImplementation(libs.assertj.core) + + testRuntimeDependencies(libs.kotlin.gradle) + testRuntimeDependencies(libs.agp.gradle) } kotlin { diff --git a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/BaselineUtils.kt b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/BaselineUtils.kt index 9c14a4c..fdb36c7 100644 --- a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/BaselineUtils.kt +++ b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/BaselineUtils.kt @@ -1,31 +1,22 @@ package io.github.usefulness.support -import com.pinterest.ktlint.core.LintError -import com.pinterest.ktlint.core.api.Baseline -import com.pinterest.ktlint.core.api.loadBaseline +import com.pinterest.ktlint.cli.reporter.baseline.Baseline +import com.pinterest.ktlint.cli.reporter.baseline.loadBaseline +import com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError import java.io.File -internal fun File.readKtlintBaseline(): Map>? { +internal fun File.readKtlintBaseline(): Map>? { val baseline = loadBaseline(absolutePath) when (baseline.status) { Baseline.Status.VALID -> Unit Baseline.Status.NOT_FOUND, Baseline.Status.INVALID, + Baseline.Status.DISABLED, -> return null - } + }.let { } return baseline.lintErrorsPerFile } internal fun File.getBaselineKey(projectDir: File) = toRelativeString(projectDir).replace(File.separatorChar, '/') - -/** - * Same as ktlint, avoids unnecessary incompatibility issues - */ -internal fun List.doesNotContain(lintError: LintError) = - none { - it.col == lintError.col && - it.line == lintError.line && - it.ruleId == lintError.ruleId - } diff --git a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/EditorConfigUtils.kt b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/EditorConfigUtils.kt index 74f019e..7ad1515 100644 --- a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/EditorConfigUtils.kt +++ b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/EditorConfigUtils.kt @@ -1,8 +1,8 @@ package io.github.usefulness.support -import com.pinterest.ktlint.core.api.EditorConfigDefaults -import com.pinterest.ktlint.core.api.EditorConfigOverride -import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.rule.engine.api.EditorConfigDefaults +import com.pinterest.ktlint.rule.engine.api.EditorConfigOverride +import com.pinterest.ktlint.rule.engine.core.api.editorconfig.EditorConfigProperty import org.ec4j.core.model.EditorConfig import org.ec4j.core.model.Glob import org.ec4j.core.model.Property diff --git a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintEngineUtils.kt b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintEngineUtils.kt index 652f2ca..9c604a4 100644 --- a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintEngineUtils.kt +++ b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintEngineUtils.kt @@ -1,9 +1,9 @@ package io.github.usefulness.support -import com.pinterest.ktlint.core.KtLintRuleEngine import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.logging.Logger import java.io.File +import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine internal fun createKtlintEngine( disabledRules: List, diff --git a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintErrorResult.kt b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintErrorResult.kt index 87a2784..0dc34b8 100644 --- a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintErrorResult.kt +++ b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/KtlintErrorResult.kt @@ -1,16 +1,16 @@ package io.github.usefulness.support -import com.pinterest.ktlint.core.LintError +import com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError import java.io.File import java.io.Serializable internal data class KtlintErrorResult( val file: File, - val errors: List>, + val errors: List, ) : Serializable { companion object { - const val serialVersionUID = 1L + const val serialVersionUID = 2L } } diff --git a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/ReporterType.kt b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/ReporterType.kt index 59ee5c4..0f1ec45 100644 --- a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/ReporterType.kt +++ b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/ReporterType.kt @@ -1,7 +1,7 @@ package io.github.usefulness.support -import com.pinterest.ktlint.core.Reporter -import com.pinterest.ktlint.core.ReporterProvider +import com.pinterest.ktlint.cli.reporter.core.api.ReporterV2 +import com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2 import java.io.File import java.io.PrintStream import java.util.ServiceLoader @@ -33,7 +33,7 @@ internal fun reporterPathFor(reporterType: ReporterType, output: File, relativeR internal fun resolveReporters( enabled: Map, -): Map { +): Map { val allReporterProviders = defaultReporters().associateBy { it.id } return enabled @@ -56,5 +56,5 @@ private fun ReporterType.generateOpt() = when (this) { ReporterType.Plain -> mapOf("color_name" to "DARK_GRAY") } -private fun defaultReporters(): List> = - ServiceLoader.load(ReporterProvider::class.java).toList() +private fun defaultReporters(): List> = + ServiceLoader.load(ReporterProviderV2::class.java).toList() diff --git a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/RuleSets.kt b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/RuleSets.kt index 99912e9..8bcdfe3 100644 --- a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/RuleSets.kt +++ b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/support/RuleSets.kt @@ -1,25 +1,26 @@ package io.github.usefulness.support -import com.pinterest.ktlint.core.RuleProvider -import com.pinterest.ktlint.core.RuleSetProviderV2 +import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 +import com.pinterest.ktlint.rule.engine.core.api.RuleProvider +import com.pinterest.ktlint.rule.engine.core.api.RuleSetId import java.util.ServiceLoader internal fun resolveRuleProviders( - providers: Iterable, + providers: Iterable, ): Set = providers .asSequence() .sortedWith( compareBy { - when (it.id) { - "standard" -> 0 + when (it.id.value) { + RuleSetId.STANDARD.value -> 0 else -> 1 } }, ) - .map(RuleSetProviderV2::getRuleProviders) + .map(RuleSetProviderV3::getRuleProviders) .flatten() .toSet() // statically resolve providers from plugin classpath. ServiceLoader#load alone resolves classes lazily which fails when run in parallel -internal val defaultRuleSetProviders: List = - ServiceLoader.load(RuleSetProviderV2::class.java).toList() +internal val defaultRuleSetProviders: List = + ServiceLoader.load(RuleSetProviderV3::class.java).toList() diff --git a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/tasks/workers/ConsoleReportWorker.kt b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/tasks/workers/ConsoleReportWorker.kt index 6d56cc9..0058de3 100644 --- a/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/tasks/workers/ConsoleReportWorker.kt +++ b/ktlint-gradle-plugin/src/main/kotlin/io/github/usefulness/tasks/workers/ConsoleReportWorker.kt @@ -1,8 +1,9 @@ package io.github.usefulness.tasks.workers -import com.pinterest.ktlint.core.LintError +import com.pinterest.ktlint.cli.reporter.baseline.doesNotContain +import com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError +import com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError.Status import io.github.usefulness.support.KtlintRunMode -import io.github.usefulness.support.doesNotContain import io.github.usefulness.support.getBaselineKey import io.github.usefulness.support.readKtlintBaseline import io.github.usefulness.support.readKtlintErrors @@ -29,7 +30,7 @@ internal abstract class ConsoleReportWorker : WorkAction val baselineErrors = baselineContent[file.getBaselineKey(projectDir)].orEmpty() - errors.forEach { (lintError, corrected) -> + errors.forEach { lintError -> when (mode) { KtlintRunMode.Check -> if (baselineErrors.doesNotContain(lintError)) { @@ -38,13 +39,21 @@ internal abstract class ConsoleReportWorker : WorkAction { - when (corrected) { - true -> logger.quiet(lintError.generateMessage(file = file, message = "Format fixed")) - false -> { + when (lintError.status) { + Status.BASELINE_IGNORED -> Unit + Status.LINT_CAN_NOT_BE_AUTOCORRECTED -> { hasUncoveredErrors = true logger.warn(lintError.generateMessage(file = file, message = "Format could not fix")) } - } + + Status.FORMAT_IS_AUTOCORRECTED -> logger.quiet(lintError.generateMessage(file = file, message = "Format fixed")) + Status.LINT_CAN_BE_AUTOCORRECTED, + Status.KOTLIN_PARSE_EXCEPTION, + Status.KTLINT_RULE_ENGINE_EXCEPTION, + -> logger.warn( + lintError.generateMessage(file = file, message = "Internal exception status=${lintError.status}"), + ) + }.let { } } } } @@ -59,7 +68,7 @@ internal abstract class ConsoleReportWorker : WorkAction reporter.before(relativePath) } reporters.onEach { (type, reporter) -> - result.errors.forEach { (lintError, corrected) -> + result.errors.forEach { lintError -> if (baselineErrors.doesNotContain(lintError)) { // some reporters want relative paths, some want absolute val filePath = reporterPathFor( @@ -45,7 +45,7 @@ internal abstract class GenerateReportsWorker : WorkAction { private val logger = DefaultContextAwareTaskLogger(Logging.getLogger(KtlintWorker::class.java)) @@ -36,7 +39,9 @@ internal abstract class KtlintWorker : WorkAction { logger.info("$name - resolved ${ktLintEngine.ruleProviders.size} RuleProviders") logger.info("$name - executing against ${files.count()} file(s)") if (logger.isDebugEnabled) { - logger.debug("Resolved RuleSetProviders = ${ktLintEngine.ruleProviders.joinToString { it.createNewRuleInstance().id }}") + logger.debug( + "Resolved RuleSetProviders = ${ktLintEngine.ruleProviders.joinToString { it.createNewRuleInstance().ruleId.value }}", + ) } val errors = mutableListOf() @@ -50,24 +55,24 @@ internal abstract class KtlintWorker : WorkAction { return@forEach } - val fileErrors = mutableListOf>() + val fileErrors = mutableListOf() when (parameters.mode.get()) { KtlintRunMode.Check, null, -> ktLintEngine.lint( - code = Code.CodeFile(file), - callback = { fileErrors.add(it to false) }, + code = Code.fromFile(file), + callback = { fileErrors.add(it.toKtlintCliErrorForLint()) }, ) KtlintRunMode.Format -> { var fileFixed = false val fixedContent = ktLintEngine.format( - code = Code.CodeFile(file), + code = Code.fromFile(file), callback = { error, corrected -> if (corrected) { fileFixed = true } - fileErrors.add(error to corrected) + fileErrors.add(error.toKtlintCliErrorForFormat(corrected)) }, ) @@ -99,4 +104,28 @@ internal abstract class KtlintWorker : WorkAction { } } +private fun LintError.toKtlintCliErrorForLint() = KtlintCliError( + line = line, + col = col, + ruleId = ruleId.value, + detail = detail, + status = if (canBeAutoCorrected) { + Status.LINT_CAN_BE_AUTOCORRECTED + } else { + Status.LINT_CAN_NOT_BE_AUTOCORRECTED + }, +) + +private fun LintError.toKtlintCliErrorForFormat(corrected: Boolean): KtlintCliError = KtlintCliError( + line = line, + col = col, + ruleId = ruleId.value, + detail = detail.applyIf(corrected) { "$this (cannot be auto-corrected)" }, + status = if (corrected) { + Status.FORMAT_IS_AUTOCORRECTED + } else { + Status.LINT_CAN_NOT_BE_AUTOCORRECTED + }, +) + private val supportedExtensions = setOf("kt", "kts") diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/AndroidProjectTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/AndroidProjectTest.kt index 48b2e76..27ccabf 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/AndroidProjectTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/AndroidProjectTest.kt @@ -44,7 +44,7 @@ internal class AndroidProjectTest : WithGradleTest.Android() { android { namespace 'io.github.usefulness' - compileSdkVersion 31 + compileSdk 33 defaultConfig { minSdkVersion 23 } diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/BaselineTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/BaselineTest.kt index 3753cae..ca0f55b 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/BaselineTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/BaselineTest.kt @@ -33,6 +33,15 @@ class BaselineTest : WithGradleTest.Kotlin() { """.trimIndent(), ) } + resolve(".editorconfig") { + writeText( + """ + [*.kt] + ktlint_standard_function-start-of-body-spacing = disabled + + """.trimIndent(), + ) + } resolve("src/main/kotlin/ClassOne.kt") { writeText(kotlinClass("ClassOne")) } @@ -64,10 +73,10 @@ class BaselineTest : WithGradleTest.Kotlin() { - + - + @@ -93,7 +102,7 @@ class BaselineTest : WithGradleTest.Kotlin() { writeText(validClass) } buildAndFail("lintKotlin").apply { - assertThat(output).contains("CustomClass.kt:2:22: Lint error > [no-multi-spaces]") + assertThat(output).contains("CustomClass.kt:2:22: Lint error > [standard:no-multi-spaces]") } projectRoot.resolve("config/baseline.xml") { @@ -103,10 +112,10 @@ class BaselineTest : WithGradleTest.Kotlin() { - + - + @@ -143,10 +152,10 @@ class BaselineTest : WithGradleTest.Kotlin() { - + - + @@ -154,7 +163,7 @@ class BaselineTest : WithGradleTest.Kotlin() { ) } build("formatKotlin").apply { - assertThat(output).contains("CustomClass.kt:2:21: Format fixed > [curly-spacing]") + assertThat(output).contains("CustomClass.kt:2:21: Format fixed > [standard:curly-spacing]") } projectRoot.resolve("src/main/kotlin/CustomClass.kt") { @@ -178,10 +187,10 @@ class BaselineTest : WithGradleTest.Kotlin() { - + - + @@ -189,7 +198,7 @@ class BaselineTest : WithGradleTest.Kotlin() { ) } build("formatKotlin").apply { - assertThat(output).contains("CustomClass.kt:2:22: Format fixed > [no-multi-spaces]") + assertThat(output).contains("CustomClass.kt:2:22: Format fixed > [standard:no-multi-spaces]") } } } diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/CustomTaskTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/CustomTaskTest.kt index 24acd47..5c12f9f 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/CustomTaskTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/CustomTaskTest.kt @@ -187,12 +187,12 @@ class CustomTaskTest : WithGradleTest.Kotlin() { buildAndFail("reportsEmpty").apply { assertThat(task(":reportsEmpty")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).contains("[final-newline] File must end with a newline (\\n)") + assertThat(output).contains("[standard:final-newline] File must end with a newline (\\n)") assertThat(projectRoot.resolve("build/reports/ktlint")).doesNotExist() } buildAndFail("reportsNotConfigured").apply { assertThat(task(":reportsNotConfigured")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).contains("[final-newline] File must end with a newline (\\n)") + assertThat(output).contains("[standard:final-newline] File must end with a newline (\\n)") assertThat(projectRoot.resolve("build/reports/ktlint")).doesNotExist() } } diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/EditorConfigTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/EditorConfigTest.kt index c2727da..50493ad 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/EditorConfigTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/EditorConfigTest.kt @@ -102,7 +102,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { } buildAndFail("lintKotlin").apply { assertThat(task(":lintKotlinMain")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).contains("[indent] Unexpected indentation (2) (should be 6)") + assertThat(output).contains("[standard:indent] Unexpected indentation (2) (should be 6)") } projectRoot.resolve(".editorconfig") { @@ -116,7 +116,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { } buildAndFail("lintKotlin").apply { assertThat(task(":lintKotlinMain")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).doesNotContain("[indent] Unexpected indentation (2) (should be 6)") + assertThat(output).doesNotContain("[standard:indent] Unexpected indentation (2) (should be 6)") } } @@ -145,7 +145,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { } buildAndFail("lintKotlin", "--info").apply { assertThat(task(":lintKotlinMain")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).contains("[filename] File 'FileName.kt' contains a single top level declaration") + assertThat(output).contains("[standard:filename] File 'FileName.kt' contains a single top level declaration") assertThat(output).contains("resetting KtLint caches") } @@ -173,7 +173,9 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { } build("formatKotlin").apply { assertThat(task(":formatKotlinMain")?.outcome).isEqualTo(TaskOutcome.SUCCESS) - assertThat(output).contains("Format could not fix > [filename] File 'FileName.kt' contains a single top level declaration") + assertThat(output).contains( + "Format could not fix > [standard:filename] File 'FileName.kt' contains a single top level declaration", + ) } projectRoot.resolve(".editorconfig") { diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ExtensionTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ExtensionTest.kt index 60634a0..355fdcd 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ExtensionTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ExtensionTest.kt @@ -82,8 +82,8 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { buildAndFail("formatKotlin").apply { assertThat(task(":formatKotlinMain")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).contains("FileName.kt:1:1: Format could not fix > [filename]") - assertThat(output).contains("SomeClass.kt:1:32: Format fixed > [colon-spacing]") + assertThat(output).contains("FileName.kt:1:1: Format could not fix > [standard:filename]") + assertThat(output).contains("SomeClass.kt:1:32: Format fixed > [standard:colon-spacing]") } projectRoot.resolve("src/main/kotlin/FileName.kt") { @@ -97,7 +97,7 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { build("formatKotlin").apply { assertThat(task(":formatKotlinMain")?.outcome).isEqualTo(TaskOutcome.SUCCESS) - assertThat(output).contains("FileName.kt:1:31: Format fixed > [colon-spacing]") + assertThat(output).contains("FileName.kt:1:31: Format fixed > [standard:colon-spacing]") } } @@ -132,7 +132,7 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { """ ktlint { experimentalRules = true - disabledRules = ["filename", "experimental:unnecessary-parentheses-before-trailing-lambda"] + disabledRules = ["filename", "standard:unnecessary-parentheses-before-trailing-lambda"] } """.trimIndent() appendText(script) @@ -205,7 +205,7 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { } ktlint { - ktlintVersion = "0.46.0" + ktlintVersion = "0.32.0" } """.trimIndent() @@ -217,12 +217,11 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { buildAndFail("lintKotlin").apply { assertThat(task(":lintKotlinMain")?.outcome).isEqualTo(TaskOutcome.FAILED) - val expectedMessage = "EditorConfigOverride com.pinterest.ktlint.core.api.EditorConfigOverride" + - "${"$"}Companion.getEMPTY_EDITOR_CONFIG_OVERRIDE()'" + val expectedMessage = "ClassNotFoundException: com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine" assertThat(output).contains(expectedMessage) } build("dependencies", "--configuration", "ktlint").apply { - assertThat(output).contains("com.pinterest:ktlint:0.46.0") + assertThat(output).contains("com.pinterest:ktlint:0.32.0") } } @@ -246,7 +245,7 @@ internal class ExtensionTest : WithGradleTest.Kotlin() { reporters = ["checkstyle", "html", "json", "plain", "sarif"] experimentalRules = true disabledRules = ["no-wildcard-imports", "experimental:annotation", "your-custom-rule:no-bugs"] - ktlintVersion = "0.48.2" + ktlintVersion = "0.49.0" chunkSize = 50 baselineFile.set(file("config/ktlint_baseline.xml")) } diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinJsProjectTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinJsProjectTest.kt index ad14894..bedbb88 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinJsProjectTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinJsProjectTest.kt @@ -66,9 +66,13 @@ class KotlinJsProjectTest : WithGradleTest.Kotlin() { buildAndFail("lintKotlin", "--continue").apply { assertThat(task(":lintKotlinMain")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).contains("Lint error > [filename] File 'FixtureFileName.kt' contains a single top level declaration") + assertThat(output).contains( + "Lint error > [standard:filename] File 'FixtureFileName.kt' contains a single top level declaration", + ) assertThat(task(":lintKotlinTest")?.outcome).isEqualTo(TaskOutcome.FAILED) - assertThat(output).contains("Lint error > [filename] File 'FixtureTestFileName.kt' contains a single top level declaration") + assertThat(output).contains( + "Lint error > [standard:filename] File 'FixtureTestFileName.kt' contains a single top level declaration", + ) } } @@ -104,11 +108,11 @@ class KotlinJsProjectTest : WithGradleTest.Kotlin() { } build("formatKotlin").apply { assertThat(task(":formatKotlinMain")?.outcome).isEqualTo(TaskOutcome.SUCCESS) - assertThat(output).contains("FixtureClass.kt:3:19: Format fixed > [curly-spacing] Missing spacing before \"{\"") - assertThat(output).contains("FixtureClass.kt:1:1: Format could not fix > [no-wildcard-imports] Wildcard import") + assertThat(output).contains("FixtureClass.kt:3:19: Format fixed > [standard:curly-spacing] Missing spacing before \"{\"") + assertThat(output).contains("FixtureClass.kt:1:1: Format could not fix > [standard:no-wildcard-imports] Wildcard import") assertThat(task(":formatKotlinTest")?.outcome).isEqualTo(TaskOutcome.SUCCESS) - assertThat(output).contains("FixtureTestClass.kt:3:23: Format fixed > [curly-spacing] Missing spacing before \"{\"") - assertThat(output).contains("FixtureTestClass.kt:1:1: Format could not fix > [no-wildcard-imports] Wildcard import") + assertThat(output).contains("FixtureTestClass.kt:3:23: Format fixed > [standard:curly-spacing] Missing spacing before \"{\"") + assertThat(output).contains("FixtureTestClass.kt:1:1: Format could not fix > [standard:no-wildcard-imports] Wildcard import") } } } diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinProjectTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinProjectTest.kt index a414d0d..a251ad5 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinProjectTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/KotlinProjectTest.kt @@ -70,7 +70,7 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { fileWithFailingExperimentalRule() buildAndFail("lintKotlin").apply { - assertThat(output).containsPattern(".*Lint error > \\[experimental:unnecessary-parentheses".toPattern()) + assertThat(output).containsPattern(".*Lint error > \\[standard:unnecessary-parentheses".toPattern()) output.lines().filter { it.contains("Lint error") }.forEach { line -> val filePath = pathPattern.find(line)?.groups?.get(1)?.value.orEmpty() assertThat(File(filePath)).exists() @@ -135,9 +135,9 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { val filePath = pathPattern.find(line)?.groups?.get(1)?.value.orEmpty() assertThat(File(filePath)).exists() } - assertThat(output).contains("Format could not fix > [no-wildcard-imports] Wildcard import") - assertThat(output).contains("KotlinClass.kt:1:1: Format fixed > [final-newline] File must end with a newline") - assertThat(output).contains("KotlinClass.kt:3:18: Format fixed > [curly-spacing] Missing spacing before \"{\"") + assertThat(output).contains("Format could not fix > [standard:no-wildcard-imports] Wildcard import") + assertThat(output).contains("KotlinClass.kt:1:1: Format fixed > [standard:final-newline] File must end with a newline") + assertThat(output).contains("KotlinClass.kt:3:18: Format fixed > [standard:curly-spacing] Missing spacing before \"{\"") // language=kotlin val expected = @@ -156,7 +156,7 @@ internal class KotlinProjectTest : WithGradleTest.Kotlin() { build("formatKotlin").apply { assertThat(task(":formatKotlinMain")?.outcome).isEqualTo(TaskOutcome.SUCCESS) - assertThat(output).contains("Format could not fix > [no-wildcard-imports] Wildcard import") + assertThat(output).contains("Format could not fix > [standard:no-wildcard-imports] Wildcard import") assertThat(output).doesNotContain("Format fixed") } } diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ModifiedSourceSetsTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ModifiedSourceSetsTest.kt index 71f57f7..be92707 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ModifiedSourceSetsTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ModifiedSourceSetsTest.kt @@ -45,7 +45,7 @@ internal class ModifiedSourceSetsTest : WithGradleTest.Android() { android { namespace 'io.github.usefulness' - compileSdkVersion 31 + compileSdk 31 defaultConfig { minSdkVersion 23 } diff --git a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ReportersTest.kt b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ReportersTest.kt index c9817ca..d9cf005 100644 --- a/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ReportersTest.kt +++ b/ktlint-gradle-plugin/src/test/kotlin/io/github/usefulness/functional/ReportersTest.kt @@ -105,7 +105,7 @@ class ReportersTest : WithGradleTest.Kotlin() { ktlint { reporters = ['sarif'] - ktlintVersion = "0.48.1" + ktlintVersion = "0.49.0" } """ @@ -114,8 +114,8 @@ class ReportersTest : WithGradleTest.Kotlin() { build("lintKotlin").apply { val reportContent = projectRoot.resolve("build/reports/ktlint/main-lint.sarif.json") - assertThat(reportContent).content().contains(""""version": "0.48.1"""") - assertThat(reportContent).content().contains(""""semanticVersion": "0.48.1"""") + assertThat(reportContent).content().contains(""""version": "0.49.0"""") + assertThat(reportContent).content().contains(""""semanticVersion": "0.49.0"""") } } @@ -161,11 +161,11 @@ private fun expectedEmptyJson() = """ """.trimIndent() private fun expectedFailedPlain() = """ -src/main/kotlin/FirstClass.kt:1:1: File 'FirstClass.kt' contains a single top level declaration and should be named 'WrongClassName.kt' (filename) -src/main/kotlin/SecondClass.kt:1:1: File 'SecondClass.kt' contains a single top level declaration and should be named 'MultipleOffencesInSingleSourceSet.kt' (filename) +src/main/kotlin/FirstClass.kt:1:1: File 'FirstClass.kt' contains a single top level declaration and should be named 'WrongClassName.kt' (standard:filename) +src/main/kotlin/SecondClass.kt:1:1: File 'SecondClass.kt' contains a single top level declaration and should be named 'MultipleOffencesInSingleSourceSet.kt' (standard:filename) Summary error count (descending) by rule: - filename: 2 + standard:filename: 2 """.trimIndent() @@ -174,10 +174,10 @@ private fun expectedFailedCheckstyle() = """ - + - + @@ -203,11 +203,11 @@ h3 {

Issues corrected: 0

src/main/kotlin/FirstClass.kt

    -
  • (1, 1): File 'FirstClass.kt' contains a single top level declaration and should be named 'WrongClassName.kt' (filename)
  • +
  • (1, 1): File 'FirstClass.kt' contains a single top level declaration and should be named 'WrongClassName.kt' (standard:filename)

src/main/kotlin/SecondClass.kt

    -
  • (1, 1): File 'SecondClass.kt' contains a single top level declaration and should be named 'MultipleOffencesInSingleSourceSet.kt' (filename)
  • +
  • (1, 1): File 'SecondClass.kt' contains a single top level declaration and should be named 'MultipleOffencesInSingleSourceSet.kt' (standard:filename)
@@ -224,7 +224,7 @@ fun expectedFailedJson() = """ "line": 1, "column": 1, "message": "File 'FirstClass.kt' contains a single top level declaration and should be named 'WrongClassName.kt'", - "rule": "filename" + "rule": "standard:filename" } ] }, @@ -235,7 +235,7 @@ fun expectedFailedJson() = """ "line": 1, "column": 1, "message": "File 'SecondClass.kt' contains a single top level declaration and should be named 'MultipleOffencesInSingleSourceSet.kt'", - "rule": "filename" + "rule": "standard:filename" } ] } diff --git a/settings.gradle b/settings.gradle index a3f6453..2624bd9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,6 +17,10 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { + url "https://oss.sonatype.org/content/repositories/snapshots" + mavenContent { snapshotsOnly() } + } } } diff --git a/test-project-android/app/build.gradle b/test-project-android/app/build.gradle index 0a125ed..51955ab 100644 --- a/test-project-android/app/build.gradle +++ b/test-project-android/app/build.gradle @@ -8,8 +8,18 @@ ktlint { reporters = ["plain"] } android { - compileSdkVersion(33) namespace = "com.ktint_gradle_plugin.example" + defaultConfig { + compileSdk 33 + minSdkVersion 26 + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11 + } } dependencies { diff --git a/test-project-android/app/src/main/java/org/jmailen/gradle/kotlinter/sample/EmptyClassBodyInJavaSourcesClass.kt b/test-project-android/app/src/main/java/io/github/usefulness/sample/EmptyClassBodyInJavaSourcesClass.kt similarity index 100% rename from test-project-android/app/src/main/java/org/jmailen/gradle/kotlinter/sample/EmptyClassBodyInJavaSourcesClass.kt rename to test-project-android/app/src/main/java/io/github/usefulness/sample/EmptyClassBodyInJavaSourcesClass.kt diff --git a/test-project-android/app/src/main/kotlin/org/jmailen/gradle/kotlinter/sample/EmptyClassBodyClass.kt b/test-project-android/app/src/main/kotlin/io/github/usefulness/sample/EmptyClassBodyClass.kt similarity index 100% rename from test-project-android/app/src/main/kotlin/org/jmailen/gradle/kotlinter/sample/EmptyClassBodyClass.kt rename to test-project-android/app/src/main/kotlin/io/github/usefulness/sample/EmptyClassBodyClass.kt diff --git a/test-project-android/app/src/test/kotlin/org/jmailen/gradle/kotlinter/sample/CustomRuleTest.kt b/test-project-android/app/src/test/kotlin/io/github/usefulness/sample/CustomRuleTest.kt similarity index 100% rename from test-project-android/app/src/test/kotlin/org/jmailen/gradle/kotlinter/sample/CustomRuleTest.kt rename to test-project-android/app/src/test/kotlin/io/github/usefulness/sample/CustomRuleTest.kt diff --git a/test-project-android/app/src/test/kotlin/org/jmailen/gradle/kotlinter/sample/OpSpacing.kt b/test-project-android/app/src/test/kotlin/io/github/usefulness/sample/OpSpacing.kt similarity index 100% rename from test-project-android/app/src/test/kotlin/org/jmailen/gradle/kotlinter/sample/OpSpacing.kt rename to test-project-android/app/src/test/kotlin/io/github/usefulness/sample/OpSpacing.kt diff --git a/test-project-android/custom-ktlint-rules/build.gradle b/test-project-android/custom-ktlint-rules/build.gradle index 8cd666c..c2e610e 100644 --- a/test-project-android/custom-ktlint-rules/build.gradle +++ b/test-project-android/custom-ktlint-rules/build.gradle @@ -3,5 +3,5 @@ plugins { } dependencies { - compileOnly("com.pinterest.ktlint:ktlint-core:0.48.2") + compileOnly("com.pinterest.ktlint:ktlint-cli-ruleset-core:0.49.0") } diff --git a/test-project-android/custom-ktlint-rules/src/main/kotlin/io/github/usefulness/customrules/CustomRuleSetProvider.kt b/test-project-android/custom-ktlint-rules/src/main/kotlin/io/github/usefulness/customrules/CustomRuleSetProvider.kt new file mode 100644 index 0000000..c4e6612 --- /dev/null +++ b/test-project-android/custom-ktlint-rules/src/main/kotlin/io/github/usefulness/customrules/CustomRuleSetProvider.kt @@ -0,0 +1,12 @@ +package io.github.usefulness.customrules + +import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 +import com.pinterest.ktlint.rule.engine.core.api.RuleProvider +import com.pinterest.ktlint.rule.engine.core.api.RuleSetId + +class CustomRuleSetProvider : RuleSetProviderV3(RuleSetId("custom-ktlint-rules")) { + + override fun getRuleProviders() = setOf( + RuleProvider { NoNewLineBeforeReturnTypeRule() }, + ) +} diff --git a/test-project-android/custom-ktlint-rules/src/main/kotlin/org/jmailen/gradle/kotlinter/customrules/NoNewLineBeforeReturnTypeRule.kt b/test-project-android/custom-ktlint-rules/src/main/kotlin/io/github/usefulness/customrules/NoNewLineBeforeReturnTypeRule.kt similarity index 73% rename from test-project-android/custom-ktlint-rules/src/main/kotlin/org/jmailen/gradle/kotlinter/customrules/NoNewLineBeforeReturnTypeRule.kt rename to test-project-android/custom-ktlint-rules/src/main/kotlin/io/github/usefulness/customrules/NoNewLineBeforeReturnTypeRule.kt index c1a6ef6..8bda324 100644 --- a/test-project-android/custom-ktlint-rules/src/main/kotlin/org/jmailen/gradle/kotlinter/customrules/NoNewLineBeforeReturnTypeRule.kt +++ b/test-project-android/custom-ktlint-rules/src/main/kotlin/io/github/usefulness/customrules/NoNewLineBeforeReturnTypeRule.kt @@ -1,17 +1,20 @@ package io.github.usefulness.customrules -import com.pinterest.ktlint.core.Rule -import com.pinterest.ktlint.core.api.EditorConfigProperties -import com.pinterest.ktlint.core.ast.isPartOfComment -import com.pinterest.ktlint.core.ast.isPartOfString -import com.pinterest.ktlint.core.ast.nextLeaf +import com.pinterest.ktlint.rule.engine.core.api.Rule +import com.pinterest.ktlint.rule.engine.core.api.RuleId +import com.pinterest.ktlint.rule.engine.core.api.isPartOfComment +import com.pinterest.ktlint.rule.engine.core.api.isPartOfString +import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtPrimaryConstructor import org.jetbrains.kotlin.psi.KtSecondaryConstructor -class NoNewLineBeforeReturnTypeRule : Rule("no-newline-before-return-type") { +class NoNewLineBeforeReturnTypeRule : Rule( + ruleId = RuleId("custom-ktlint-rules:no-newline-before-return-type"), + about = About() +) { override fun beforeVisitChildNodes( node: ASTNode, diff --git a/test-project-android/custom-ktlint-rules/src/main/kotlin/org/jmailen/gradle/kotlinter/customrules/CustomRuleSetProvider.kt b/test-project-android/custom-ktlint-rules/src/main/kotlin/org/jmailen/gradle/kotlinter/customrules/CustomRuleSetProvider.kt deleted file mode 100644 index c444490..0000000 --- a/test-project-android/custom-ktlint-rules/src/main/kotlin/org/jmailen/gradle/kotlinter/customrules/CustomRuleSetProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package io.github.usefulness.customrules - -import com.pinterest.ktlint.core.RuleProvider -import com.pinterest.ktlint.core.RuleSetProviderV2 - -class CustomRuleSetProvider : RuleSetProviderV2( - "custom-ktlint-rules", - about = NO_ABOUT, -) { - - override fun getRuleProviders() = setOf( - RuleProvider { NoNewLineBeforeReturnTypeRule() }, - ) -} diff --git a/test-project-android/custom-ktlint-rules/src/main/resources/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2 b/test-project-android/custom-ktlint-rules/src/main/resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 similarity index 100% rename from test-project-android/custom-ktlint-rules/src/main/resources/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2 rename to test-project-android/custom-ktlint-rules/src/main/resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 diff --git a/test-project/src/main/kotlin/org/jmailen/gradle/kotlinter/sample/EmptyClassBodyClass.kt b/test-project/src/main/kotlin/io/github/usefulness/sample/EmptyClassBodyClass.kt similarity index 100% rename from test-project/src/main/kotlin/org/jmailen/gradle/kotlinter/sample/EmptyClassBodyClass.kt rename to test-project/src/main/kotlin/io/github/usefulness/sample/EmptyClassBodyClass.kt diff --git a/test-project/src/test/kotlin/org/jmailen/gradle/kotlinter/sample/OpSpacing.kt b/test-project/src/test/kotlin/io/github/usefulness/sample/OpSpacing.kt similarity index 100% rename from test-project/src/test/kotlin/org/jmailen/gradle/kotlinter/sample/OpSpacing.kt rename to test-project/src/test/kotlin/io/github/usefulness/sample/OpSpacing.kt