diff --git a/CHANGES.md b/CHANGES.md index 26eac11f42..2f6144fcf0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Bump default `ktlint` version to latest `1.5.0` -> `1.7.1`. ([#2555](https://github.com/diffplug/spotless/pull/2555)) * Bump default `jackson` version to latest `2.19.2` -> `2.20.0`. ([#2606](https://github.com/diffplug/spotless/pull/2606)) * Bump default `gson` version to latest `2.13.1` -> `2.13.2`. ([#2615](https://github.com/diffplug/spotless/pull/2615)) +* **BREAKING** Bump default `ktfmt` version to latest `0.53` -> `0.58` ([#2613](https://github.com/diffplug/spotless/pull/2613)) + * use `TrailingCommaManagementStrategy` enum instead of `manageTrailingCommas` boolean configuration option ## [3.3.1] - 2025-07-21 ### Fixed diff --git a/gradle.properties b/gradle.properties index d0c487208d..fdb8a8a788 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,7 +21,7 @@ artifactIdMaven=spotless-maven-plugin artifactIdGradle=spotless-plugin-gradle # Build requirements -VER_JAVA=11 +VER_JAVA=17 VER_JSR_305=3.0.2 # Dependencies provided by Spotless plugin diff --git a/gradle/java-publish.gradle b/gradle/java-publish.gradle index 52a6ae7137..dad3328f5a 100644 --- a/gradle/java-publish.gradle +++ b/gradle/java-publish.gradle @@ -77,7 +77,7 @@ javadoc { // // Thus, no javadoc warnings. options.addStringOption('Xdoclint:none', '-quiet') - options.addStringOption('source', '11') + options.addStringOption('source', '17') // setup the header options.header javadocInfo // setup links diff --git a/lib/build.gradle b/lib/build.gradle index 39dd361a71..93d39fa7b1 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -104,7 +104,7 @@ dependencies { jacksonCompileOnly "com.fasterxml.jackson.core:jackson-databind:$VER_JACKSON" jacksonCompileOnly "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$VER_JACKSON" // ktfmt - ktfmtCompileOnly "com.facebook:ktfmt:0.53" + ktfmtCompileOnly "com.facebook:ktfmt:0.58" ktfmtCompileOnly("com.google.googlejavaformat:google-java-format") { version { strictly '1.7' // for JDK 8 compatibility diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java index bb4c9050bd..4b8308e47c 100644 --- a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java +++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 DiffPlug + * Copyright 2022-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,8 +28,7 @@ public final class KtfmtFormatterFunc implements FormatterFunc { @Nonnull private final KtfmtStyle style; - @Nullable - private final KtfmtFormattingOptions ktfmtFormattingOptions; + @Nullable private final KtfmtFormattingOptions ktfmtFormattingOptions; public KtfmtFormatterFunc() { this(KtfmtStyle.META, null); @@ -55,29 +54,23 @@ public String apply(@Nonnull String input) throws Exception { } private FormattingOptions createFormattingOptions() throws Exception { - FormattingOptions formattingOptions; - switch (style) { - case META: - formattingOptions = Formatter.META_FORMAT; - break; - case GOOGLE: - formattingOptions = Formatter.GOOGLE_FORMAT; - break; - case KOTLIN_LANG: - formattingOptions = Formatter.KOTLINLANG_FORMAT; - break; - default: - throw new IllegalStateException("Unknown formatting option " + style); - } + FormattingOptions formattingOptions = switch (style) { + case META -> Formatter.META_FORMAT; + case GOOGLE -> Formatter.GOOGLE_FORMAT; + case KOTLIN_LANG -> Formatter.KOTLINLANG_FORMAT; + default -> throw new IllegalStateException("Unknown formatting option " + style); + }; if (ktfmtFormattingOptions != null) { formattingOptions = formattingOptions.copy( - ktfmtFormattingOptions.getMaxWidth().orElse(formattingOptions.getMaxWidth()), - ktfmtFormattingOptions.getBlockIndent().orElse(formattingOptions.getBlockIndent()), - ktfmtFormattingOptions.getContinuationIndent().orElse(formattingOptions.getContinuationIndent()), - ktfmtFormattingOptions.getManageTrailingCommas().orElse(formattingOptions.getManageTrailingCommas()), - ktfmtFormattingOptions.getRemoveUnusedImports().orElse(formattingOptions.getRemoveUnusedImports()), - formattingOptions.getDebuggingPrintOpsAfterFormatting()); + ktfmtFormattingOptions.getMaxWidth().orElse(formattingOptions.getMaxWidth()), + ktfmtFormattingOptions.getBlockIndent().orElse(formattingOptions.getBlockIndent()), + ktfmtFormattingOptions.getContinuationIndent().orElse(formattingOptions.getContinuationIndent()), + ktfmtFormattingOptions.getTrailingCommaManagementStrategy() + .map(KtfmtTrailingCommaManagementStrategy::toFormatterTrailingCommaManagementStrategy) + .orElse(formattingOptions.getTrailingCommaManagementStrategy()), + ktfmtFormattingOptions.getRemoveUnusedImports().orElse(formattingOptions.getRemoveUnusedImports()), + formattingOptions.getDebuggingPrintOpsAfterFormatting()); } return formattingOptions; diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java index 0a810152b6..b110f2bbde 100644 --- a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java +++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormattingOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 DiffPlug + * Copyright 2022-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,32 +22,27 @@ public final class KtfmtFormattingOptions { - @Nullable - private Integer maxWidth; + @Nullable private Integer maxWidth; - @Nullable - private Integer blockIndent; + @Nullable private Integer blockIndent; - @Nullable - private Integer continuationIndent; + @Nullable private Integer continuationIndent; - @Nullable - private Boolean removeUnusedImports; + @Nullable private Boolean removeUnusedImports; - @Nullable - private Boolean manageTrailingCommas; + @Nullable private KtfmtTrailingCommaManagementStrategy trailingCommaManagementStrategy; public KtfmtFormattingOptions( @Nullable Integer maxWidth, @Nullable Integer blockIndent, @Nullable Integer continuationIndent, @Nullable Boolean removeUnusedImports, - @Nullable Boolean manageTrailingCommas) { + @Nullable KtfmtTrailingCommaManagementStrategy trailingCommaManagementStrategy) { this.maxWidth = maxWidth; this.blockIndent = blockIndent; this.continuationIndent = continuationIndent; this.removeUnusedImports = removeUnusedImports; - this.manageTrailingCommas = manageTrailingCommas; + this.trailingCommaManagementStrategy = trailingCommaManagementStrategy; } @Nonnull @@ -71,8 +66,8 @@ public Optional getRemoveUnusedImports() { } @Nonnull - public Optional getManageTrailingCommas() { - return Optional.ofNullable(manageTrailingCommas); + public Optional getTrailingCommaManagementStrategy() { + return Optional.ofNullable(trailingCommaManagementStrategy); } public void setMaxWidth(int maxWidth) { @@ -100,7 +95,7 @@ public void setRemoveUnusedImports(boolean removeUnusedImports) { this.removeUnusedImports = removeUnusedImports; } - public void setManageTrailingCommas(boolean manageTrailingCommas) { - this.manageTrailingCommas = manageTrailingCommas; + public void setTrailingCommaManagementStrategy(@Nullable KtfmtTrailingCommaManagementStrategy trailingCommaManagementStrategy) { + this.trailingCommaManagementStrategy = trailingCommaManagementStrategy; } } diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtTrailingCommaManagementStrategy.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtTrailingCommaManagementStrategy.java new file mode 100644 index 0000000000..f9ca437eee --- /dev/null +++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtTrailingCommaManagementStrategy.java @@ -0,0 +1,30 @@ +/* + * Copyright 2025 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.ktfmt; + +import com.facebook.ktfmt.format.TrailingCommaManagementStrategy; + +public enum KtfmtTrailingCommaManagementStrategy { + NONE, ONLY_ADD, COMPLETE; + + public TrailingCommaManagementStrategy toFormatterTrailingCommaManagementStrategy() { + return switch (this) { + case NONE -> TrailingCommaManagementStrategy.NONE; + case ONLY_ADD -> TrailingCommaManagementStrategy.ONLY_ADD; + case COMPLETE -> TrailingCommaManagementStrategy.COMPLETE; + }; + } +} diff --git a/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java index 2120dc144a..b30044ff2c 100644 --- a/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java +++ b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 DiffPlug + * Copyright 2016-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import static com.diffplug.spotless.kotlin.KtfmtStep.Style.DEFAULT; import static com.diffplug.spotless.kotlin.KtfmtStep.Style.DROPBOX; import static com.diffplug.spotless.kotlin.KtfmtStep.Style.META; +import static com.diffplug.spotless.kotlin.KtfmtStep.TrailingCommaManagementStrategy.ONLY_ADD; import java.io.Serializable; import java.lang.reflect.Constructor; @@ -39,7 +40,7 @@ */ public class KtfmtStep implements Serializable { private static final long serialVersionUID = 1L; - private static final String DEFAULT_VERSION = "0.53"; + private static final String DEFAULT_VERSION = "0.58"; private static final String NAME = "ktfmt"; private static final String MAVEN_COORDINATE = "com.facebook:ktfmt:"; @@ -47,11 +48,11 @@ public class KtfmtStep implements Serializable { /** * Option that allows to apply formatting options to perform a 4-space block and continuation indent. */ - @Nullable - private final Style style; - @Nullable - private final KtfmtFormattingOptions options; - /** The jar that contains the formatter. */ + @Nullable private final Style style; + @Nullable private final KtfmtFormattingOptions options; + /** + * The jar that contains the formatter. + */ private final JarState.Promised jarState; private KtfmtStep(String version, @@ -103,31 +104,55 @@ String getSince() { return since; } - /** Last version (inclusive) that supports this style */ - @Nullable - String getUntil() { + /** + * Last version (inclusive) that supports this style + */ + @Nullable String getUntil() { return until; } } + public enum TrailingCommaManagementStrategy { + /** + * Do not manage trailing commas at all, only format what is already present. + */ + NONE, + /** + *

+ * Only add trailing commas when necessary, but do not remove them. + *

+ *

+ * Lists that cannot fit on one line will have trailing commas inserted. + * Trailing commas can to be used to "hint" ktfmt that the list should be broken to multiple lines + *

+ */ + ONLY_ADD, + /** + *

+ * Fully manage trailing commas, adding and removing them where necessary. + *

+ *

+ * Lists that cannot fit on one line will have trailing commas inserted. + * Lists that span multiple lines will have them removed. Manually inserted trailing commas + * cannot be used as a hint to force breaking lists to multiple lines. + *

+ */ + COMPLETE, + } + public static class KtfmtFormattingOptions implements Serializable { private static final long serialVersionUID = 1L; - @Nullable - private Integer maxWidth = null; + @Nullable private Integer maxWidth = null; - @Nullable - private Integer blockIndent = null; + @Nullable private Integer blockIndent = null; - @Nullable - private Integer continuationIndent = null; + @Nullable private Integer continuationIndent = null; - @Nullable - private Boolean removeUnusedImports = null; + @Nullable private Boolean removeUnusedImports = null; - @Nullable - private Boolean manageTrailingCommas = null; + @Nullable private TrailingCommaManagementStrategy trailingCommaManagementStrategy; public KtfmtFormattingOptions() {} @@ -136,12 +161,12 @@ public KtfmtFormattingOptions( @Nullable Integer blockIndent, @Nullable Integer continuationIndent, @Nullable Boolean removeUnusedImports, - @Nullable Boolean manageTrailingCommas) { + @Nullable TrailingCommaManagementStrategy trailingCommaManagementStrategy) { this.maxWidth = maxWidth; this.blockIndent = blockIndent; this.continuationIndent = continuationIndent; this.removeUnusedImports = removeUnusedImports; - this.manageTrailingCommas = manageTrailingCommas; + this.trailingCommaManagementStrategy = trailingCommaManagementStrategy; } public void setMaxWidth(int maxWidth) { @@ -160,22 +185,28 @@ public void setRemoveUnusedImports(boolean removeUnusedImports) { this.removeUnusedImports = removeUnusedImports; } - public void setManageTrailingCommas(boolean manageTrailingCommas) { - this.manageTrailingCommas = manageTrailingCommas; + public void setTrailingCommaManagementStrategy(TrailingCommaManagementStrategy trailingCommaManagementStrategy) { + this.trailingCommaManagementStrategy = trailingCommaManagementStrategy; } } - /** Creates a step which formats everything - code, import order, and unused imports. */ + /** + * Creates a step which formats everything - code, import order, and unused imports. + */ public static FormatterStep create(Provisioner provisioner) { return create(defaultVersion(), provisioner); } - /** Creates a step which formats everything - code, import order, and unused imports. */ + /** + * Creates a step which formats everything - code, import order, and unused imports. + */ public static FormatterStep create(String version, Provisioner provisioner) { return create(version, provisioner, null, null); } - /** Creates a step which formats everything - code, import order, and unused imports. */ + /** + * Creates a step which formats everything - code, import order, and unused imports. + */ public static FormatterStep create(String version, Provisioner provisioner, @Nullable Style style, @Nullable KtfmtFormattingOptions options) { Objects.requireNonNull(version, "version"); Objects.requireNonNull(provisioner, "provisioner"); @@ -196,10 +227,8 @@ private State equalityState() { private static final class State implements Serializable { private static final long serialVersionUID = 1L; private final String version; - @Nullable - private final Style style; - @Nullable - private final KtfmtFormattingOptions options; + @Nullable private final Style style; + @Nullable private final KtfmtFormattingOptions options; private final JarState jarState; State(String version, @@ -224,6 +253,7 @@ FormatterFunc createFormat() throws Exception { final Class formatterFuncClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtFormatterFunc"); final Class ktfmtStyleClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtStyle"); final Class ktfmtFormattingOptionsClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtFormattingOptions"); + final Class ktfmtTrailingCommaManagmentStrategyClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtTrailingCommaManagementStrategy"); if (style == null && options == null) { final Constructor constructor = formatterFuncClass.getConstructor(); @@ -237,9 +267,13 @@ FormatterFunc createFormat() throws Exception { } final Constructor optionsConstructor = ktfmtFormattingOptionsClass.getConstructor( - Integer.class, Integer.class, Integer.class, Boolean.class, Boolean.class); + Integer.class, Integer.class, Integer.class, Boolean.class, ktfmtTrailingCommaManagmentStrategyClass); + + final Object ktfmtTrailingCommaManagementStrategy = options.trailingCommaManagementStrategy == null + ? null + : Enum.valueOf((Class) ktfmtTrailingCommaManagmentStrategyClass, options.trailingCommaManagementStrategy.name()); final Object ktfmtFormattingOptions = optionsConstructor.newInstance( - options.maxWidth, options.blockIndent, options.continuationIndent, options.removeUnusedImports, options.manageTrailingCommas); + options.maxWidth, options.blockIndent, options.continuationIndent, options.removeUnusedImports, ktfmtTrailingCommaManagementStrategy); if (style == null) { final Constructor constructor = formatterFuncClass.getConstructor(ktfmtFormattingOptionsClass); return (FormatterFunc) constructor.newInstance(ktfmtFormattingOptions); @@ -262,6 +296,12 @@ private void validateOptions() { throw new IllegalStateException("Ktfmt formatting option `removeUnusedImports` supported for version 0.17 and later"); } } + + if (BadSemver.version(version) < BadSemver.version(0, 57)) { + if (options != null && options.trailingCommaManagementStrategy == ONLY_ADD) { + throw new IllegalStateException("Value ONLY_ADD for Ktfmt formatting option `trailingCommaManagementStrategy` supported for version 0.57 and later"); + } + } } private void validateStyle() { @@ -365,7 +405,7 @@ private Object getCustomFormattingOptions(Class formatterClass) throws Except /* continuationIndent = */ Optional.ofNullable(options.continuationIndent).orElse((Integer) formattingOptionsClass.getMethod("getContinuationIndent").invoke(formattingOptions)), /* removeUnusedImports = */ Optional.ofNullable(options.removeUnusedImports).orElse((Boolean) formattingOptionsClass.getMethod("getRemoveUnusedImports").invoke(formattingOptions)), /* debuggingPrintOpsAfterFormatting = */ (Boolean) formattingOptionsClass.getMethod("getDebuggingPrintOpsAfterFormatting").invoke(formattingOptions)); - } else { + } else if (BadSemver.version(version) < BadSemver.version(0, 57)) { Class styleClass = classLoader.loadClass(formattingOptionsClass.getName() + "$Style"); formattingOptions = formattingOptions.getClass().getConstructor(styleClass, int.class, int.class, int.class, boolean.class, boolean.class, boolean.class).newInstance( /* style = */ formattingOptionsClass.getMethod("getStyle").invoke(formattingOptions), @@ -374,7 +414,17 @@ private Object getCustomFormattingOptions(Class formatterClass) throws Except /* continuationIndent = */ Optional.ofNullable(options.continuationIndent).orElse((Integer) formattingOptionsClass.getMethod("getContinuationIndent").invoke(formattingOptions)), /* removeUnusedImports = */ Optional.ofNullable(options.removeUnusedImports).orElse((Boolean) formattingOptionsClass.getMethod("getRemoveUnusedImports").invoke(formattingOptions)), /* debuggingPrintOpsAfterFormatting = */ (Boolean) formattingOptionsClass.getMethod("getDebuggingPrintOpsAfterFormatting").invoke(formattingOptions), - /* manageTrailingCommas */ Optional.ofNullable(options.manageTrailingCommas).orElse((Boolean) formattingOptionsClass.getMethod("getManageTrailingCommas").invoke(formattingOptions))); + /* manageTrailingCommas = */ Optional.ofNullable(getManageTrailingCommasFrom(options.trailingCommaManagementStrategy)).orElse((Boolean) formattingOptionsClass.getMethod("getManageTrailingCommas").invoke(formattingOptions))); + } else { + Class styleClass = classLoader.loadClass(formattingOptionsClass.getName() + "$Style"); + formattingOptions = formattingOptions.getClass().getConstructor(styleClass, int.class, int.class, int.class, boolean.class, boolean.class, TrailingCommaManagementStrategy.class).newInstance( + /* style = */ formattingOptionsClass.getMethod("getStyle").invoke(formattingOptions), + /* maxWidth = */ Optional.ofNullable(options.maxWidth).orElse((Integer) formattingOptionsClass.getMethod("getMaxWidth").invoke(formattingOptions)), + /* blockIndent = */ Optional.ofNullable(options.blockIndent).orElse((Integer) formattingOptionsClass.getMethod("getBlockIndent").invoke(formattingOptions)), + /* continuationIndent = */ Optional.ofNullable(options.continuationIndent).orElse((Integer) formattingOptionsClass.getMethod("getContinuationIndent").invoke(formattingOptions)), + /* removeUnusedImports = */ Optional.ofNullable(options.removeUnusedImports).orElse((Boolean) formattingOptionsClass.getMethod("getRemoveUnusedImports").invoke(formattingOptions)), + /* debuggingPrintOpsAfterFormatting = */ (Boolean) formattingOptionsClass.getMethod("getDebuggingPrintOpsAfterFormatting").invoke(formattingOptions), + /* trailingCommaManagementStrategy */ Optional.ofNullable(options.trailingCommaManagementStrategy).orElse((TrailingCommaManagementStrategy) formattingOptionsClass.getMethod("getTrailingCommaManagementStrategy").invoke(formattingOptions))); } } @@ -422,5 +472,18 @@ private Class getFormattingOptionsClazz() throws Exception { } return formattingOptionsClazz; } + + private @Nullable Boolean getManageTrailingCommasFrom( + @Nullable TrailingCommaManagementStrategy trailingCommaManagementStrategy + ) { + if (trailingCommaManagementStrategy == null) { + return null; + } + + return switch (trailingCommaManagementStrategy) { + case NONE, ONLY_ADD -> false; + case COMPLETE -> true; + }; + } } } diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 5ea29c04e6..032bcc7533 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -11,6 +11,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Bump default `ktlint` version to latest `1.5.0` -> `1.7.1`. ([#2555](https://github.com/diffplug/spotless/pull/2555)) * Bump default `jackson` version to latest `2.19.2` -> `2.20.0`. ([#2606](https://github.com/diffplug/spotless/pull/2606)) * Running `spotlessCheck` with violations unilaterally produces the error message `Run './gradlew spotlessApply' to fix these violations`. ([#2592](https://github.com/diffplug/spotless/issues/2592)) +* **BREAKING** Bump default `ktfmt` version to latest `0.53` -> `0.58` ([#2613](https://github.com/diffplug/spotless/pull/2613)) + * use `TrailingCommaManagementStrategy` enum instead of `manageTrailingCommas` boolean configuration option + ### Fixed * Respect system gitconfig when performing git operations ([#2404](https://github.com/diffplug/spotless/issues/2404)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 31947a036d..903dbbdf47 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -515,7 +515,7 @@ spotless { it.setBlockIndent(4) it.setContinuationIndent(4) it.setRemoveUnusedImports(false) - it.setManageTrailingCommas(false) + it.setTrailingCommaManagementStrategy(TrailingCommaManagementStrategy.NONE) } } } 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 2132ac11e4..f986d83717 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 @@ -47,6 +47,7 @@ void integrationDiktat() throws IOException { @Test void integrationKtfmtDropboxStyleWithPublicApi() throws IOException { setFile("build.gradle.kts").toLines( + "import com.diffplug.spotless.kotlin.KtfmtStep.TrailingCommaManagementStrategy", "plugins {", " id(\"org.jetbrains.kotlin.jvm\") version \"1.6.21\"", " id(\"com.diffplug.spotless\")", @@ -59,7 +60,7 @@ void integrationKtfmtDropboxStyleWithPublicApi() throws IOException { " it.setBlockIndent(4)", " it.setContinuationIndent(4)", " it.setRemoveUnusedImports(false)", - " it.setManageTrailingCommas(false)", + " it.setTrailingCommaManagementStrategy(TrailingCommaManagementStrategy.NONE)", " }", " }", "}"); diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 812b710ee0..858ef20d54 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -11,6 +11,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Bump default `ktlint` version to latest `1.5.0` -> `1.7.1`. ([#2555](https://github.com/diffplug/spotless/pull/2555)) * Bump default `jackson` version to latest `2.19.2` -> `2.20.0`. ([#2606](https://github.com/diffplug/spotless/pull/2606)) * Bump default `gson` version to latest `2.13.1` -> `2.13.2`. ([#2615](https://github.com/diffplug/spotless/pull/2615)) +* **BREAKING** Bump default `ktfmt` version to latest `0.53` -> `0.58` ([#2613](https://github.com/diffplug/spotless/pull/2613)) + * use `TrailingCommaManagementStrategy` enum instead of `manageTrailingCommas` boolean configuration option ## [2.46.1] - 2025-07-21 ### Fixed diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 05903b7540..7efd7c3157 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -473,7 +473,7 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T 4 8 false - true + COMPLETE ``` diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java index 4c5c4628d3..12fd4090c9 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 DiffPlug + * Copyright 2016-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import com.diffplug.spotless.kotlin.KtfmtStep; import com.diffplug.spotless.kotlin.KtfmtStep.KtfmtFormattingOptions; import com.diffplug.spotless.kotlin.KtfmtStep.Style; +import com.diffplug.spotless.kotlin.KtfmtStep.TrailingCommaManagementStrategy; import com.diffplug.spotless.maven.FormatterStepConfig; import com.diffplug.spotless.maven.FormatterStepFactory; @@ -45,13 +46,13 @@ public class Ktfmt implements FormatterStepFactory { private Boolean removeUnusedImports; @Parameter - private Boolean manageTrailingCommas; + private TrailingCommaManagementStrategy trailingCommaManagementStrategy; @Override public FormatterStep newFormatterStep(FormatterStepConfig config) { String version = this.version != null ? this.version : KtfmtStep.defaultVersion(); Style style = this.style != null ? Style.valueOf(this.style) : null; - KtfmtFormattingOptions options = new KtfmtFormattingOptions(maxWidth, blockIndent, continuationIndent, removeUnusedImports, manageTrailingCommas); + KtfmtFormattingOptions options = new KtfmtFormattingOptions(maxWidth, blockIndent, continuationIndent, removeUnusedImports, trailingCommaManagementStrategy); return KtfmtStep.create(version, config.getProvisioner(), style, options); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java index 68d99c8186..5869422995 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 DiffPlug + * Copyright 2016-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ void testKtfmtWithMaxWidthOption() throws Exception { @Test void testKtfmtStyleWithMaxWidthOption() throws Exception { - writePomWithKotlinSteps("0.17120"); + writePomWithKotlinSteps("0.50120"); setFile("src/main/kotlin/main.kt").toResource("kotlin/ktfmt/max-width.dirty"); mavenRunner().withArguments("spotless:apply").runNoError(); @@ -74,7 +74,7 @@ void testKtfmtStyleWithMaxWidthOption() throws Exception { @Test void testKtfmtWithManageTrailingCommasOption() throws Exception { - writePomWithKotlinSteps("0.49true"); + writePomWithKotlinSteps("0.49COMPLETE"); setFile("src/main/kotlin/main.kt").toResource("kotlin/ktfmt/trailing-commas.dirty"); mavenRunner().withArguments("spotless:apply").runNoError(); diff --git a/testlib/src/main/resources/kotlin/ktfmt/continuation.clean b/testlib/src/main/resources/kotlin/ktfmt/continuation.clean index 11677928fc..9bbb9a5d7b 100644 --- a/testlib/src/main/resources/kotlin/ktfmt/continuation.clean +++ b/testlib/src/main/resources/kotlin/ktfmt/continuation.clean @@ -1,6 +1,8 @@ fun myFunction() { val location = restTemplate.postForLocation( - "/v1/my-api", mapOf("name" to "some-name", "url" to "https://www.google.com")) + "/v1/my-api", + mapOf("name" to "some-name", "url" to "https://www.google.com"), + ) return location } diff --git a/testlib/src/main/resources/kotlin/ktfmt/trailing-commas-only-add.clean b/testlib/src/main/resources/kotlin/ktfmt/trailing-commas-only-add.clean new file mode 100644 index 0000000000..7f10d0537c --- /dev/null +++ b/testlib/src/main/resources/kotlin/ktfmt/trailing-commas-only-add.clean @@ -0,0 +1,13 @@ +import a.* + +fun foo( + paramA: String, + paramB: Int, + anotherParamIsHere: Float, + myLongParamNameIsHere: CustomType, + lastParam: Boolean, +) = Unit + +fun bar( + myLongParamNameIsHereButDoesNotWrap: Int, +) = Unit diff --git a/testlib/src/main/resources/kotlin/ktfmt/trailing-commas-only-add.dirty b/testlib/src/main/resources/kotlin/ktfmt/trailing-commas-only-add.dirty new file mode 100644 index 0000000000..4767c419e8 --- /dev/null +++ b/testlib/src/main/resources/kotlin/ktfmt/trailing-commas-only-add.dirty @@ -0,0 +1,8 @@ +import a.* + +fun foo(paramA: String,paramB : Int , anotherParamIsHere: Float ,myLongParamNameIsHere: CustomType +,lastParam: Boolean ) = Unit + +fun bar( + myLongParamNameIsHereButDoesNotWrap: Int, +) = Unit diff --git a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java index 56687d0578..49f9a5e884 100644 --- a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 DiffPlug + * Copyright 2016-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ */ package com.diffplug.spotless.kotlin; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + import org.junit.jupiter.api.Test; import com.diffplug.spotless.*; @@ -65,11 +67,32 @@ void dropboxStyle_0_50() throws Exception { @Test void behaviorWithTrailingCommas() throws Exception { KtfmtStep.KtfmtFormattingOptions options = new KtfmtStep.KtfmtFormattingOptions(); - options.setManageTrailingCommas(true); + options.setTrailingCommaManagementStrategy(KtfmtStep.TrailingCommaManagementStrategy.COMPLETE); FormatterStep step = KtfmtStep.create("0.49", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, options); StepHarness.forStep(step).testResource("kotlin/ktfmt/trailing-commas.dirty", "kotlin/ktfmt/trailing-commas.clean"); } + @Test + void behaviorWithTrailingCommaManagementStrategyOnlyAdd() { + KtfmtStep.KtfmtFormattingOptions options = new KtfmtStep.KtfmtFormattingOptions(); + options.setTrailingCommaManagementStrategy(KtfmtStep.TrailingCommaManagementStrategy.ONLY_ADD); + FormatterStep step = KtfmtStep.create("0.58", TestProvisioner.mavenCentral(), KtfmtStep.Style.KOTLINLANG, options); + StepHarness.forStep(step).testResource( + "kotlin/ktfmt/trailing-commas-only-add.dirty", + "kotlin/ktfmt/trailing-commas-only-add.clean"); + } + + @Test + void trailingCommaManagementStrategyOnlyAddUnsupportedBefore_0_57() { + KtfmtStep.KtfmtFormattingOptions options = new KtfmtStep.KtfmtFormattingOptions(); + options.setTrailingCommaManagementStrategy(KtfmtStep.TrailingCommaManagementStrategy.ONLY_ADD); + var step = KtfmtStep.create("0.56", TestProvisioner.mavenCentral(), KtfmtStep.Style.KOTLINLANG, options); + + assertThatThrownBy(() -> StepHarness.forStep(step)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("ONLY_ADD"); + } + @Test void equality() throws Exception { new SerializableEqualityTester() {