Skip to content

Commit

Permalink
Update KtLint min version to 0.46.0 and default version to 0.46.1
Browse files Browse the repository at this point in the history
Closes #1239
  • Loading branch information
magneticflux- committed Jun 29, 2022
1 parent bab36df commit 67978ab
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 143 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Expand Up @@ -12,6 +12,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Added
* Support for `MAC_CLASSIC` (`\r`) line ending ([#1243](https://github.com/diffplug/spotless/pull/1243) fixes [#1196](https://github.com/diffplug/spotless/issues/1196))
### Changes
* Bump default `ktlint` version to latest `0.45.2` -> `0.46.1` [#1239](https://github.com/diffplug/spotless/issues/1239)
* Note that we now require `ktlint >= 0.46.0` due to frequent compatibility breakages

## [2.26.2] - 2022-06-11
### Fixed
Expand Down
2 changes: 1 addition & 1 deletion lib/build.gradle
Expand Up @@ -45,7 +45,7 @@ dependencies {
}
}

String VER_KTLINT='0.45.2'
String VER_KTLINT='0.46.1'
ktlintCompileOnly "com.pinterest:ktlint:$VER_KTLINT"
ktlintCompileOnly "com.pinterest.ktlint:ktlint-core:$VER_KTLINT"
ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-experimental:$VER_KTLINT"
Expand Down
Expand Up @@ -24,6 +24,8 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jetbrains.annotations.NotNull;

import com.pinterest.ktlint.core.KtLint;
import com.pinterest.ktlint.core.KtLint.ExperimentalParams;
import com.pinterest.ktlint.core.LintError;
Expand All @@ -46,6 +48,7 @@ public class KtlintFormatterFunc implements FormatterFunc.NeedsFile {
private final Map<String, String> userData;
private final Function2<? super LintError, ? super Boolean, Unit> formatterCallback;
private final boolean isScript;
@NotNull
private final EditorConfigOverride editorConfigOverride;

/**
Expand All @@ -64,7 +67,7 @@ public KtlintFormatterFunc(boolean isScript, boolean useExperimental, Map<String
this.isScript = isScript;

if (editorConfigOverrideMap.isEmpty()) {
this.editorConfigOverride = null;
this.editorConfigOverride = EditorConfigOverride.Companion.getEmptyEditorConfigOverride();
} else {
this.editorConfigOverride = createEditorConfigOverride(editorConfigOverrideMap);
}
Expand All @@ -83,7 +86,7 @@ private EditorConfigOverride createEditorConfigOverride(Map<String, Object> edit

// Create a mapping of properties to their names based on rule properties and default properties
Map<String, UsesEditorConfigProperties.EditorConfigProperty<?>> supportedProperties = Stream
.concat(ruleProperties, DefaultEditorConfigProperties.INSTANCE.getDefaultEditorConfigProperties().stream())
.concat(ruleProperties, DefaultEditorConfigProperties.INSTANCE.getEditorConfigProperties().stream())
.distinct()
.collect(Collectors.toMap(property -> property.getType().getName(), property -> property));

Expand Down Expand Up @@ -116,31 +119,16 @@ public Unit invoke(LintError lint, Boolean corrected) {

@Override
public String applyWithFile(String unix, File file) throws Exception {

if (editorConfigOverride != null) {
// Use ExperimentalParams with EditorConfigOverride which requires KtLint 0.45.2
return KtLint.INSTANCE.format(new ExperimentalParams(
file.getName(),
unix,
rulesets,
userData,
formatterCallback,
isScript,
null,
false,
editorConfigOverride,
false));
} else {
// Use Params for backward compatibility
return KtLint.INSTANCE.format(new KtLint.Params(
file.getName(),
unix,
rulesets,
userData,
formatterCallback,
isScript,
null,
false));
}
return KtLint.INSTANCE.format(new ExperimentalParams(
file.getName(),
unix,
rulesets,
userData,
formatterCallback,
isScript,
null,
false,
editorConfigOverride,
false));
}
}
86 changes: 7 additions & 79 deletions lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java
Expand Up @@ -18,10 +18,6 @@
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
Expand All @@ -31,18 +27,15 @@
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.JarState;
import com.diffplug.spotless.Provisioner;
import com.diffplug.spotless.ThrowingEx;

/** Wraps up <a href="https://github.com/pinterest/ktlint">ktlint</a> as a FormatterStep. */
public class KtLintStep {
// prevent direct instantiation
private KtLintStep() {}

private static final String DEFAULT_VERSION = "0.45.2";
private static final String DEFAULT_VERSION = "0.46.1";
static final String NAME = "ktlint";
static final String PACKAGE_PRE_0_32 = "com.github.shyiko";
static final String PACKAGE = "com.pinterest";
static final String MAVEN_COORDINATE_PRE_0_32 = PACKAGE_PRE_0_32 + ":ktlint:";
static final String MAVEN_COORDINATE = PACKAGE + ":ktlint:";

public static FormatterStep create(Provisioner provisioner) {
Expand Down Expand Up @@ -85,95 +78,30 @@ static final class State implements Serializable {

/** Are the files being linted Kotlin script files. */
private final boolean isScript;
private final String pkg;
/** The jar that contains the formatter. */
final JarState jarState;
private final boolean useExperimental;
private final TreeMap<String, String> userData;
private final TreeMap<String, Object> editorConfigOverride;
private final boolean useParams;

State(String version, Provisioner provisioner, boolean isScript, boolean useExperimental,
Map<String, String> userData, Map<String, Object> editorConfigOverride) throws IOException {

if (!editorConfigOverride.isEmpty() &&
BadSemver.version(version) < BadSemver.version(0, 45, 2)) {
throw new IllegalStateException("KtLint editorConfigOverride supported for version 0.45.2 and later");
if (BadSemver.version(version) < BadSemver.version(0, 46, 0)) {
throw new IllegalStateException("KtLint versions < 0.46.0 not supported!");
}

this.useExperimental = useExperimental;
this.userData = new TreeMap<>(userData);
this.editorConfigOverride = new TreeMap<>(editorConfigOverride);
String coordinate;
if (BadSemver.version(version) < BadSemver.version(0, 32)) {
coordinate = MAVEN_COORDINATE_PRE_0_32;
this.pkg = PACKAGE_PRE_0_32;
} else {
coordinate = MAVEN_COORDINATE;
this.pkg = PACKAGE;
}
this.useParams = BadSemver.version(version) >= BadSemver.version(0, 34);
this.jarState = JarState.from(coordinate + version, provisioner);
this.jarState = JarState.from(MAVEN_COORDINATE + version, provisioner);
this.isScript = isScript;
}

FormatterFunc createFormat() throws Exception {
if (useParams) {
Class<?> formatterFunc = jarState.getClassLoader().loadClass("com.diffplug.spotless.glue.ktlint.KtlintFormatterFunc");
Constructor<?> constructor = formatterFunc.getConstructor(boolean.class, boolean.class, Map.class, Map.class);
return (FormatterFunc.NeedsFile) constructor.newInstance(isScript, useExperimental, userData, editorConfigOverride);
}

ClassLoader classLoader = jarState.getClassLoader();
// String KtLint::format(String input, Iterable<RuleSet> rules, Function2 errorCallback)

ArrayList<Object> ruleSets = new ArrayList<>();

// first, we get the standard rules
Class<?> standardRuleSetProviderClass = classLoader.loadClass(pkg + ".ktlint.ruleset.standard.StandardRuleSetProvider");
Object standardRuleSet = standardRuleSetProviderClass.getMethod("get").invoke(standardRuleSetProviderClass.newInstance());
ruleSets.add(standardRuleSet);

// second, we get the experimental rules if desired
if (useExperimental) {
Class<?> experimentalRuleSetProviderClass = classLoader.loadClass(pkg + ".ktlint.ruleset.experimental.ExperimentalRuleSetProvider");
Object experimentalRuleSet = experimentalRuleSetProviderClass.getMethod("get").invoke(experimentalRuleSetProviderClass.newInstance());
ruleSets.add(experimentalRuleSet);
}

// next, we create an error callback which throws an assertion error when the format is bad
Class<?> function2Interface = classLoader.loadClass("kotlin.jvm.functions.Function2");
Class<?> lintErrorClass = classLoader.loadClass(pkg + ".ktlint.core.LintError");
Method detailGetter = lintErrorClass.getMethod("getDetail");
Method lineGetter = lintErrorClass.getMethod("getLine");
Method colGetter = lintErrorClass.getMethod("getCol");
Object formatterCallback = Proxy.newProxyInstance(classLoader, new Class[]{function2Interface},
(proxy, method, args) -> {
Object lintError = args[0]; //ktlint.core.LintError
boolean corrected = (Boolean) args[1];
if (!corrected) {
String detail = (String) detailGetter.invoke(lintError);
int line = (Integer) lineGetter.invoke(lintError);
int col = (Integer) colGetter.invoke(lintError);
throw new AssertionError("Error on line: " + line + ", column: " + col + "\n" + detail);
}
return null;
});

// grab the KtLint singleton
Class<?> ktlintClass = classLoader.loadClass(pkg + ".ktlint.core.KtLint");
Object ktlint = ktlintClass.getDeclaredField("INSTANCE").get(null);

// and its format method
String formatterMethodName = isScript ? "formatScript" : "format";
Method formatterMethod = ktlintClass.getMethod(formatterMethodName, String.class, Iterable.class, Map.class, function2Interface);
return input -> {
try {
return (String) formatterMethod.invoke(ktlint, input, ruleSets, userData, formatterCallback);
} catch (InvocationTargetException e) {
throw ThrowingEx.unwrapCause(e);
}
};
Class<?> formatterFunc = jarState.getClassLoader().loadClass("com.diffplug.spotless.glue.ktlint.KtlintFormatterFunc");
Constructor<?> constructor = formatterFunc.getConstructor(boolean.class, boolean.class, Map.class, Map.class);
return (FormatterFunc.NeedsFile) constructor.newInstance(isScript, useExperimental, userData, editorConfigOverride);
}
}
}
3 changes: 3 additions & 0 deletions plugin-gradle/CHANGES.md
Expand Up @@ -5,6 +5,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Added
* Support for `MAC_CLASSIC` (`\r`) line ending ([#1243](https://github.com/diffplug/spotless/pull/1243) fixes [#1196](https://github.com/diffplug/spotless/issues/1196))
### Changes
* Bump default `ktlint` version to latest `0.45.2` -> `0.46.1` [#1239](https://github.com/diffplug/spotless/issues/1239)
* Note that we now require `ktlint >= 0.46.0` due to frequent compatibility breakages

## [6.7.2] - 2022-06-11
### Fixed
Expand Down
3 changes: 3 additions & 0 deletions plugin-maven/CHANGES.md
Expand Up @@ -5,6 +5,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Added
* Support for `MAC_CLASSIC` (`\r`) line ending ([#1243](https://github.com/diffplug/spotless/pull/1243) fixes [#1196](https://github.com/diffplug/spotless/issues/1196))
### Changes
* Bump default `ktlint` version to latest `0.45.2` -> `0.46.1` [#1239](https://github.com/diffplug/spotless/issues/1239)
* Note that we now require `ktlint >= 0.46.0` due to frequent compatibility breakages

## [2.22.8] - 2022-06-11
### Fixed
Expand Down
Expand Up @@ -42,8 +42,8 @@ void behavior() throws Exception {
}

@Test
void worksShyiko() throws Exception {
FormatterStep step = KtLintStep.create("0.31.0", TestProvisioner.mavenCentral());
void worksPre0_46_1() throws Exception {
FormatterStep step = KtLintStep.create("0.46.0", TestProvisioner.mavenCentral());
StepHarness.forStep(step)
.testResource("kotlin/ktlint/basic.dirty", "kotlin/ktlint/basic.clean")
.testResourceException("kotlin/ktlint/unsolvable.dirty", assertion -> {
Expand All @@ -53,48 +53,17 @@ void worksShyiko() throws Exception {
});
}

// Regression test to ensure it works on the version it switched to Pinterest (version 0.32.0)
// but before 0.34.
// https://github.com/diffplug/spotless/issues/419
@Test
void worksPinterestAndPre034() throws Exception {
FormatterStep step = KtLintStep.create("0.32.0", TestProvisioner.mavenCentral());
StepHarness.forStep(step)
.testResource("kotlin/ktlint/basic.dirty", "kotlin/ktlint/basic.clean")
.testResourceException("kotlin/ktlint/unsolvable.dirty", assertion -> {
assertion.isInstanceOf(AssertionError.class);
assertion.hasMessage("Error on line: 1, column: 1\n" +
"Wildcard import");
});
}

// Regression test to handle alpha and 1.x version numbers
// https://github.com/diffplug/spotless/issues/668
@Test
void worksAlpha1() throws Exception {
FormatterStep step = KtLintStep.create("0.38.0-alpha01", TestProvisioner.mavenCentral());
StepHarness.forStep(step)
.testResource("kotlin/ktlint/basic.dirty", "kotlin/ktlint/basic.clean");
}

@Test
void worksPre0_45_2() throws Exception {
FormatterStep step = KtLintStep.create("0.45.1", TestProvisioner.mavenCentral());
StepHarness.forStep(step)
.testResource("kotlin/ktlint/basic.dirty", "kotlin/ktlint/basic.clean");
}

@Test
void equality() throws Exception {
new SerializableEqualityTester() {
String version = "0.32.0";
String version = "0.46.0";

@Override
protected void setupTest(API api) {
// same version == same
api.areDifferentThan();
// change the version, and it's different
version = "0.38.0-alpha01";
version = "0.46.1";
api.areDifferentThan();
}

Expand Down

0 comments on commit 67978ab

Please sign in to comment.