From 1d945a77b8a4395c244f8b800712bb6592c9e28e Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Sat, 30 Apr 2022 12:19:41 +0300 Subject: [PATCH 1/5] Convert diktat integration to use a compile-only sourceset * Convert diktat integration * Pass absolute path into `Params` object to resolve the problem with package name checking --- CHANGES.md | 1 + lib/build.gradle | 6 +- .../glue/diktat/DiktatFormatterFunc.java | 95 +++++++++++++++++++ .../diffplug/spotless/kotlin/DiktatStep.java | 91 +----------------- 4 files changed, 105 insertions(+), 88 deletions(-) create mode 100644 lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java diff --git a/CHANGES.md b/CHANGES.md index b2acc6f0b3..f1379048d1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ 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] +* Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) ## [2.25.1] - 2022-04-27 ### Changes diff --git a/lib/build.gradle b/lib/build.gradle index 2df4243110..ccfb9b1b79 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -11,7 +11,8 @@ def NEEDS_GLUE = [ 'palantirJavaFormat', 'ktfmt', 'ktlint', - 'flexmark' + 'flexmark', + 'diktat' ] for (glue in NEEDS_GLUE) { sourceSets.register(glue) { @@ -50,6 +51,9 @@ dependencies { ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-experimental:$VER_KTLINT" ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-standard:$VER_KTLINT" + String VER_DIKTAT = "1.1.0" + diktatCompileOnly "org.cqfn.diktat:diktat-rules:$VER_DIKTAT" + // used for markdown formatting flexmarkCompileOnly 'com.vladsch.flexmark:flexmark-all:0.62.2' } diff --git a/lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java b/lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java new file mode 100644 index 0000000000..5960ce2095 --- /dev/null +++ b/lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java @@ -0,0 +1,95 @@ +/* + * Copyright 2021-2022 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.glue.diktat; + +import java.io.File; +import java.util.*; + +import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider; + +import com.pinterest.ktlint.core.KtLint; +import com.pinterest.ktlint.core.KtLint.Params; +import com.pinterest.ktlint.core.LintError; +import com.pinterest.ktlint.core.RuleSet; + +import com.diffplug.spotless.FormatterFunc; + +import kotlin.Unit; +import kotlin.jvm.functions.Function2; + +public class DiktatFormatterFunc implements FormatterFunc.NeedsFile { + + private final List rulesets; + private final Map userData; + private final Function2 formatterCallback; + private final boolean isScript; + + private final ArrayList errors = new ArrayList<>(); + + public DiktatFormatterFunc(boolean isScript, Map userData) { + rulesets = Collections.singletonList(new DiktatRuleSetProvider().get()); + this.userData = userData; + this.formatterCallback = new FormatterCallback(errors); + this.isScript = isScript; + } + + static class FormatterCallback implements Function2 { + private final ArrayList errors; + + FormatterCallback(ArrayList errors) { + this.errors = errors; + } + + @Override + public Unit invoke(LintError lintError, Boolean corrected) { + if (!corrected) { + errors.add(lintError); + } + return null; + } + } + + @Override + public String applyWithFile(String unix, File file) throws Exception { + errors.clear(); + userData.put("file_path", file.getAbsolutePath()); + String result = KtLint.INSTANCE.format(new Params( + file.getName(), + unix, + rulesets, + userData, + formatterCallback, + isScript, + null, + false)); + + if (!errors.isEmpty()) { + StringBuilder error = new StringBuilder(); + error.append("There are ").append(errors.size()).append(" unfixed errors:"); + for (LintError er : errors) { + error.append(System.lineSeparator()) + .append("Error on line: ").append(er.getLine()) + .append(", column: ").append(er.getCol()) + .append(" cannot be fixed automatically") + .append(System.lineSeparator()) + .append(er.getDetail()); + } + throw new AssertionError(error); + } + + return result; + } +} diff --git a/lib/src/main/java/com/diffplug/spotless/kotlin/DiktatStep.java b/lib/src/main/java/com/diffplug/spotless/kotlin/DiktatStep.java index 7f5779cce6..e01748d4b5 100644 --- a/lib/src/main/java/com/diffplug/spotless/kotlin/DiktatStep.java +++ b/lib/src/main/java/com/diffplug/spotless/kotlin/DiktatStep.java @@ -18,9 +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.*; import javax.annotation.Nullable; @@ -33,10 +30,9 @@ public class DiktatStep { // prevent direct instantiation private DiktatStep() {} - private static final String DEFAULT_VERSION = "1.0.1"; + private static final String DEFAULT_VERSION = "1.1.0"; static final String NAME = "diktat"; static final String PACKAGE_DIKTAT = "org.cqfn.diktat"; - static final String PACKAGE_KTLINT = "com.pinterest.ktlint"; static final String MAVEN_COORDINATE = PACKAGE_DIKTAT + ":diktat-rules:"; public static String defaultVersionDiktat() { @@ -82,8 +78,6 @@ static final class State implements Serializable { /** Are the files being linted Kotlin script files. */ private final boolean isScript; private final @Nullable FileSignature config; - private final String pkg; - private final String pkgKtlint; final JarState jar; private final TreeMap userData; @@ -93,96 +87,19 @@ static final class State implements Serializable { pkgSet.add(MAVEN_COORDINATE + versionDiktat); this.userData = new TreeMap<>(userData); - this.pkg = PACKAGE_DIKTAT; - this.pkgKtlint = PACKAGE_KTLINT; this.jar = JarState.from(pkgSet, provisioner); this.isScript = isScript; this.config = config; } FormatterFunc createFormat() throws Exception { - - ClassLoader classLoader = jar.getClassLoader(); - - // first, we get the diktat rules if (config != null) { System.setProperty("diktat.config.path", config.getOnlyFile().getAbsolutePath()); } - Class ruleSetProviderClass = classLoader.loadClass(pkg + ".ruleset.rules.DiktatRuleSetProvider"); - Object diktatRuleSet = ruleSetProviderClass.getMethod("get").invoke(ruleSetProviderClass.newInstance()); - Iterable ruleSets = Collections.singletonList(diktatRuleSet); - - // 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(pkgKtlint + ".core.LintError"); - Method detailGetter = lintErrorClass.getMethod("getDetail"); - Method lineGetter = lintErrorClass.getMethod("getLine"); - Method colGetter = lintErrorClass.getMethod("getCol"); - - // grab the KtLint singleton - Class ktlintClass = classLoader.loadClass(pkgKtlint + ".core.KtLint"); - Object ktlint = ktlintClass.getDeclaredField("INSTANCE").get(null); - - Class paramsClass = classLoader.loadClass(pkgKtlint + ".core.KtLint$Params"); - // and its constructor - Constructor constructor = paramsClass.getConstructor( - /* fileName, nullable */ String.class, - /* text */ String.class, - /* ruleSets */ Iterable.class, - /* userData */ Map.class, - /* callback */ function2Interface, - /* script */ boolean.class, - /* editorConfigPath, nullable */ String.class, - /* debug */ boolean.class); - Method formatterMethod = ktlintClass.getMethod("format", paramsClass); - FormatterFunc.NeedsFile formatterFunc = (input, file) -> { - ArrayList errors = new ArrayList<>(); - - 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) { - errors.add(lintError); - } - return null; - }); - - userData.put("file_path", file.getAbsolutePath()); - try { - Object params = constructor.newInstance( - /* fileName, nullable */ file.getName(), - /* text */ input, - /* ruleSets */ ruleSets, - /* userData */ userData, - /* callback */ formatterCallback, - /* script */ isScript, - /* editorConfigPath, nullable */ null, - /* debug */ false); - String result = (String) formatterMethod.invoke(ktlint, params); - if (!errors.isEmpty()) { - StringBuilder error = new StringBuilder(""); - error.append("There are ").append(errors.size()).append(" unfixed errors:"); - for (Object er : errors) { - String detail = (String) detailGetter.invoke(er); - int line = (Integer) lineGetter.invoke(er); - int col = (Integer) colGetter.invoke(er); - - error.append(System.lineSeparator()).append("Error on line: ").append(line).append(", column: ").append(col).append(" cannot be fixed automatically") - .append(System.lineSeparator()).append(detail); - } - throw new AssertionError(error); - } - return result; - } catch (InvocationTargetException e) { - throw ThrowingEx.unwrapCause(e); - } - }; - - return formatterFunc; + Class formatterFunc = jar.getClassLoader().loadClass("com.diffplug.spotless.glue.diktat.DiktatFormatterFunc"); + Constructor constructor = formatterFunc.getConstructor(boolean.class, Map.class); + return (FormatterFunc.NeedsFile) constructor.newInstance(isScript, userData); } - } - } From ef85dc4a25a3494e633c192d90c68ac6f0277339 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 2 May 2022 13:32:20 -0700 Subject: [PATCH 2/5] Update changelogs. --- CHANGES.md | 4 +++- plugin-gradle/CHANGES.md | 3 +++ plugin-maven/CHANGES.md | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index f1379048d1..3f34593b1e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,7 +10,9 @@ 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] -* Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) +### Changes +* Bump default `diktat` version to latest `1.0.1` -> `1.0.1`. + * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) ## [2.25.1] - 2022-04-27 ### Changes diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 7025767e6d..1b7e892414 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Changes +* Bump default `diktat` version to latest `1.0.1` -> `1.0.1`. + * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) ## [6.5.1] - 2022-04-27 ### Changes diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index b050ecfed0..db2891049b 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Changes +* Bump default `diktat` version to latest `1.0.1` -> `1.0.1`. + * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) ## [2.22.3] - 2022-04-27 ### Changes From a49c2b1b7b72d947077fc41c8221dcddd44bf29d Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Tue, 3 May 2022 10:42:21 +0300 Subject: [PATCH 3/5] Convert diktat integration to use a compile-only sourceset * Pass absolute path into `Params` object to resolve the problem with package name checking * Update changelogs --- CHANGES.md | 3 ++- .../diffplug/spotless/glue/diktat/DiktatFormatterFunc.java | 4 +++- plugin-gradle/CHANGES.md | 3 ++- plugin-maven/CHANGES.md | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3f34593b1e..56a0040dd4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,8 +11,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changes -* Bump default `diktat` version to latest `1.0.1` -> `1.0.1`. +* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) + * Use the full path to a file in `diktat` integration ([#1189](https://github.com/diffplug/spotless/issues/1189)) ## [2.25.1] - 2022-04-27 ### Changes diff --git a/lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java b/lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java index 5960ce2095..1374bebb10 100644 --- a/lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java +++ b/lib/src/diktat/java/com/diffplug/spotless/glue/diktat/DiktatFormatterFunc.java @@ -67,7 +67,9 @@ public String applyWithFile(String unix, File file) throws Exception { errors.clear(); userData.put("file_path", file.getAbsolutePath()); String result = KtLint.INSTANCE.format(new Params( - file.getName(), + // Unlike Ktlint, Diktat requires full path to the file. + // See https://github.com/diffplug/spotless/issues/1189, https://github.com/analysis-dev/diktat/issues/1202 + file.getAbsolutePath(), unix, rulesets, userData, diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 1b7e892414..3ef22ce327 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,8 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changes -* Bump default `diktat` version to latest `1.0.1` -> `1.0.1`. +* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) + * Use the full path to a file in `diktat` integration ([#1189](https://github.com/diffplug/spotless/issues/1189)) ## [6.5.1] - 2022-04-27 ### Changes diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index db2891049b..8598ac482e 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,8 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changes -* Bump default `diktat` version to latest `1.0.1` -> `1.0.1`. +* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) + * Use the full path to a file in `diktat` integration ([#1189](https://github.com/diffplug/spotless/issues/1189)) ## [2.22.3] - 2022-04-27 ### Changes From 417b1b85d68423726ae914fe926c4938deb11d6b Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 3 May 2022 14:12:24 -0700 Subject: [PATCH 4/5] Bump changelogs (mostly to trigger CI). --- CHANGES.md | 6 +++--- plugin-gradle/CHANGES.md | 6 +++--- plugin-maven/CHANGES.md | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 56a0040dd4..083b6b31f5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,9 +11,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changes -* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. - * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) - * Use the full path to a file in `diktat` integration ([#1189](https://github.com/diffplug/spotless/issues/1189)) +* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. ([#1190](https://github.com/diffplug/spotless/pull/1190)) + * Converted `diktat` integration to use a compile-only source set. (fixes [#524](https://github.com/diffplug/spotless/issues/524)) + * Use the full path to a file in `diktat` integration. (fixes [#1189](https://github.com/diffplug/spotless/issues/1189)) ## [2.25.1] - 2022-04-27 ### Changes diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 3ef22ce327..81590a3d86 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,9 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changes -* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. - * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) - * Use the full path to a file in `diktat` integration ([#1189](https://github.com/diffplug/spotless/issues/1189)) +* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. ([#1190](https://github.com/diffplug/spotless/pull/1190)) + * Converted `diktat` integration to use a compile-only source set. (fixes [#524](https://github.com/diffplug/spotless/issues/524)) + * Use the full path to a file in `diktat` integration. (fixes [#1189](https://github.com/diffplug/spotless/issues/1189)) ## [6.5.1] - 2022-04-27 ### Changes diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 8598ac482e..4b7610ebb3 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,9 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changes -* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. - * Converted `diktat` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524)) - * Use the full path to a file in `diktat` integration ([#1189](https://github.com/diffplug/spotless/issues/1189)) +* Bump default `diktat` version to latest `1.0.1` -> `1.1.0`. ([#1190](https://github.com/diffplug/spotless/pull/1190)) + * Converted `diktat` integration to use a compile-only source set. (fixes [#524](https://github.com/diffplug/spotless/issues/524)) + * Use the full path to a file in `diktat` integration. (fixes [#1189](https://github.com/diffplug/spotless/issues/1189)) ## [2.22.3] - 2022-04-27 ### Changes From 335d49524f3d9944d88da2cdadc69ff4f05a4cee Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 3 May 2022 15:44:52 -0700 Subject: [PATCH 5/5] Fixup the tests. --- .../java/com/diffplug/spotless/kotlin/DiktatStepTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testlib/src/test/java/com/diffplug/spotless/kotlin/DiktatStepTest.java b/testlib/src/test/java/com/diffplug/spotless/kotlin/DiktatStepTest.java index 040a23d0a8..24a79ed61b 100644 --- a/testlib/src/test/java/com/diffplug/spotless/kotlin/DiktatStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/kotlin/DiktatStepTest.java @@ -38,9 +38,9 @@ void behavior() throws Exception { assertion.isInstanceOf(AssertionError.class); assertion.hasMessage("There are 2 unfixed errors:" + System.lineSeparator() + "Error on line: 1, column: 1 cannot be fixed automatically" + - System.lineSeparator() + "[FILE_NAME_INCORRECT] file name is incorrect - it should end with .kt extension and be in PascalCase: " + + System.lineSeparator() + "[FILE_NAME_INCORRECT] file name is incorrect - it should end with .kt extension and be in PascalCase: testlib" + System.lineSeparator() + "Error on line: 1, column: 1 cannot be fixed automatically" + - System.lineSeparator() + "[FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: vs Unsolvable"); + System.lineSeparator() + "[FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: testlib vs Unsolvable"); }); } @@ -57,9 +57,9 @@ void behaviorConf() throws Exception { assertion.isInstanceOf(AssertionError.class); assertion.hasMessage("There are 2 unfixed errors:" + System.lineSeparator() + "Error on line: 1, column: 1 cannot be fixed automatically" + - System.lineSeparator() + "[FILE_NAME_INCORRECT] file name is incorrect - it should end with .kt extension and be in PascalCase: " + + System.lineSeparator() + "[FILE_NAME_INCORRECT] file name is incorrect - it should end with .kt extension and be in PascalCase: testlib" + System.lineSeparator() + "Error on line: 1, column: 1 cannot be fixed automatically" + - System.lineSeparator() + "[FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: vs Unsolvable"); + System.lineSeparator() + "[FILE_NAME_MATCH_CLASS] file name is incorrect - it should match with the class described in it if there is the only one class declared: testlib vs Unsolvable"); }); }