Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom rule sets for Ktlint #1896

Merged
merged 3 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 14 additions & 7 deletions lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -46,25 +49,26 @@ public static FormatterStep create(Provisioner provisioner) {
}

public static FormatterStep create(String version, Provisioner provisioner) {
return create(version, provisioner, null, Collections.emptyMap());
return create(version, provisioner, null, Collections.emptyMap(), Collections.emptyList());
}

public static FormatterStep create(String version,
Provisioner provisioner,
@Nullable FileSignature editorConfig,
Map<String, Object> editorConfigOverride) {
Map<String, Object> editorConfigOverride,
List<String> customRuleSets) {
Objects.requireNonNull(version, "version");
Objects.requireNonNull(provisioner, "provisioner");
return FormatterStep.createLazy(NAME,
() -> new State(version, provisioner, editorConfig, editorConfigOverride),
() -> new State(version, provisioner, editorConfig, editorConfigOverride, customRuleSets),
State::createFormat);
}

public static String defaultVersion() {
return DEFAULT_VERSION;
}

static final class State implements Serializable {
private static final class State implements Serializable {
private static final long serialVersionUID = 1L;
/** The jar that contains the formatter. */
private final JarState jarState;
Expand All @@ -76,11 +80,14 @@ static final class State implements Serializable {
State(String version,
Provisioner provisioner,
@Nullable FileSignature editorConfigPath,
Map<String, Object> editorConfigOverride) throws IOException {
Map<String, Object> editorConfigOverride,
List<String> 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<String> mavenCoordinates = new HashSet<>(customRuleSets);
mavenCoordinates.add(ktlintCoordinate);
this.jarState = JarState.from(mavenCoordinates, provisioner);
this.editorConfigPath = editorConfigPath;
}

Expand Down
2 changes: 2 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
7 changes: 6 additions & 1 deletion plugin-gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,14 +399,19 @@ 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(
mapOf(
"indent_size" to 2,
)
)
.customRuleSets(
listOf(
"io.nlopez.compose.rules:ktlint:0.3.3"
)
)
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -51,7 +53,7 @@ public KtlintConfig ktlint() throws IOException {

/** Adds the specified version of <a href="https://github.com/pinterest/ktlint">ktlint</a>. */
public KtlintConfig ktlint(String version) throws IOException {
return new KtlintConfig(version, Collections.emptyMap());
return new KtlintConfig(version, Collections.emptyMap(), Collections.emptyList());
}

/** Uses the <a href="https://github.com/facebookincubator/ktfmt">ktfmt</a> jar to format source code. */
Expand Down Expand Up @@ -147,16 +149,19 @@ public class KtlintConfig {
private final String version;
private FileSignature editorConfigPath;
private Map<String, Object> editorConfigOverride;
private List<String> customRuleSets;

private KtlintConfig(
String version,
Map<String, Object> editorConfigOverride) throws IOException {
Map<String, Object> editorConfigOverride,
List<String> 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());
}

Expand All @@ -182,12 +187,19 @@ public KtlintConfig editorConfigOverride(Map<String, Object> editorConfigOverrid
return this;
}

public KtlintConfig customRuleSets(List<String> customRuleSets) {
this.customRuleSets = ImmutableList.copyOf(customRuleSets);
replaceStep(createStep());
return this;
}

private FormatterStep createStep() {
return KtLintStep.create(
version,
provisioner(),
editorConfigPath,
editorConfigOverride);
editorConfigOverride,
customRuleSets);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

@Test
void testWithHeader() throws IOException {
setFile("build.gradle").toLines(
Expand Down
1 change: 1 addition & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
3 changes: 3 additions & 0 deletions plugin-maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ Additionally, `editorConfigOverride` options will override what's supplied in `.
<ij_kotlin_allow_trailing_comma>true</ij_kotlin_allow_trailing_comma>
<ij_kotlin_allow_trailing_comma_on_call_site>true</ij_kotlin_allow_trailing_comma_on_call_site>
</editorConfigOverride>
<customRuleSets> <!-- optional -->
<value>io.nlopez.compose.rules:ktlint:0.3.3</value>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use value, String, or something else as the node key?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think value is good, but I'm happy to use anything else if you prefer.

</customRuleSets>
</ktlint>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,13 +30,14 @@
import com.diffplug.spotless.maven.FormatterStepFactory;

public class Ktlint implements FormatterStepFactory {

@Parameter
private String version;
@Parameter
private String editorConfigPath;
@Parameter
private Map<String, Object> editorConfigOverride;
@Parameter
private List<String> customRuleSets;

@Override
public FormatterStep newFormatterStep(final FormatterStepConfig stepConfig) {
Expand All @@ -46,7 +49,14 @@ public FormatterStep newFormatterStep(final FormatterStepConfig stepConfig) {
if (editorConfigOverride == null) {
editorConfigOverride = new HashMap<>();
}

return KtLintStep.create(ktlintVersion, stepConfig.getProvisioner(), configPath, editorConfigOverride);
if (customRuleSets == null) {
customRuleSets = Collections.emptyList();
}
return KtLintStep.create(
ktlintVersion,
stepConfig.getProvisioner(),
configPath,
editorConfigOverride,
customRuleSets);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -63,6 +66,21 @@ void testSetEditorConfigCanOverrideEditorConfigFile() throws Exception {
checkKtlintOfficialStyle();
}

@Test
void testWithCustomRuleSetApply() throws Exception {
writePomWithKotlinSteps("<ktlint>\n" +
" <customRuleSets>\n" +
" <value>io.nlopez.compose.rules:ktlint:0.3.3</value>\n" +
" </customRuleSets>\n" +
" <editorConfigOverride>\n" +
" <ktlint_function_naming_ignore_when_annotated_with>Composable</ktlint_function_naming_ignore_when_annotated_with>\n" +
" </editorConfigOverride>\n" +
"</ktlint>");
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");
Expand Down
6 changes: 6 additions & 0 deletions testlib/src/main/resources/kotlin/ktlint/listScreen.dirty
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import androidx.compose.runtime.Composable

@Composable
fun listScreen() {
val list: List<String> = mutableListOf<String>()
}