From 705e72a7d66efc083e3a87997413f43b2682b756 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 21 Nov 2023 10:41:11 +0800 Subject: [PATCH] Support custom rule sets for Ktlint --- CHANGES.md | 2 ++ .../diffplug/spotless/kotlin/KtLintStep.java | 19 ++++++++++----- plugin-gradle/CHANGES.md | 2 ++ plugin-gradle/README.md | 7 +++++- .../gradle/spotless/BaseKotlinExtension.java | 18 +++++++++++--- .../gradle/spotless/KotlinExtensionTest.java | 24 +++++++++++++++++++ plugin-maven/CHANGES.md | 1 + plugin-maven/README.md | 3 +++ .../spotless/maven/kotlin/Ktlint.java | 9 ++++++- .../spotless/maven/kotlin/KtlintTest.java | 18 ++++++++++++++ .../resources/kotlin/ktlint/listScreen.dirty | 6 +++++ 11 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 testlib/src/main/resources/kotlin/ktlint/listScreen.dirty diff --git a/CHANGES.md b/CHANGES.md index c1a11e3a0a..404363e199 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ This document is intended for Spotless developers. We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* Support custom rule sets for Ktlint. ([#1896](https://github.com/diffplug/spotless/pull/1896) ### Fixed * Fix Eclipse JDT on some settings files. ([#1864](https://github.com/diffplug/spotless/pull/1864) fixes [#1638](https://github.com/diffplug/spotless/issues/1638)) ### Changes diff --git a/lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java b/lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java index 7c6801a2b6..e131b2b46f 100644 --- a/lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java +++ b/lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java @@ -19,8 +19,11 @@ import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.TreeMap; import javax.annotation.Nullable; @@ -51,18 +54,19 @@ public static FormatterStep create(String version, Provisioner provisioner) { public static FormatterStep create(String version, Provisioner provisioner, Map editorConfigOverride) { - return create(version, provisioner, false, null, editorConfigOverride); + return create(version, provisioner, false, null, editorConfigOverride, Collections.emptyList()); } public static FormatterStep create(String version, Provisioner provisioner, boolean isScript, @Nullable FileSignature editorConfig, - Map editorConfigOverride) { + Map editorConfigOverride, + List customRuleSets) { Objects.requireNonNull(version, "version"); Objects.requireNonNull(provisioner, "provisioner"); return FormatterStep.createLazy(NAME, - () -> new State(version, provisioner, isScript, editorConfig, editorConfigOverride), + () -> new State(version, provisioner, isScript, editorConfig, editorConfigOverride, customRuleSets), State::createFormat); } @@ -86,11 +90,14 @@ static final class State implements Serializable { Provisioner provisioner, boolean isScript, @Nullable FileSignature editorConfigPath, - Map editorConfigOverride) throws IOException { + Map editorConfigOverride, + List customRuleSets) throws IOException { this.version = version; this.editorConfigOverride = new TreeMap<>(editorConfigOverride); - this.jarState = JarState.from((version.startsWith("0.") ? MAVEN_COORDINATE_0_DOT : MAVEN_COORDINATE_1_DOT) + version, - provisioner); + String ktlintCoordinate = (version.startsWith("0.") ? MAVEN_COORDINATE_0_DOT : MAVEN_COORDINATE_1_DOT) + version; + Set mavenCoordinates = new HashSet<>(customRuleSets); + mavenCoordinates.add(ktlintCoordinate); + this.jarState = JarState.from(mavenCoordinates, provisioner); this.editorConfigPath = editorConfigPath; this.isScript = isScript; } diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 9d833b0076..04d3e9bb38 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Added +* Support custom rule sets for Ktlint. ([#1896](https://github.com/diffplug/spotless/pull/1896) ### Fixed * Fix Eclipse JDT on some settings files. ([#1864](https://github.com/diffplug/spotless/pull/1864) fixes [#1638](https://github.com/diffplug/spotless/issues/1638)) * Check if EditorConfig file exist for Ktlint in KotlinGradleExtension. ([#1889](https://github.com/diffplug/spotless/pull/1889) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 3341bb29ef..6232f9c0e1 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -399,7 +399,7 @@ Additionally, `editorConfigOverride` options will override what's supplied in `. ```kotlin spotless { kotlin { - // version, editorConfigPath and editorConfigOverride are all optional + // version, editorConfigPath, editorConfigOverride and customRuleSets are all optional ktlint("1.0.0") .setEditorConfigPath("$projectDir/config/.editorconfig") // sample unusual placement .editorConfigOverride( @@ -407,6 +407,11 @@ spotless { "indent_size" to 2, ) ) + .customRuleSets( + listOf( + "io.nlopez.compose.rules:ktlint:0.3.3" + ) + ) } } ``` diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java index e446ce67c4..0d89e224f6 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java @@ -18,12 +18,14 @@ import java.io.File; import java.io.IOException; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import javax.annotation.Nullable; +import com.diffplug.common.collect.ImmutableList; import com.diffplug.common.collect.ImmutableSortedMap; import com.diffplug.spotless.FileSignature; import com.diffplug.spotless.FormatterStep; @@ -51,7 +53,7 @@ public KtlintConfig ktlint() throws IOException { /** Adds the specified version of ktlint. */ public KtlintConfig ktlint(String version) throws IOException { - return new KtlintConfig(version, Collections.emptyMap()); + return new KtlintConfig(version, Collections.emptyMap(), Collections.emptyList()); } /** Uses the ktfmt jar to format source code. */ @@ -147,16 +149,19 @@ public class KtlintConfig { private final String version; private FileSignature editorConfigPath; private Map editorConfigOverride; + private List customRuleSets; private KtlintConfig( String version, - Map editorConfigOverride) throws IOException { + Map editorConfigOverride, + List customRuleSets) throws IOException { Objects.requireNonNull(version); File defaultEditorConfig = getProject().getRootProject().file(".editorconfig"); FileSignature editorConfigPath = defaultEditorConfig.exists() ? FileSignature.signAsList(defaultEditorConfig) : null; this.version = version; this.editorConfigPath = editorConfigPath; this.editorConfigOverride = editorConfigOverride; + this.customRuleSets = customRuleSets; addStep(createStep()); } @@ -182,13 +187,20 @@ public KtlintConfig editorConfigOverride(Map editorConfigOverrid return this; } + public KtlintConfig customRuleSets(List customRuleSets) { + this.customRuleSets = ImmutableList.copyOf(customRuleSets); + replaceStep(createStep()); + return this; + } + private FormatterStep createStep() { return KtLintStep.create( version, provisioner(), isScript(), editorConfigPath, - editorConfigOverride); + editorConfigOverride, + customRuleSets); } } } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java index 7ce1819d60..dd0f2f5e21 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java @@ -141,6 +141,30 @@ void testSetEditorConfigCanOverrideEditorConfigFile() throws IOException { checkKtlintOfficialStyle(); } + @Test + void withCustomRuleSetApply() throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'org.jetbrains.kotlin.jvm' version '1.5.31'", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "spotless {", + " kotlin {", + " ktlint(\"1.0.1\")", + " .customRuleSets([", + " \"io.nlopez.compose.rules:ktlint:0.3.3\"", + " ])", + " .editorConfigOverride([", + " ktlint_function_naming_ignore_when_annotated_with: \"Composable\",", + " ])", + " }", + "}"); + setFile("src/main/kotlin/Main.kt").toResource("kotlin/ktlint/listScreen.dirty"); + String buildOutput = gradleRunner().withArguments("spotlessCheck").buildAndFail().getOutput(); + assertThat(buildOutput).contains("Composable functions that return Unit should start with an uppercase letter."); + } + @Test void testWithHeader() throws IOException { setFile("build.gradle").toLines( diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 10ebfc57c1..5122402019 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -5,6 +5,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * CompileSourceRoots and TestCompileSourceRoots are now respected as default includes. These properties are commonly set when adding extra source directories. ([#1846](https://github.com/diffplug/spotless/issues/1846)) +* Support custom rule sets for Ktlint. ([#1896](https://github.com/diffplug/spotless/pull/1896) ### Fixed * Fix crash when build dir is a softlink to another directory. ([#1859](https://github.com/diffplug/spotless/pull/1859)) * Fix Eclipse JDT on some settings files. ([#1864](https://github.com/diffplug/spotless/pull/1864) fixes [#1638](https://github.com/diffplug/spotless/issues/1638)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 7944b5a450..f7849fbdfc 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -416,6 +416,9 @@ Additionally, `editorConfigOverride` options will override what's supplied in `. true true + + io.nlopez.compose.rules:ktlint:0.3.3 + ``` diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktlint.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktlint.java index 1fc0e75ad3..5c939687b8 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktlint.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktlint.java @@ -15,7 +15,9 @@ */ package com.diffplug.spotless.maven.kotlin; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.maven.plugins.annotations.Parameter; @@ -35,6 +37,8 @@ public class Ktlint implements FormatterStepFactory { private String editorConfigPath; @Parameter private Map editorConfigOverride; + @Parameter + private List customRuleSets; @Override public FormatterStep newFormatterStep(final FormatterStepConfig stepConfig) { @@ -46,7 +50,10 @@ public FormatterStep newFormatterStep(final FormatterStepConfig stepConfig) { if (editorConfigOverride == null) { editorConfigOverride = new HashMap<>(); } + if (customRuleSets == null) { + customRuleSets = Collections.emptyList(); + } - return KtLintStep.create(ktlintVersion, stepConfig.getProvisioner(), false, configPath, editorConfigOverride); + return KtLintStep.create(ktlintVersion, stepConfig.getProvisioner(), false, configPath, editorConfigOverride, customRuleSets); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtlintTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtlintTest.java index 2916e118a5..fe5b0e1b57 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtlintTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtlintTest.java @@ -15,8 +15,11 @@ */ package com.diffplug.spotless.maven.kotlin; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.Test; +import com.diffplug.spotless.ProcessRunner; import com.diffplug.spotless.maven.MavenIntegrationHarness; class KtlintTest extends MavenIntegrationHarness { @@ -63,6 +66,21 @@ void testSetEditorConfigCanOverrideEditorConfigFile() throws Exception { checkKtlintOfficialStyle(); } + @Test + void testWithCustomRuleSetApply() throws Exception { + writePomWithKotlinSteps("\n" + + " \n" + + " io.nlopez.compose.rules:ktlint:0.3.3\n" + + " \n" + + " \n" + + " Composable\n" + + " \n" + + ""); + setFile("src/main/kotlin/Main.kt").toResource("kotlin/ktlint/listScreen.dirty"); + ProcessRunner.Result result = mavenRunner().withArguments("spotless:check").runHasError(); + assertTrue(result.toString().contains("Composable functions that return Unit should start with an uppercase letter.")); + } + private void checkKtlintOfficialStyle() throws Exception { String path = "src/main/kotlin/Main.kt"; setFile(path).toResource("kotlin/ktlint/experimentalEditorConfigOverride.dirty"); diff --git a/testlib/src/main/resources/kotlin/ktlint/listScreen.dirty b/testlib/src/main/resources/kotlin/ktlint/listScreen.dirty new file mode 100644 index 0000000000..14c06d6d43 --- /dev/null +++ b/testlib/src/main/resources/kotlin/ktlint/listScreen.dirty @@ -0,0 +1,6 @@ +import androidx.compose.runtime.Composable + +@Composable +fun listScreen() { + val list: List = mutableListOf() +}