diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index becceb0b0c..958390b347 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -11,6 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Fixed * You can now use `removeUnusedImports` and `googleJavaFormat` at the same time again. (fixes [#2159](https://github.com/diffplug/spotless/issues/2159)) * The default list of type annotations used by `formatAnnotations` now includes Jakarta Validation's `Valid` and constraints validations (fixes [#2334](https://github.com/diffplug/spotless/issues/2334)) +* `indentWith[Spaces|Tabs]` has been deprecated in favor of `leadingTabsToSpaces` and `leadingSpacesToTabs`. ([#2350](https://github.com/diffplug/spotless/pull/2350) fixes [#794](https://github.com/diffplug/spotless/issues/794)) ## [7.0.0.BETA4] - 2024-10-24 ### Added diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 89c260085b..90078f191d 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -109,7 +109,7 @@ spotless { // define the steps to apply to those files trimTrailingWhitespace() - indentWithTabs() // or spaces. Takes an integer argument if you don't like 4 + leadingSpacesToTabs() // or leadingTabsToSpaces. Takes an integer argument if you don't like 4 endWithNewline() } java { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java index 56cccc52c9..59898cbf56 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java @@ -47,6 +47,8 @@ import org.gradle.api.plugins.BasePlugin; import org.gradle.api.tasks.TaskProvider; import org.gradle.util.GradleVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.diffplug.common.base.Preconditions; import com.diffplug.spotless.FormatterFunc; @@ -77,6 +79,9 @@ /** Adds a {@code spotless{Name}Check} and {@code spotless{Name}Apply} task. */ public class FormatExtension { + + private static final Logger logger = LoggerFactory.getLogger(FormatExtension.class); + final SpotlessExtension spotless; final List> lazyActions = new ArrayList<>(); @@ -505,25 +510,53 @@ public void endWithNewline() { } /** Ensures that the files are indented using spaces. */ + public void leadingTabsToSpaces(int spacesPerTab) { + addStep(IndentStep.Type.SPACE.create(spacesPerTab)); + } + + @Deprecated public void indentWithSpaces(int numSpacesPerTab) { - addStep(IndentStep.Type.SPACE.create(numSpacesPerTab)); + logDeprecation("indentWithSpaces", "leadingTabsToSpaces"); + leadingTabsToSpaces(numSpacesPerTab); } /** Ensures that the files are indented using spaces. */ - public void indentWithSpaces() { + public void leadingTabsToSpaces() { addStep(IndentStep.Type.SPACE.create()); } + @Deprecated + public void indentWithSpaces() { + logDeprecation("indentWithSpaces", "leadingTabsToSpaces"); + leadingTabsToSpaces(); + } + /** Ensures that the files are indented using tabs. */ + public void leadingSpacesToTabs(int spacesPerTab) { + addStep(IndentStep.Type.TAB.create(spacesPerTab)); + } + + @Deprecated public void indentWithTabs(int tabToSpaces) { - addStep(IndentStep.Type.TAB.create(tabToSpaces)); + logDeprecation("indentWithTabs", "leadingSpacesToTabs"); + leadingSpacesToTabs(tabToSpaces); } /** Ensures that the files are indented using tabs. */ - public void indentWithTabs() { + public void leadingSpacesToTabs() { addStep(IndentStep.Type.TAB.create()); } + @Deprecated + public void indentWithTabs() { + logDeprecation("indentWithTabs", "leadingSpacesToTabs"); + leadingSpacesToTabs(); + } + + private static void logDeprecation(String methodName, String replacement) { + logger.warn("'{}' is deprecated, use '{}' in your gradle build script instead.", methodName, replacement); + } + /** Ensures formatting of files via native binary. */ public void nativeCmd(String name, String pathToExe, List arguments) { addStep(NativeCmdStep.create(name, new File(pathToExe), arguments)); diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/IndentIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/IndentIntegrationTest.java new file mode 100644 index 0000000000..fc883b41e9 --- /dev/null +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/IndentIntegrationTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2021-2024 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.gradle.spotless; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.util.stream.Stream; + +import org.gradle.testkit.runner.BuildResult; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +class IndentIntegrationTest extends GradleIntegrationHarness { + + @ParameterizedTest + @ValueSource(strings = {"indentWithSpaces", "indentWithTabs"}) + void oldIndentApiLogsDeprecationWarning(String indentationMethodName) throws IOException { + BuildResult result = runIndentFormatter(indentationMethodName); + assertThat(result.getOutput()).containsPattern(".*" + indentationMethodName + ".*deprecated.*"); + } + + @ParameterizedTest + @ValueSource(strings = {"leadingTabsToSpaces", "leadingSpacesToTabs"}) + void newIndentApiDoesNotLogDeprecationWarning(String indentationMethodName) throws IOException { + BuildResult result = runIndentFormatter(indentationMethodName); + assertThat(result.getOutput()).doesNotContainPattern(".*" + indentationMethodName + ".*deprecated.*"); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("indentationCombinations") + void indentationCombinations(String testName, String indentationMethodName, String actualResource, String expectedResultResource) throws IOException { + runIndentFormatter(indentationMethodName, actualResource); + assertFile("test.txt").sameAsResource(expectedResultResource); + } + + private static Stream indentationCombinations() { + return Stream.of( + // new API + Arguments.of("tabsToTabs", "leadingSpacesToTabs", "indent/IndentedWithTab.test", "indent/IndentedWithTab.test"), + Arguments.of("spacesToSpaces", "leadingTabsToSpaces", "indent/IndentedWithSpace.test", "indent/IndentedWithSpace.test"), + Arguments.of("spacesToTabs", "leadingSpacesToTabs", "indent/IndentedWithSpace.test", "indent/IndentedWithTab.test"), + Arguments.of("tabsToSpaces", "leadingTabsToSpaces", "indent/IndentedWithTab.test", "indent/IndentedWithSpace.test"), + Arguments.of("mixedToTabs", "leadingSpacesToTabs", "indent/IndentedMixed.test", "indent/IndentedWithTab.test"), + Arguments.of("mixedToSpaces", "leadingTabsToSpaces", "indent/IndentedMixed.test", "indent/IndentedWithSpace.test"), + // legacy API + Arguments.of("legacy: tabsToTabs", "indentWithTabs", "indent/IndentedWithTab.test", "indent/IndentedWithTab.test"), + Arguments.of("legacy: spacesToSpaces", "indentWithSpaces", "indent/IndentedWithSpace.test", "indent/IndentedWithSpace.test"), + Arguments.of("legacy: spacesToTabs", "indentWithTabs", "indent/IndentedWithSpace.test", "indent/IndentedWithTab.test"), + Arguments.of("legacy: tabsToSpaces", "indentWithSpaces", "indent/IndentedWithTab.test", "indent/IndentedWithSpace.test"), + Arguments.of("legacy: mixedToTabs", "indentWithTabs", "indent/IndentedMixed.test", "indent/IndentedWithTab.test"), + Arguments.of("legacy: mixedToSpaces", "indentWithSpaces", "indent/IndentedMixed.test", "indent/IndentedWithSpace.test")); + } + + private BuildResult runIndentFormatter(String indentationMethodName) throws IOException { + return runIndentFormatter(indentationMethodName, "indent/IndentedMixed.test"); + } + + private BuildResult runIndentFormatter(String indentationMethodName, String resourceFile) throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "spotless {", + " format 'test', {", + " target '**/*.txt'", + " " + indentationMethodName + "()", + " }", + "}"); + setFile("test.txt").toResource(resourceFile); + BuildResult result = gradleRunner().withArguments("spotlessApply").build(); + return result; + } + +} diff --git a/testlib/src/main/resources/indent/IndentedMixed.test b/testlib/src/main/resources/indent/IndentedMixed.test new file mode 100644 index 0000000000..37c108c1df --- /dev/null +++ b/testlib/src/main/resources/indent/IndentedMixed.test @@ -0,0 +1,37 @@ +package com.github.youribonnaffe.gradle.format; + +import java.util.function.Function; + +/** + * Test class. + */ +public class Java8Test { + /** + * Test method. + */ + public void doStuff() throws Exception { + Function example = Integer::parseInt; + example.andThen(val -> { + return val + 2; + } ); + SimpleEnum val = SimpleEnum.A; + switch (val) { + case A: + break; + case B: + break; + case C: + break; + default: + throw new Exception(); + } + } + + /** Test enum + * with weirdly formatted javadoc + * which IndentStep should not change + */ + public enum SimpleEnum { + A, B, C; + } +}