From 6419de194845da533ecfb1a0bb1afd92e07dab0e Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Thu, 11 Jan 2024 18:04:39 +0300 Subject: [PATCH 001/210] Basic IDEA usage locally. Thought of implementation plan, experimented with code dependencies using tests. --- .../com/diffplug/spotless/java/IdeaStep.java | 40 +++++++++++++++ .../main/resources/java/idea/full.clean.java | 14 ++++++ .../main/resources/java/idea/full.dirty.java | 22 ++++++++ .../diffplug/spotless/java/IdeaStepTest.java | 50 +++++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java create mode 100644 testlib/src/main/resources/java/idea/full.clean.java create mode 100644 testlib/src/main/resources/java/idea/full.dirty.java create mode 100644 testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java new file mode 100644 index 0000000000..3c3021b644 --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -0,0 +1,40 @@ +package com.diffplug.spotless.java; + +import java.io.File; +import java.nio.file.Files; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.diffplug.spotless.FormatterFunc; +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.ProcessRunner; + +public class IdeaStep { + + private static final Logger LOGGER = + LoggerFactory.getLogger(IdeaStep.class); + + public static FormatterStep create() { + // TODO: make it lazy + return FormatterStep.createNeverUpToDate("IDEA", + new FormatterFunc.NeedsFile() { + + // TODO: parameterize so user is able to provide it's own file + // TODO: Use ForeignExe to ensure file + private final String binaryPath = + "idea"; + + @Override + public String applyWithFile(String unix, File file) + throws Exception { + try (ProcessRunner runner = new ProcessRunner()) { + var result = runner.exec(binaryPath, "format", + "-allowDefaults", file.toString()); + LOGGER.debug("command finished with stdout: {}", + result.stdOutUtf8()); + return Files.readString(file.toPath()); + } + } + }); + } + +} diff --git a/testlib/src/main/resources/java/idea/full.clean.java b/testlib/src/main/resources/java/idea/full.clean.java new file mode 100644 index 0000000000..84d76d4650 --- /dev/null +++ b/testlib/src/main/resources/java/idea/full.clean.java @@ -0,0 +1,14 @@ +package com.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} + diff --git a/testlib/src/main/resources/java/idea/full.dirty.java b/testlib/src/main/resources/java/idea/full.dirty.java new file mode 100644 index 0000000000..83923130e6 --- /dev/null +++ b/testlib/src/main/resources/java/idea/full.dirty.java @@ -0,0 +1,22 @@ +package com.example; + +import org.springframework.boot.SpringApplication; + + + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@ + +SpringBootApplication +public + + +class Application{ + + public static void main( String[] args) { + SpringApplication. run(Application.class, args); + } + +} + diff --git a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java new file mode 100644 index 0000000000..6a7e066b48 --- /dev/null +++ b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java @@ -0,0 +1,50 @@ +package com.diffplug.spotless.java; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import com.diffplug.common.io.Files; +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.ResourceHarness; + +class IdeaStepTest extends ResourceHarness { + + @Test + void name() throws Exception { + FormatterStep step = IdeaStep.create(); + + String name = step.getName(); + + Assertions.assertEquals("IDEA", name); + } + + @Test + void notFormattings() throws Exception { + File cleanFile = newFile("clean.java"); + String cleanJava = + ResourceHarness.getTestResource("java/idea/full.clean.java"); + Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8); + FormatterStep step = IdeaStep.create(); + + var result = step.format(cleanJava, cleanFile); + + Assertions.assertEquals(cleanJava, result, + "formatting was applied to clean file"); + } + + @Test + void formattings() throws Exception { + File dirtyFile = newFile("dirty.java"); + String dirtyJava = + ResourceHarness.getTestResource("java/idea/full.dirty.java"); + Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8); + FormatterStep step = IdeaStep.create(); + + var result = step.format(dirtyJava, dirtyFile); + + Assertions.assertNotEquals(dirtyJava, result, + "files were not changed after reformat"); + } + +} From b84d24331f2839ca628867cb66fa94d4dbb48664 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Tue, 23 Jan 2024 22:31:38 +0300 Subject: [PATCH 002/210] Parameterize IDEA usage. Added parameterized method to call idea formatter. --- .../spotless/java/IdeaFormatterFunc.java | 66 +++++++++++++++++++ .../com/diffplug/spotless/java/IdeaStep.java | 52 +++++++-------- .../diffplug/spotless/java/IdeaStepTest.java | 45 ++++++++++++- 3 files changed, 132 insertions(+), 31 deletions(-) create mode 100644 lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java new file mode 100644 index 0000000000..55e9989bda --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java @@ -0,0 +1,66 @@ +package com.diffplug.spotless.java; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.diffplug.spotless.FormatterFunc; +import com.diffplug.spotless.ProcessRunner; + +public final class IdeaFormatterFunc implements FormatterFunc.NeedsFile { + + private static final Logger LOGGER = + LoggerFactory.getLogger(IdeaStep.class); + + private static final String DEFAULT_IDEA = "idea"; + + // TODO: Use ForeignExe to ensure file + private final String binaryPath; + private final boolean withDefaults; + + private IdeaFormatterFunc(boolean withDefaults, String binaryPath) { + this.withDefaults = withDefaults; + this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); + } + + public static IdeaFormatterFunc allowingDefaultsWithCustomBinary( + String binaryPath) { + return new IdeaFormatterFunc(true, binaryPath); + } + + public static IdeaFormatterFunc noDefaultsWithCustomBinary( + String binaryPath) { + return new IdeaFormatterFunc(false, binaryPath); + } + + @Override + public String applyWithFile(String unix, File file) throws Exception { + List params = getParams(file); + + try (ProcessRunner runner = new ProcessRunner()) { + var result = runner.exec(params); + + LOGGER.debug("command finished with stdout: {}", + result.assertExitZero(StandardCharsets.UTF_8)); + + return Files.readString(file.toPath()); + } + } + + private List getParams(File file) { + var builder = Stream.builder(); + builder.add(binaryPath); + builder.add("format"); + if (withDefaults) { + builder.add("-allowDefaults"); + } + builder.add(file.toString()); + return builder.build().collect(Collectors.toList()); + } + +} diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java index 3c3021b644..a2240a067d 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -1,40 +1,34 @@ package com.diffplug.spotless.java; -import java.io.File; -import java.nio.file.Files; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.diffplug.spotless.FormatterFunc; import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.ProcessRunner; -public class IdeaStep { +public final class IdeaStep { - private static final Logger LOGGER = - LoggerFactory.getLogger(IdeaStep.class); + private IdeaStep() {} public static FormatterStep create() { + return create(true); + } + + public static FormatterStep create(boolean withDefaults) { + return create(true, null); + } + + public static FormatterStep create(boolean withDefaults, + String binaryPath) { + IdeaFormatterFunc formatterFunc = + getFormatterFunc(withDefaults, binaryPath); // TODO: make it lazy - return FormatterStep.createNeverUpToDate("IDEA", - new FormatterFunc.NeedsFile() { - - // TODO: parameterize so user is able to provide it's own file - // TODO: Use ForeignExe to ensure file - private final String binaryPath = - "idea"; - - @Override - public String applyWithFile(String unix, File file) - throws Exception { - try (ProcessRunner runner = new ProcessRunner()) { - var result = runner.exec(binaryPath, "format", - "-allowDefaults", file.toString()); - LOGGER.debug("command finished with stdout: {}", - result.stdOutUtf8()); - return Files.readString(file.toPath()); - } - } - }); + return FormatterStep.createNeverUpToDate("IDEA", formatterFunc); + } + + private static IdeaFormatterFunc getFormatterFunc(boolean withDefaults, + String binaryPath) { + if (withDefaults) { + return IdeaFormatterFunc + .allowingDefaultsWithCustomBinary(binaryPath); + } + return IdeaFormatterFunc.noDefaultsWithCustomBinary(binaryPath); } } diff --git a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java index 6a7e066b48..670faa7c8b 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java @@ -12,7 +12,7 @@ class IdeaStepTest extends ResourceHarness { @Test void name() throws Exception { - FormatterStep step = IdeaStep.create(); + FormatterStep step = IdeaStep.create(true, "idea"); String name = step.getName(); @@ -25,7 +25,7 @@ void notFormattings() throws Exception { String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java"); Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8); - FormatterStep step = IdeaStep.create(); + FormatterStep step = IdeaStep.create(true, "idea"); var result = step.format(cleanJava, cleanFile); @@ -35,6 +35,20 @@ void notFormattings() throws Exception { @Test void formattings() throws Exception { + File dirtyFile = newFile("dirty.java"); + String dirtyJava = + ResourceHarness.getTestResource("java/idea/full.dirty.java"); + Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8); + FormatterStep step = IdeaStep.create(true, "idea"); + + var result = step.format(dirtyJava, dirtyFile); + + Assertions.assertNotEquals(dirtyJava, result, + "files were not changed after reformat"); + } + + @Test + void formattingsWorkWithDefaultParameters() throws Exception { File dirtyFile = newFile("dirty.java"); String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java"); @@ -47,4 +61,31 @@ void formattings() throws Exception { "files were not changed after reformat"); } + @Test + void formattingsNotDeafaultDoesNothing() throws Exception { + File dirtyFile = newFile("dirty.java"); + String dirtyJava = + ResourceHarness.getTestResource("java/idea/full.dirty.java"); + Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8); + FormatterStep step = IdeaStep.create(false, "idea"); + + var result = step.format(dirtyJava, dirtyFile); + + Assertions.assertEquals(dirtyJava, result, + "files were changed after reformat"); + } + + @Test + void configureFile() throws Exception { + File cleanFile = newFile("clean.java"); + String cleanJava = + ResourceHarness.getTestResource("java/idea/full.clean.java"); + Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8); + FormatterStep step = IdeaStep.create(true, "idea"); + + var result = step.format(cleanJava, cleanFile); + + Assertions.assertEquals(cleanJava, result, + "formatting was applied to clean file"); + } } From 1d8d9b20034fa00558036d718ae2429519e1229c Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Tue, 23 Jan 2024 22:46:43 +0300 Subject: [PATCH 003/210] Verify IDEA binary. Used ForeignExe to check idea binary --- .../spotless/java/IdeaFormatterFunc.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java index 55e9989bda..68d26bc304 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java @@ -1,14 +1,17 @@ package com.diffplug.spotless.java; import java.io.File; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.List; import java.util.Objects; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.diffplug.spotless.ForeignExe; import com.diffplug.spotless.FormatterFunc; import com.diffplug.spotless.ProcessRunner; @@ -19,13 +22,30 @@ public final class IdeaFormatterFunc implements FormatterFunc.NeedsFile { private static final String DEFAULT_IDEA = "idea"; - // TODO: Use ForeignExe to ensure file - private final String binaryPath; - private final boolean withDefaults; + private String binaryPath; + private boolean withDefaults; private IdeaFormatterFunc(boolean withDefaults, String binaryPath) { this.withDefaults = withDefaults; this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); + resolveFullBinaryPathAndCheckVersion(); + } + + private void resolveFullBinaryPathAndCheckVersion() { + var exe = ForeignExe.nameAndVersion(this.binaryPath, "IntelliJ IDEA") + .versionRegex(Pattern.compile("(IntelliJ IDEA) .*")) + .fixCantFind("IDEA executable cannot be found on your machine, " + + "please install it and put idea binary to PATH; or report the problem") + .fixWrongVersion("Provided binary is not IDEA, " + + "please check it and fix the problem; or report the problem"); + try { + this.binaryPath = exe.confirmVersionAndGetAbsolutePath(); + } catch (IOException e) { + throw new IllegalArgumentException("binary cannot be found", e); + } catch (InterruptedException e) { + throw new IllegalArgumentException( + "binary cannot be found, process was interrupted", e); + } } public static IdeaFormatterFunc allowingDefaultsWithCustomBinary( From affd905be602b818e3084ffe186ae1149b829eb1 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Tue, 23 Jan 2024 23:17:24 +0300 Subject: [PATCH 004/210] Gradle IDEA integration. IDEA running using gradle --- .../gradle/spotless/JavaExtension.java | 34 ++++++++++++++- .../gradle/spotless/JavaIdeaTest.java | 41 +++++++++++++++++++ .../diffplug/spotless/ResourceHarness.java | 12 ++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index db869dc4e6..a191e3ef50 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -39,6 +39,7 @@ import com.diffplug.spotless.java.CleanthatJavaStep; import com.diffplug.spotless.java.FormatAnnotationsStep; import com.diffplug.spotless.java.GoogleJavaFormatStep; +import com.diffplug.spotless.java.IdeaStep; import com.diffplug.spotless.java.ImportOrderStep; import com.diffplug.spotless.java.PalantirJavaFormatStep; import com.diffplug.spotless.java.RemoveUnusedImportsStep; @@ -313,6 +314,37 @@ public EclipseConfig withP2Mirrors(Map mirrors) { } + public IdeaConfig idea() { + return new IdeaConfig(); + } + + public class IdeaConfig { + String binaryPath; + boolean withDefaults = false; + + IdeaConfig() { + addStep(createStep()); + } + + private FormatterStep createStep() { + return IdeaStep.create(withDefaults, binaryPath); + } + + public IdeaConfig binaryPath(String binaryPath) { + Objects.requireNonNull(binaryPath); + this.binaryPath = binaryPath; + replaceStep(createStep()); + return this; + } + + public IdeaConfig withDefaults(Boolean withDefaults) { + Objects.requireNonNull(withDefaults); + this.withDefaults = withDefaults; + replaceStep(createStep()); + return this; + } + } + /** Removes newlines between type annotations and types. */ public FormatAnnotationsConfig formatAnnotations() { return new FormatAnnotationsConfig(); @@ -400,7 +432,7 @@ public CleanthatJavaConfig clearMutators() { } // An id of a mutator (see IMutator.getIds()) or - // tThe fully qualified name of a class implementing eu.solven.cleanthat.engine.java.refactorer.meta.IMutator + // The fully qualified name of a class implementing eu.solven.cleanthat.engine.java.refactorer.meta.IMutator public CleanthatJavaConfig addMutator(String mutator) { this.mutators.add(mutator); replaceStep(createStep()); diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java new file mode 100644 index 0000000000..d899b13203 --- /dev/null +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2020-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 java.io.IOException; + +import org.junit.jupiter.api.Test; + + +class JavaIdeaTest extends GradleIntegrationHarness { + @Test + void idea() throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "spotless {", + " java {", + " target file('test.java')", + " idea().binaryPath('idea').withDefaults(true)", + " }", + "}"); + + setFile("test.java").toResource("java/idea/full.dirty.java"); + gradleRunner().withArguments("spotlessApply").build(); + assertFile("test.java").notSameAsResource("java/idea/full.dirty.java"); + } +} diff --git a/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java b/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java index 0304889e1f..fcdfa2f97d 100644 --- a/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java +++ b/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java @@ -151,10 +151,18 @@ public void hasContent(String expected) { hasContent(expected, StandardCharsets.UTF_8); } + public void hasDifferentContent(String expected) { + hasDifferentContent(expected, StandardCharsets.UTF_8); + } + public void hasContent(String expected, Charset charset) { assertThat(file).usingCharset(charset).hasContent(expected); } + public void hasDifferentContent(String expected, Charset charset) { + assertThat(file).usingCharset(charset).isNotEqualTo(expected); + } + public void hasLines(String... lines) { hasContent(String.join("\n", Arrays.asList(lines))); } @@ -163,6 +171,10 @@ public void sameAsResource(String resource) throws IOException { hasContent(getTestResource(resource)); } + public void notSameAsResource(String resource) throws IOException { + hasDifferentContent(getTestResource(resource)); + } + public void matches(Consumer> conditions) throws IOException { String content = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); conditions.accept(assertThat(content)); From effe2fcfdb0679598b6c83d2cd9dbbc965237c03 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Tue, 23 Jan 2024 23:26:10 +0300 Subject: [PATCH 005/210] Maven IDEA integration. IDEA running using maven --- .../diffplug/spotless/maven/java/Idea.java | 36 +++++++++++++++++++ .../diffplug/spotless/maven/java/Java.java | 4 +++ .../spotless/maven/java/IdeaTest.java | 36 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java create mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java new file mode 100644 index 0000000000..182178c797 --- /dev/null +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016-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.spotless.maven.java; + +import org.apache.maven.plugins.annotations.Parameter; +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.java.IdeaStep; +import com.diffplug.spotless.maven.FormatterStepConfig; +import com.diffplug.spotless.maven.FormatterStepFactory; + +public class Idea implements FormatterStepFactory { + + @Parameter + private String binaryPath; + + @Parameter + private Boolean withDefaults = false; + + @Override + public FormatterStep newFormatterStep(FormatterStepConfig config) { + return IdeaStep.create(withDefaults, binaryPath); + } +} diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java index b0692446b7..751da56ae9 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java @@ -68,6 +68,10 @@ public void addImportOrder(ImportOrder importOrder) { addStepFactory(importOrder); } + public void addIdea(Idea idea) { + addStepFactory(idea); + } + public void addPalantirJavaFormat(PalantirJavaFormat palantirJavaFormat) { addStepFactory(palantirJavaFormat); } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java new file mode 100644 index 0000000000..05747eae06 --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016-2021 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.maven.java; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.maven.MavenIntegrationHarness; + +class IdeaTest extends MavenIntegrationHarness { + @Test + void idea() throws Exception { + setFile("test.java").toResource("java/cleanthat/MultipleMutators.dirty.test"); + writePomWithJavaSteps( + "", + " idea", + " true", + ""); + + mavenRunner().withArguments("spotless:apply").runNoError(); + + assertFile("test.java").notSameAsResource("java/cleanthat/MultipleMutators.dirty.test"); + } +} From 8e301758f6e70d55b2d8dd3db3aff8214bf4b117 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Tue, 23 Jan 2024 23:30:56 +0300 Subject: [PATCH 006/210] Make IDEA tests special As described here: https://github.com/diffplug/spotless/issues/200#issuecomment-1905302847 --- gradle/special-tests.gradle | 1 + .../gradle/spotless/JavaIdeaTest.java | 3 +- .../spotless/maven/java/IdeaTest.java | 1 + .../com/diffplug/spotless/tag/IdeaTest.java | 30 +++++++++++++++++++ .../diffplug/spotless/java/IdeaStepTest.java | 2 ++ 5 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java diff --git a/gradle/special-tests.gradle b/gradle/special-tests.gradle index 8d9004a709..58a21f0cb2 100644 --- a/gradle/special-tests.gradle +++ b/gradle/special-tests.gradle @@ -6,6 +6,7 @@ def special = [ 'Buf', 'Clang', 'gofmt', + 'idea', 'Npm', 'Shfmt' ] diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java index d899b13203..2e51f26bb0 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java @@ -18,8 +18,9 @@ import java.io.IOException; import org.junit.jupiter.api.Test; +import com.diffplug.spotless.tag.IdeaTest; - +@IdeaTest class JavaIdeaTest extends GradleIntegrationHarness { @Test void idea() throws IOException { diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java index 05747eae06..575f88c29c 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java @@ -19,6 +19,7 @@ import com.diffplug.spotless.maven.MavenIntegrationHarness; +@com.diffplug.spotless.tag.IdeaTest class IdeaTest extends MavenIntegrationHarness { @Test void idea() throws Exception { diff --git a/testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java b/testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java new file mode 100644 index 0000000000..79813d91d9 --- /dev/null +++ b/testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java @@ -0,0 +1,30 @@ +/* + * 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.spotless.tag; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.Tag; + +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +@Tag("idea") +public @interface IdeaTest {} diff --git a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java index 670faa7c8b..b750fb5677 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java @@ -7,7 +7,9 @@ import com.diffplug.common.io.Files; import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.ResourceHarness; +import com.diffplug.spotless.tag.IdeaTest; +@IdeaTest class IdeaStepTest extends ResourceHarness { @Test From 1554dd6c25d293ed62d872f250aae300e32f81e9 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Tue, 23 Jan 2024 23:41:17 +0300 Subject: [PATCH 007/210] docs: CHANGES.md --- CHANGES.md | 2 ++ plugin-gradle/CHANGES.md | 2 ++ plugin-maven/CHANGES.md | 2 ++ 3 files changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index adf6d109e7..0e6eb2a8c7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) + ## [2.45.0] - 2024-01-23 ### Added * Support for `gofmt` ([#2001](https://github.com/diffplug/spotless/pull/2001)) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index d4ce3b410e..1f81da2ccb 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,6 +4,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) + ## [6.25.0] - 2024-01-23 ### Added * Maven / Gradle - Support for formatting Java Docs for the Palantir formatter ([#2009](https://github.com/diffplug/spotless/pull/2009)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 56cd5a5104..7488008b05 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,6 +4,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) + ## [2.43.0] - 2024-01-23 ### Added * Support for formatting shell scripts via [shfmt](https://github.com/mvdan/sh). ([#1998](https://github.com/diffplug/spotless/issues/1998)) From 763eaac98a888f463759cd86a2bc271b688acfb3 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Tue, 23 Jan 2024 23:57:02 +0300 Subject: [PATCH 008/210] Config file for IDEA step This part is lacking tests due to unpredictable nature of IDEA formatting. They may change configs thus breaking build. --- .../spotless/java/IdeaFormatterFunc.java | 17 ++++++++++++----- .../com/diffplug/spotless/java/IdeaStep.java | 13 +++++++++---- .../diffplug/gradle/spotless/JavaExtension.java | 8 ++++++++ .../com/diffplug/spotless/maven/java/Idea.java | 5 ++++- .../diffplug/spotless/java/IdeaStepTest.java | 2 +- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java index 68d26bc304..282ff37f07 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java @@ -23,10 +23,13 @@ public final class IdeaFormatterFunc implements FormatterFunc.NeedsFile { private static final String DEFAULT_IDEA = "idea"; private String binaryPath; + private String configPath; private boolean withDefaults; - private IdeaFormatterFunc(boolean withDefaults, String binaryPath) { + private IdeaFormatterFunc(boolean withDefaults, String binaryPath, + String configPath) { this.withDefaults = withDefaults; + this.configPath = configPath; this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); resolveFullBinaryPathAndCheckVersion(); } @@ -49,13 +52,13 @@ private void resolveFullBinaryPathAndCheckVersion() { } public static IdeaFormatterFunc allowingDefaultsWithCustomBinary( - String binaryPath) { - return new IdeaFormatterFunc(true, binaryPath); + String binaryPath, String configPath) { + return new IdeaFormatterFunc(true, binaryPath, configPath); } public static IdeaFormatterFunc noDefaultsWithCustomBinary( - String binaryPath) { - return new IdeaFormatterFunc(false, binaryPath); + String binaryPath, String configPath) { + return new IdeaFormatterFunc(false, binaryPath, configPath); } @Override @@ -79,6 +82,10 @@ private List getParams(File file) { if (withDefaults) { builder.add("-allowDefaults"); } + if (configPath != null) { + builder.add("-s"); + builder.add(configPath); + } builder.add(file.toString()); return builder.build().collect(Collectors.toList()); } diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java index a2240a067d..b4efee7c04 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -16,19 +16,24 @@ public static FormatterStep create(boolean withDefaults) { public static FormatterStep create(boolean withDefaults, String binaryPath) { + return create(withDefaults, binaryPath, null); + } + + public static FormatterStep create(boolean withDefaults, + String binaryPath, String configPath) { IdeaFormatterFunc formatterFunc = - getFormatterFunc(withDefaults, binaryPath); + getFormatterFunc(withDefaults, binaryPath, configPath); // TODO: make it lazy return FormatterStep.createNeverUpToDate("IDEA", formatterFunc); } private static IdeaFormatterFunc getFormatterFunc(boolean withDefaults, - String binaryPath) { + String binaryPath, String configPath) { if (withDefaults) { return IdeaFormatterFunc - .allowingDefaultsWithCustomBinary(binaryPath); + .allowingDefaultsWithCustomBinary(binaryPath, configPath); } - return IdeaFormatterFunc.noDefaultsWithCustomBinary(binaryPath); + return IdeaFormatterFunc.noDefaultsWithCustomBinary(binaryPath, configPath); } } diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index a191e3ef50..98617fa787 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -320,6 +320,7 @@ public IdeaConfig idea() { public class IdeaConfig { String binaryPath; + String configPath; boolean withDefaults = false; IdeaConfig() { @@ -337,6 +338,13 @@ public IdeaConfig binaryPath(String binaryPath) { return this; } + public IdeaConfig configPath(String configPath) { + Objects.requireNonNull(configPath); + this.configPath = configPath; + replaceStep(createStep()); + return this; + } + public IdeaConfig withDefaults(Boolean withDefaults) { Objects.requireNonNull(withDefaults); this.withDefaults = withDefaults; diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java index 182178c797..83decc6867 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java @@ -26,11 +26,14 @@ public class Idea implements FormatterStepFactory { @Parameter private String binaryPath; + @Parameter + private String configPath; + @Parameter private Boolean withDefaults = false; @Override public FormatterStep newFormatterStep(FormatterStepConfig config) { - return IdeaStep.create(withDefaults, binaryPath); + return IdeaStep.create(withDefaults, binaryPath, configPath); } } diff --git a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java index b750fb5677..38606c3657 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java @@ -64,7 +64,7 @@ void formattingsWorkWithDefaultParameters() throws Exception { } @Test - void formattingsNotDeafaultDoesNothing() throws Exception { + void formattingsWithOutDefaultDoesNothing() throws Exception { File dirtyFile = newFile("dirty.java"); String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java"); From fdb73b7994f8c15c69e9d3017d8a27eac471d664 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Wed, 24 Jan 2024 09:56:28 +0300 Subject: [PATCH 009/210] CI Fixes --- .../spotless/java/IdeaFormatterFunc.java | 33 +++++++++++++++---- .../com/diffplug/spotless/java/IdeaStep.java | 28 ++++++++++++---- .../gradle/spotless/JavaExtension.java | 8 ++--- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java index 282ff37f07..779dc3b563 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java @@ -1,3 +1,18 @@ +/* + * Copyright 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.spotless.java; import java.io.File; @@ -9,25 +24,29 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; + +import javax.annotation.Nullable; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import com.diffplug.spotless.ForeignExe; import com.diffplug.spotless.FormatterFunc; import com.diffplug.spotless.ProcessRunner; public final class IdeaFormatterFunc implements FormatterFunc.NeedsFile { - private static final Logger LOGGER = - LoggerFactory.getLogger(IdeaStep.class); + private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class); private static final String DEFAULT_IDEA = "idea"; private String binaryPath; + @Nullable private String configPath; private boolean withDefaults; - private IdeaFormatterFunc(boolean withDefaults, String binaryPath, - String configPath) { + private IdeaFormatterFunc(boolean withDefaults, @Nullable String binaryPath, + @Nullable String configPath) { this.withDefaults = withDefaults; this.configPath = configPath; this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); @@ -52,12 +71,12 @@ private void resolveFullBinaryPathAndCheckVersion() { } public static IdeaFormatterFunc allowingDefaultsWithCustomBinary( - String binaryPath, String configPath) { + @Nullable String binaryPath, @Nullable String configPath) { return new IdeaFormatterFunc(true, binaryPath, configPath); } public static IdeaFormatterFunc noDefaultsWithCustomBinary( - String binaryPath, String configPath) { + @Nullable String binaryPath, @Nullable String configPath) { return new IdeaFormatterFunc(false, binaryPath, configPath); } @@ -76,7 +95,7 @@ public String applyWithFile(String unix, File file) throws Exception { } private List getParams(File file) { - var builder = Stream.builder(); + var builder = Stream. builder(); builder.add(binaryPath); builder.add("format"); if (withDefaults) { diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java index b4efee7c04..8839bbdba0 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -1,5 +1,22 @@ +/* + * Copyright 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.spotless.java; +import javax.annotation.Nullable; + import com.diffplug.spotless.FormatterStep; public final class IdeaStep { @@ -11,24 +28,23 @@ public static FormatterStep create() { } public static FormatterStep create(boolean withDefaults) { - return create(true, null); + return create(withDefaults, null); } public static FormatterStep create(boolean withDefaults, - String binaryPath) { + @Nullable String binaryPath) { return create(withDefaults, binaryPath, null); } public static FormatterStep create(boolean withDefaults, - String binaryPath, String configPath) { - IdeaFormatterFunc formatterFunc = - getFormatterFunc(withDefaults, binaryPath, configPath); + @Nullable String binaryPath, @Nullable String configPath) { + IdeaFormatterFunc formatterFunc = getFormatterFunc(withDefaults, binaryPath, configPath); // TODO: make it lazy return FormatterStep.createNeverUpToDate("IDEA", formatterFunc); } private static IdeaFormatterFunc getFormatterFunc(boolean withDefaults, - String binaryPath, String configPath) { + @Nullable String binaryPath, @Nullable String configPath) { if (withDefaults) { return IdeaFormatterFunc .allowingDefaultsWithCustomBinary(binaryPath, configPath); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index 98617fa787..5acd080d16 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -319,16 +319,16 @@ public IdeaConfig idea() { } public class IdeaConfig { - String binaryPath; - String configPath; - boolean withDefaults = false; + private String binaryPath; + private String configPath; + private boolean withDefaults = false; IdeaConfig() { addStep(createStep()); } private FormatterStep createStep() { - return IdeaStep.create(withDefaults, binaryPath); + return IdeaStep.create(withDefaults, binaryPath, configPath); } public IdeaConfig binaryPath(String binaryPath) { From c6c6ccefc0fa4c7dbc18c51badc8571d9484eaf0 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Wed, 24 Jan 2024 10:11:17 +0300 Subject: [PATCH 010/210] docs: fixed structure of CHANGES.md --- CHANGES.md | 3 +-- plugin-gradle/CHANGES.md | 4 ++-- plugin-maven/CHANGES.md | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2dc29c4809..d3bace3e90 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,13 +12,12 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * `FileSignature.Promised` and `JarState.Promised` to facilitate round-trip serialization for the Gradle configuration cache. ([#1945](https://github.com/diffplug/spotless/pull/1945)) +* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) ### Removed * **BREAKING** Remove `JarState.getMavenCoordinate(String prefix)`. ([#1945](https://github.com/diffplug/spotless/pull/1945)) ### Fixed * Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990)) -* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) - ## [2.45.0] - 2024-01-23 ### Added * Support for `gofmt` ([#2001](https://github.com/diffplug/spotless/pull/2001)) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 1544f9b705..bb03847254 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,11 +3,11 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Added +* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) ### Fixed * Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990)) -* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) - ## [6.25.0] - 2024-01-23 ### Added * Maven / Gradle - Support for formatting Java Docs for the Palantir formatter ([#2009](https://github.com/diffplug/spotless/pull/2009)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 57607c5637..17f50162b4 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,10 +3,11 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) ### Fixed * Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990)) -* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020)) ## [2.43.0] - 2024-01-23 ### Added From 91235270c3abfaef00927e2606c850d9c7eb9d54 Mon Sep 17 00:00:00 2001 From: Ilya Ilyinykh Date: Sat, 27 Jan 2024 14:44:13 +0300 Subject: [PATCH 011/210] Create State object This object is now resides in IdeaStep --- .../spotless/java/IdeaFormatterFunc.java | 112 ------------------ .../com/diffplug/spotless/java/IdeaStep.java | 100 ++++++++++++++-- 2 files changed, 91 insertions(+), 121 deletions(-) delete mode 100644 lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java deleted file mode 100644 index 779dc3b563..0000000000 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaFormatterFunc.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 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.spotless.java; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.List; -import java.util.Objects; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.annotation.Nullable; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.diffplug.spotless.ForeignExe; -import com.diffplug.spotless.FormatterFunc; -import com.diffplug.spotless.ProcessRunner; - -public final class IdeaFormatterFunc implements FormatterFunc.NeedsFile { - - private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class); - - private static final String DEFAULT_IDEA = "idea"; - - private String binaryPath; - @Nullable - private String configPath; - private boolean withDefaults; - - private IdeaFormatterFunc(boolean withDefaults, @Nullable String binaryPath, - @Nullable String configPath) { - this.withDefaults = withDefaults; - this.configPath = configPath; - this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); - resolveFullBinaryPathAndCheckVersion(); - } - - private void resolveFullBinaryPathAndCheckVersion() { - var exe = ForeignExe.nameAndVersion(this.binaryPath, "IntelliJ IDEA") - .versionRegex(Pattern.compile("(IntelliJ IDEA) .*")) - .fixCantFind("IDEA executable cannot be found on your machine, " - + "please install it and put idea binary to PATH; or report the problem") - .fixWrongVersion("Provided binary is not IDEA, " - + "please check it and fix the problem; or report the problem"); - try { - this.binaryPath = exe.confirmVersionAndGetAbsolutePath(); - } catch (IOException e) { - throw new IllegalArgumentException("binary cannot be found", e); - } catch (InterruptedException e) { - throw new IllegalArgumentException( - "binary cannot be found, process was interrupted", e); - } - } - - public static IdeaFormatterFunc allowingDefaultsWithCustomBinary( - @Nullable String binaryPath, @Nullable String configPath) { - return new IdeaFormatterFunc(true, binaryPath, configPath); - } - - public static IdeaFormatterFunc noDefaultsWithCustomBinary( - @Nullable String binaryPath, @Nullable String configPath) { - return new IdeaFormatterFunc(false, binaryPath, configPath); - } - - @Override - public String applyWithFile(String unix, File file) throws Exception { - List params = getParams(file); - - try (ProcessRunner runner = new ProcessRunner()) { - var result = runner.exec(params); - - LOGGER.debug("command finished with stdout: {}", - result.assertExitZero(StandardCharsets.UTF_8)); - - return Files.readString(file.toPath()); - } - } - - private List getParams(File file) { - var builder = Stream. builder(); - builder.add(binaryPath); - builder.add("format"); - if (withDefaults) { - builder.add("-allowDefaults"); - } - if (configPath != null) { - builder.add("-s"); - builder.add(configPath); - } - builder.add(file.toString()); - return builder.build().collect(Collectors.toList()); - } - -} diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java index 8839bbdba0..cfe8c5f349 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -15,12 +15,31 @@ */ package com.diffplug.spotless.java; +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.diffplug.spotless.ForeignExe; +import com.diffplug.spotless.FormatterFunc; import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.ProcessRunner; public final class IdeaStep { + private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class); + private IdeaStep() {} public static FormatterStep create() { @@ -38,18 +57,81 @@ public static FormatterStep create(boolean withDefaults, public static FormatterStep create(boolean withDefaults, @Nullable String binaryPath, @Nullable String configPath) { - IdeaFormatterFunc formatterFunc = getFormatterFunc(withDefaults, binaryPath, configPath); - // TODO: make it lazy - return FormatterStep.createNeverUpToDate("IDEA", formatterFunc); + return FormatterStep.createLazy("IDEA", + () -> createState(withDefaults, binaryPath, configPath), + state -> state); } - private static IdeaFormatterFunc getFormatterFunc(boolean withDefaults, + private static State createState(boolean withDefaults, @Nullable String binaryPath, @Nullable String configPath) { - if (withDefaults) { - return IdeaFormatterFunc - .allowingDefaultsWithCustomBinary(binaryPath, configPath); - } - return IdeaFormatterFunc.noDefaultsWithCustomBinary(binaryPath, configPath); + return new State(withDefaults, binaryPath, configPath); } + private static class State + implements FormatterFunc.NeedsFile, Serializable { + + private static final long serialVersionUID = -1825662355363926318L; + private static final String DEFAULT_IDEA = "idea"; + + private String binaryPath; + @Nullable + private String configPath; + private boolean withDefaults; + + private State(boolean withDefaults, @Nullable String binaryPath, + @Nullable String configPath) { + this.withDefaults = withDefaults; + this.configPath = configPath; + this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); + resolveFullBinaryPathAndCheckVersion(); + } + + private void resolveFullBinaryPathAndCheckVersion() { + var exe = ForeignExe + .nameAndVersion(this.binaryPath, "IntelliJ IDEA") + .versionRegex(Pattern.compile("(IntelliJ IDEA) .*")) + .fixCantFind( + "IDEA executable cannot be found on your machine, " + + "please install it and put idea binary to PATH; or report the problem") + .fixWrongVersion("Provided binary is not IDEA, " + + "please check it and fix the problem; or report the problem"); + try { + this.binaryPath = exe.confirmVersionAndGetAbsolutePath(); + } catch (IOException e) { + throw new IllegalArgumentException("binary cannot be found", e); + } catch (InterruptedException e) { + throw new IllegalArgumentException( + "binary cannot be found, process was interrupted", e); + } + } + + @Override + public String applyWithFile(String unix, File file) throws Exception { + List params = getParams(file); + + try (ProcessRunner runner = new ProcessRunner()) { + var result = runner.exec(params); + + LOGGER.debug("command finished with stdout: {}", + result.assertExitZero(StandardCharsets.UTF_8)); + + return Files.readString(file.toPath()); + } + } + + private List getParams(File file) { + var builder = Stream. builder(); + builder.add(binaryPath); + builder.add("format"); + if (withDefaults) { + builder.add("-allowDefaults"); + } + if (configPath != null) { + builder.add("-s"); + builder.add(configPath); + } + builder.add(file.toString()); + return builder.build().collect(Collectors.toList()); + } + } } From a0bde464fbbeb376332b6048452ec401f03f87c9 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 12 Feb 2024 16:04:52 -0800 Subject: [PATCH 012/210] spotlessApply --- .../gradle/spotless/JavaIdeaTest.java | 1 + .../diffplug/spotless/maven/java/Idea.java | 1 + .../diffplug/spotless/maven/java/Java.java | 2 +- .../spotless/maven/java/IdeaTest.java | 2 +- .../diffplug/spotless/ResourceHarness.java | 2 +- .../diffplug/spotless/java/IdeaStepTest.java | 32 +++++++++++++------ 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java index 2e51f26bb0..b154c2d851 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java @@ -18,6 +18,7 @@ import java.io.IOException; import org.junit.jupiter.api.Test; + import com.diffplug.spotless.tag.IdeaTest; @IdeaTest diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java index 83decc6867..8981a9dc9b 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java @@ -16,6 +16,7 @@ package com.diffplug.spotless.maven.java; import org.apache.maven.plugins.annotations.Parameter; + import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.java.IdeaStep; import com.diffplug.spotless.maven.FormatterStepConfig; diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java index 751da56ae9..20a2db96f7 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 DiffPlug + * Copyright 2016-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java index 575f88c29c..c11b2a64d1 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java b/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java index fcdfa2f97d..b704d5c981 100644 --- a/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java +++ b/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 DiffPlug + * Copyright 2016-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java index 38606c3657..98de28627a 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java @@ -1,9 +1,26 @@ +/* + * Copyright 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.spotless.java; import java.io.File; import java.nio.charset.StandardCharsets; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; + import com.diffplug.common.io.Files; import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.ResourceHarness; @@ -24,8 +41,7 @@ void name() throws Exception { @Test void notFormattings() throws Exception { File cleanFile = newFile("clean.java"); - String cleanJava = - ResourceHarness.getTestResource("java/idea/full.clean.java"); + String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java"); Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8); FormatterStep step = IdeaStep.create(true, "idea"); @@ -38,8 +54,7 @@ void notFormattings() throws Exception { @Test void formattings() throws Exception { File dirtyFile = newFile("dirty.java"); - String dirtyJava = - ResourceHarness.getTestResource("java/idea/full.dirty.java"); + String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java"); Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8); FormatterStep step = IdeaStep.create(true, "idea"); @@ -52,8 +67,7 @@ void formattings() throws Exception { @Test void formattingsWorkWithDefaultParameters() throws Exception { File dirtyFile = newFile("dirty.java"); - String dirtyJava = - ResourceHarness.getTestResource("java/idea/full.dirty.java"); + String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java"); Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8); FormatterStep step = IdeaStep.create(); @@ -66,8 +80,7 @@ void formattingsWorkWithDefaultParameters() throws Exception { @Test void formattingsWithOutDefaultDoesNothing() throws Exception { File dirtyFile = newFile("dirty.java"); - String dirtyJava = - ResourceHarness.getTestResource("java/idea/full.dirty.java"); + String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java"); Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8); FormatterStep step = IdeaStep.create(false, "idea"); @@ -80,8 +93,7 @@ void formattingsWithOutDefaultDoesNothing() throws Exception { @Test void configureFile() throws Exception { File cleanFile = newFile("clean.java"); - String cleanJava = - ResourceHarness.getTestResource("java/idea/full.clean.java"); + String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java"); Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8); FormatterStep step = IdeaStep.create(true, "idea"); From 6efa10afe558050e6fb14f741a55020895a57e49 Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Wed, 11 Dec 2024 08:58:33 +0100 Subject: [PATCH 013/210] feat: supply eclipse formatter settings as XML content --- CHANGES.md | 1 + .../spotless/extra/EquoBasedStepBuilder.java | 19 ++++-- .../spotless/FormatterProperties.java | 65 +++++++++++++++---- plugin-gradle/README.md | 18 ++++- .../gradle/spotless/BaseGroovyExtension.java | 7 ++ .../gradle/spotless/CppExtension.java | 7 ++ .../gradle/spotless/JavaExtension.java | 7 ++ .../gradle/spotless/JavaEclipseTest.java | 25 ++++++- .../spotless/FormatterPropertiesTest.java | 57 +++++++++++----- 9 files changed, 168 insertions(+), 38 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 22b2b73e27..9465f8afe4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changed +* TODO ([#](https://github.com/diffplug/spotless/pull/X)) * Allow setting Eclipse config from a string, not only from files ([#2337](https://github.com/diffplug/spotless/pull/2337)) * Bump default `ktlint` version to latest `1.3.0` -> `1.4.0`. ([#2314](https://github.com/diffplug/spotless/pull/2314)) * Add _Sort Members_ feature based on [Eclipse JDT](plugin-gradle/README.md#eclipse-jdt) implementation. ([#2312](https://github.com/diffplug/spotless/pull/2312)) diff --git a/lib-extra/src/main/java/com/diffplug/spotless/extra/EquoBasedStepBuilder.java b/lib-extra/src/main/java/com/diffplug/spotless/extra/EquoBasedStepBuilder.java index df3824e9ca..267d6cc496 100644 --- a/lib-extra/src/main/java/com/diffplug/spotless/extra/EquoBasedStepBuilder.java +++ b/lib-extra/src/main/java/com/diffplug/spotless/extra/EquoBasedStepBuilder.java @@ -56,6 +56,7 @@ public abstract class EquoBasedStepBuilder { private String formatterVersion; private Iterable settingsFiles = new ArrayList<>(); private List settingProperties = new ArrayList<>(); + private List settingXml = new ArrayList<>(); private Map p2Mirrors = Map.of(); private File cacheDirectory; @@ -86,6 +87,10 @@ public void setPropertyPreferences(List propertyPreferences) { this.settingProperties = propertyPreferences; } + public void setXmlPreferences(List settingXml) { + this.settingXml = settingXml; + } + public void setP2Mirrors(Map p2Mirrors) { this.p2Mirrors = Map.copyOf(p2Mirrors); } @@ -119,7 +124,7 @@ protected void addPlatformRepo(P2Model model, String version) { /** Returns the FormatterStep (whose state will be calculated lazily). */ public FormatterStep build() { - var roundtrippableState = new EquoStep(formatterVersion, settingProperties, FileSignature.promise(settingsFiles), JarState.promise(() -> { + var roundtrippableState = new EquoStep(formatterVersion, settingProperties, settingXml, FileSignature.promise(settingsFiles), JarState.promise(() -> { P2QueryResult query; try { if (null != cacheDirectory) { @@ -174,23 +179,26 @@ static class EquoStep implements Serializable { private final JarState.Promised jarPromise; private final ImmutableMap stepProperties; private List settingProperties; + private List settingXml; EquoStep( String semanticVersion, List settingProperties, + List settingXml, FileSignature.Promised settingsPromise, JarState.Promised jarPromise, ImmutableMap stepProperties) { this.semanticVersion = semanticVersion; this.settingProperties = Optional.ofNullable(settingProperties).orElse(new ArrayList<>()); + this.settingXml = Optional.ofNullable(settingXml).orElse(new ArrayList<>()); this.settingsPromise = settingsPromise; this.jarPromise = jarPromise; this.stepProperties = stepProperties; } private State state() { - return new State(semanticVersion, jarPromise.get(), settingProperties, settingsPromise.get(), stepProperties); + return new State(semanticVersion, jarPromise.get(), settingProperties, settingXml, settingsPromise.get(), stepProperties); } } @@ -205,11 +213,13 @@ public static class State implements Serializable { final FileSignature settingsFiles; final ImmutableMap stepProperties; private List settingProperties; + private List settingXml; - public State(String semanticVersion, JarState jarState, List settingProperties, FileSignature settingsFiles, ImmutableMap stepProperties) { + public State(String semanticVersion, JarState jarState, List settingProperties, List settingXml, FileSignature settingsFiles, ImmutableMap stepProperties) { this.semanticVersion = semanticVersion; this.jarState = jarState; this.settingProperties = Optional.ofNullable(settingProperties).orElse(new ArrayList<>()); + this.settingXml = Optional.ofNullable(settingXml).orElse(new ArrayList<>()); this.settingsFiles = settingsFiles; this.stepProperties = stepProperties; } @@ -225,7 +235,8 @@ public String getSemanticVersion() { public Properties getPreferences() { FormatterProperties fromFiles = FormatterProperties.from(settingsFiles.files()); FormatterProperties fromPropertiesContent = FormatterProperties.fromPropertiesContent(settingProperties); - return FormatterProperties.merge(fromFiles.getProperties(), fromPropertiesContent.getProperties()).getProperties(); + FormatterProperties fromXmlContent = FormatterProperties.fromXmlContent(settingXml); + return FormatterProperties.merge(fromFiles.getProperties(), fromPropertiesContent.getProperties(), fromXmlContent.getProperties()).getProperties(); } public ImmutableMap getStepProperties() { diff --git a/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java b/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java index 5ea32f8f99..455318e38f 100644 --- a/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java +++ b/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java @@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -28,6 +29,7 @@ import java.util.List; import java.util.Objects; import java.util.Properties; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -90,6 +92,25 @@ public static FormatterProperties fromPropertiesContent(Iterable content return properties; } + public static FormatterProperties fromXmlContent(final Iterable content) throws IllegalArgumentException { + final List nonNullElements = toNullHostileList(content); + final FormatterProperties properties = new FormatterProperties(); + nonNullElements.forEach(contentElement -> { + try { + final Properties newSettings = FileParser.XML.executeXmlContent(contentElement); + properties.properties.putAll(newSettings); + } catch (IOException | IllegalArgumentException exception) { + String message = String.format("Failed to add preferences from XML:%n%s%n", contentElement); + final String detailedMessage = exception.getMessage(); + if (null != detailedMessage) { + message += String.format(" %s", detailedMessage); + } + throw new IllegalArgumentException(message, exception); + } + }); + return properties; + } + public static FormatterProperties merge(Properties... properties) { FormatterProperties merged = new FormatterProperties(); List.of(properties).stream().forEach((source) -> merged.properties.putAll(source)); @@ -139,20 +160,40 @@ protected Properties execute(final File file) throws IOException, IllegalArgumen } return properties; } + + @Override + protected Properties executeXmlContent(String content) throws IOException, IllegalArgumentException { + throw new RuntimeException("Not implemented"); + } }, XML("xml") { @Override protected Properties execute(final File file) throws IOException, IllegalArgumentException { - Node rootNode = getRootNode(file); + return executeWithSupplier(() -> { + try { + return new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new RuntimeException("File not found: " + file, e); + } + }); + } + + @Override + protected Properties executeXmlContent(String content) throws IOException, IllegalArgumentException { + return executeWithSupplier(() -> new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); + } + + private Properties executeWithSupplier(Supplier isSupplier) throws IOException, IllegalArgumentException { + Node rootNode = getRootNode(isSupplier.get()); String nodeName = rootNode.getNodeName(); if (null == nodeName) { throw new IllegalArgumentException("XML document does not contain a root node."); } - return XmlParser.parse(file, rootNode); + return XmlParser.parse(isSupplier.get(), rootNode); } - private Node getRootNode(final File file) throws IOException, IllegalArgumentException { + private Node getRootNode(final InputStream is) throws IOException, IllegalArgumentException { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); /* @@ -166,7 +207,7 @@ private Node getRootNode(final File file) throws IOException, IllegalArgumentExc */ dbf.setFeature(LOAD_EXTERNAL_DTD_PROP, false); DocumentBuilder db = dbf.newDocumentBuilder(); - return db.parse(file).getDocumentElement(); + return db.parse(is).getDocumentElement(); } catch (SAXException | ParserConfigurationException e) { throw new IllegalArgumentException("File has no valid XML syntax.", e); } @@ -186,6 +227,8 @@ private Node getRootNode(final File file) throws IOException, IllegalArgumentExc protected abstract Properties execute(File file) throws IOException, IllegalArgumentException; + protected abstract Properties executeXmlContent(String content) throws IOException, IllegalArgumentException; + public static Properties parse(final File file) throws IOException, IllegalArgumentException { String fileNameExtension = getFileNameExtension(file); for (FileParser parser : FileParser.values()) { @@ -211,19 +254,17 @@ private static String getFileNameExtension(File file) { private enum XmlParser { PROPERTIES("properties") { @Override - protected Properties execute(final File xmlFile, final Node rootNode) + protected Properties execute(final InputStream xmlFile, final Node rootNode) throws IOException, IllegalArgumentException { final Properties properties = new Properties(); - try (InputStream xmlInput = new FileInputStream(xmlFile)) { - properties.loadFromXML(xmlInput); - } + properties.loadFromXML(xmlFile); return properties; } }, PROFILES("profiles") { @Override - protected Properties execute(File file, Node rootNode) throws IOException, IllegalArgumentException { + protected Properties execute(InputStream file, Node rootNode) throws IOException, IllegalArgumentException { final Properties properties = new Properties(); Node firstProfile = getSingleProfile(rootNode); for (Object settingObj : getChildren(firstProfile, "setting")) { @@ -285,14 +326,14 @@ public String toString() { return this.rootNodeName; } - protected abstract Properties execute(File file, Node rootNode) throws IOException, IllegalArgumentException; + protected abstract Properties execute(InputStream is, Node rootNode) throws IOException, IllegalArgumentException; - public static Properties parse(final File file, final Node rootNode) + public static Properties parse(final InputStream is, final Node rootNode) throws IOException, IllegalArgumentException { String rootNodeName = rootNode.getNodeName(); for (XmlParser parser : XmlParser.values()) { if (parser.rootNodeName.equals(rootNodeName)) { - return parser.execute(file, rootNode); + return parser.execute(is, rootNode); } } String msg = String.format("The XML root node '%1$s' is not part of the supported root nodes [%2$s].", diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 58db554e66..6ed02b0f2b 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -262,10 +262,14 @@ spotless { eclipse() // optional: you can specify a specific version and/or config file eclipse('4.26').configFile('eclipse-prefs.xml') - // Or supply the configuration as a string + // Or supply the configuration properties as a string eclipse('4.26').configProperties(""" ... """) + // Or supply the configuration XML as a string + eclipse('4.26').configXml(""" + ... + """) // if the access to the p2 repositories is restricted, mirrors can be // specified using a URI prefix map as follows: eclipse().withP2Mirrors(['https://download.eclipse.org/eclipse/updates/4.29/':'https://some.internal.mirror/4-29-updates-p2/']) @@ -422,10 +426,14 @@ spotless { greclipse() // optional: you can specify a specific version or config file(s), version matches the Eclipse Platform greclipse('4.26').configFile('spotless.eclipseformat.xml', 'org.codehaus.groovy.eclipse.ui.prefs') - // Or supply the configuration as a string + // Or supply the configuration properties as a string greclipse('4.26').configProperties(""" ... """) + // Or supply the configuration XML as a string + greclipse('4.26').configXml(""" + ... + """) ``` Groovy-Eclipse formatting errors/warnings lead per default to a build failure. This behavior can be changed by adding the property/key value `ignoreFormatterProblems=true` to a configuration file. In this scenario, files causing problems, will not be modified by this formatter step. @@ -580,10 +588,14 @@ spotles { cpp { // version and configFile are both optional eclipseCdt('4.13.0').configFile('eclipse-cdt.xml') - // Or supply the configuration as a string + // Or supply the configuration properties as a string eclipseCdt('4.13.0').configProperties(""" ... """) + // Or supply the configuration XML as a string + eclipseCdt('4.13.0').configXml(""" + ... + """) } } ``` diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java index 83d678c46c..37712a470b 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java @@ -80,6 +80,13 @@ public GrEclipseConfig configProperties(String... configs) { return this; } + public GrEclipseConfig configXml(String... configs) { + requireElementsNonNull(configs); + builder.setXmlPreferences(List.of(configs)); + extension.replaceStep(builder.build()); + return this; + } + public GrEclipseConfig withP2Mirrors(Map mirrors) { builder.setP2Mirrors(mirrors); extension.replaceStep(builder.build()); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java index f2d6ee91bb..db7d9bee9a 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java @@ -69,6 +69,13 @@ public EclipseConfig configProperties(String... configs) { return this; } + public EclipseConfig configXml(String... configs) { + requireElementsNonNull(configs); + builder.setXmlPreferences(List.of(configs)); + replaceStep(builder.build()); + return this; + } + public EclipseConfig withP2Mirrors(Map mirrors) { builder.setP2Mirrors(mirrors); replaceStep(builder.build()); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index b7d3c84304..343092b4ad 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -312,6 +312,13 @@ public EclipseConfig configProperties(String... configs) { return this; } + public EclipseConfig configXml(String... configs) { + requireElementsNonNull(configs); + builder.setXmlPreferences(List.of(configs)); + replaceStep(builder.build()); + return this; + } + public EclipseConfig sortMembersDoNotSortFields(boolean doNotSortFields) { builder.sortMembersDoNotSortFields(doNotSortFields); replaceStep(builder.build()); diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java index c102b7abe1..1ef433acd6 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java @@ -21,7 +21,7 @@ class JavaEclipseTest extends GradleIntegrationHarness { @Test - void settingsWithContentWithoutFile() throws IOException { + void settingsWithProprtiesContent() throws IOException { setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -37,4 +37,27 @@ void settingsWithContentWithoutFile() throws IOException { gradleRunner().withArguments("spotlessApply").build(); } + + @Test + void settingsWithXmlContent() throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + " id 'java'", + "}", + "repositories { mavenCentral() }", + "", + "spotless {", + " java { eclipse().configProperties(\"\"\"", + "", + "", + " ", + " ", + " ", + "", + "\"\"\") }", + "}"); + + gradleRunner().withArguments("spotlessApply").build(); + } } diff --git a/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java b/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java index 8333fcc41d..58ae1c913e 100644 --- a/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java @@ -16,6 +16,7 @@ package com.diffplug.spotless; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.File; import java.io.IOException; @@ -52,8 +53,12 @@ private List validPropertiesResources() { return List.of(VALID_SETTINGS_RESOURCES).stream().filter(it -> !it.endsWith(".xml")).collect(Collectors.toList()); } - private List invalidPropertiesResources() { - return List.of(INVALID_SETTINGS_RESOURCES).stream().filter(it -> !it.endsWith(".xml")).collect(Collectors.toList()); + private List validXmlResources() { + return List.of(VALID_SETTINGS_RESOURCES).stream().filter(it -> it.endsWith(".xml")).collect(Collectors.toList()); + } + + private List invalidXmlResources() { + return List.of(INVALID_SETTINGS_RESOURCES).stream().filter(it -> it.endsWith(".xml")).collect(Collectors.toList()); } private static final String[] VALID_VALUES = { @@ -86,6 +91,18 @@ void differentPropertyFileTypes_content_properties() throws IOException { } } + @Test + void differentPropertyFileTypes_content_xml() throws IOException { + for (String settingsResource : validXmlResources()) { + File settingsFile = createTestFile(settingsResource); + String content = Files.readString(settingsFile.toPath()); + FormatterProperties preferences = FormatterProperties.fromXmlContent(List.of(content)); + assertFor(preferences) + .containsSpecificValuesOf(settingsFile) + .containsCommonValueOf(settingsFile); + } + } + @Test void multiplePropertyFiles() throws IOException { LinkedList settingsFiles = new LinkedList<>(); @@ -116,6 +133,22 @@ void multiplePropertyFiles_content_properties() throws IOException { .containsCommonValueOf(settingsFiles.getLast()); } + @Test + void multiplePropertyFiles_content_xml() throws IOException { + LinkedList settingsFiles = new LinkedList<>(); + LinkedList content = new LinkedList<>(); + for (String settingsResource : validXmlResources()) { + File settingsFile = createTestFile(settingsResource); + content.add(Files.readString(settingsFile.toPath())); + settingsFiles.add(settingsFile); + } + FormatterProperties preferences = FormatterProperties.fromXmlContent(content); + /* Settings are loaded / overridden in the sequence they are configured. */ + assertFor(preferences) + .containsSpecificValuesOf(settingsFiles) + .containsCommonValueOf(settingsFiles.getLast()); + } + @Test void invalidPropertyFiles() throws IOException { for (String settingsResource : INVALID_SETTINGS_RESOURCES) { @@ -136,22 +169,10 @@ void invalidPropertyFiles() throws IOException { } @Test - void invalidPropertyFiles_content_properties() throws IOException { - for (String settingsResource : invalidPropertiesResources()) { - File settingsFile = createTestFile(settingsResource); - String content = Files.readString(settingsFile.toPath()); - boolean exceptionCaught = false; - try { - FormatterProperties.fromPropertiesContent(List.of(content)); - } catch (IllegalArgumentException ex) { - exceptionCaught = true; - assertThat(ex.getMessage()) - .as("IllegalArgumentException does not contain absolute path of file '%s'", settingsFile.getName()) - .contains(settingsFile.getAbsolutePath()); - } - assertThat(exceptionCaught) - .as("No IllegalArgumentException thrown when parsing '%s'", settingsFile.getName()) - .isTrue(); + void invalidPropertyFiles_content_xml() throws IOException { + for (String settingsResource : invalidXmlResources()) { + IllegalArgumentException actual = assertThrows(IllegalArgumentException.class, () -> FormatterProperties.fromXmlContent(List.of(ResourceHarness.getTestResource(settingsResource)))); + assertThat(actual.getMessage()).startsWith("Failed to add preferences from XML:"); } } From eb7bf1a5d26b5f190946c603bdffb55ab02f9672 Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Wed, 11 Dec 2024 10:54:12 +0100 Subject: [PATCH 014/210] chore: changes --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9465f8afe4..2941d60e9d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changed -* TODO ([#](https://github.com/diffplug/spotless/pull/X)) +* Allow setting Eclipse XML config from a string, not only from files ([#2361](https://github.com/diffplug/spotless/pull/2361)) * Allow setting Eclipse config from a string, not only from files ([#2337](https://github.com/diffplug/spotless/pull/2337)) * Bump default `ktlint` version to latest `1.3.0` -> `1.4.0`. ([#2314](https://github.com/diffplug/spotless/pull/2314)) * Add _Sort Members_ feature based on [Eclipse JDT](plugin-gradle/README.md#eclipse-jdt) implementation. ([#2312](https://github.com/diffplug/spotless/pull/2312)) From 45420dcfb0ff07be6e598c5ecf48a7fbb325a833 Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Wed, 11 Dec 2024 11:01:52 +0100 Subject: [PATCH 015/210] chore: testing with configXml not properties --- .../test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java index 1ef433acd6..862f82010f 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java @@ -48,7 +48,7 @@ void settingsWithXmlContent() throws IOException { "repositories { mavenCentral() }", "", "spotless {", - " java { eclipse().configProperties(\"\"\"", + " java { eclipse().configXml(\"\"\"", "", "", " ", From 10258213c8201363b3a1b3cffd85935f98d2110f Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 16 Dec 2024 20:58:44 +0100 Subject: [PATCH 016/210] feat: add support for absolute binary path --- .../com/diffplug/spotless/java/IdeaStep.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java index cfe8c5f349..0aa3612d65 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.slf4j.Logger; @@ -56,15 +57,15 @@ public static FormatterStep create(boolean withDefaults, } public static FormatterStep create(boolean withDefaults, - @Nullable String binaryPath, @Nullable String configPath) { + @Nullable String binaryPath, @Nullable String codeStyleSettingsPath) { return FormatterStep.createLazy("IDEA", - () -> createState(withDefaults, binaryPath, configPath), + () -> createState(withDefaults, binaryPath, codeStyleSettingsPath), state -> state); } private static State createState(boolean withDefaults, - @Nullable String binaryPath, @Nullable String configPath) { - return new State(withDefaults, binaryPath, configPath); + @Nullable String binaryPath, @Nullable String codeStyleSettingsPath) { + return new State(withDefaults, binaryPath, codeStyleSettingsPath); } private static class State @@ -75,13 +76,13 @@ private static class State private String binaryPath; @Nullable - private String configPath; + private String codeStyleSettingsPath; private boolean withDefaults; private State(boolean withDefaults, @Nullable String binaryPath, - @Nullable String configPath) { + @Nullable String codeStyleSettingsPath) { this.withDefaults = withDefaults; - this.configPath = configPath; + this.codeStyleSettingsPath = codeStyleSettingsPath; this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); resolveFullBinaryPathAndCheckVersion(); } @@ -89,10 +90,11 @@ private State(boolean withDefaults, @Nullable String binaryPath, private void resolveFullBinaryPathAndCheckVersion() { var exe = ForeignExe .nameAndVersion(this.binaryPath, "IntelliJ IDEA") + .pathToExe(pathToExe()) .versionRegex(Pattern.compile("(IntelliJ IDEA) .*")) .fixCantFind( "IDEA executable cannot be found on your machine, " - + "please install it and put idea binary to PATH; or report the problem") + + "please install it and put idea binary to PATH, provide a valid path to the executable or report the problem") .fixWrongVersion("Provided binary is not IDEA, " + "please check it and fix the problem; or report the problem"); try { @@ -105,6 +107,17 @@ private void resolveFullBinaryPathAndCheckVersion() { } } + @CheckForNull + private String pathToExe() { + if (binaryPath == null) { + throw new IllegalStateException("binaryPath is not set"); + } + if (new File(binaryPath).exists()) { + return binaryPath; + } + return null; // search in PATH + } + @Override public String applyWithFile(String unix, File file) throws Exception { List params = getParams(file); @@ -126,9 +139,9 @@ private List getParams(File file) { if (withDefaults) { builder.add("-allowDefaults"); } - if (configPath != null) { + if (codeStyleSettingsPath != null) { builder.add("-s"); - builder.add(configPath); + builder.add(codeStyleSettingsPath); } builder.add(file.toString()); return builder.build().collect(Collectors.toList()); From dc3b568c893d9cb774d2f495a808c2f6a28780f5 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 16 Dec 2024 21:07:01 +0100 Subject: [PATCH 017/210] fix: don't interact with the file directly --- .../com/diffplug/spotless/java/IdeaStep.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java index 0aa3612d65..5c8a0597f1 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -36,6 +36,7 @@ import com.diffplug.spotless.FormatterFunc; import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.ProcessRunner; +import com.diffplug.spotless.ThrowingEx; public final class IdeaStep { @@ -120,15 +121,21 @@ private String pathToExe() { @Override public String applyWithFile(String unix, File file) throws Exception { - List params = getParams(file); - - try (ProcessRunner runner = new ProcessRunner()) { - var result = runner.exec(params); - - LOGGER.debug("command finished with stdout: {}", - result.assertExitZero(StandardCharsets.UTF_8)); - - return Files.readString(file.toPath()); + // since we cannot directly work with the file, we need to write the unix string to a temporary file + File tempFile = File.createTempFile("spotless", file.getName()); + try { + Files.write(tempFile.toPath(), unix.getBytes(StandardCharsets.UTF_8)); + List params = getParams(tempFile); + + try (ProcessRunner runner = new ProcessRunner()) { + var result = runner.exec(params); + LOGGER.debug("command finished with stdout: {}", + result.assertExitZero(StandardCharsets.UTF_8)); + + return Files.readString(tempFile.toPath(), StandardCharsets.UTF_8); + } + } finally { + Files.delete(tempFile.toPath()); } } @@ -143,7 +150,7 @@ private List getParams(File file) { builder.add("-s"); builder.add(codeStyleSettingsPath); } - builder.add(file.toString()); + builder.add(ThrowingEx.get(file::getCanonicalPath)); return builder.build().collect(Collectors.toList()); } } From a9320dd26fa7930988c287b54badab76303a0ad4 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 16 Dec 2024 21:11:37 +0100 Subject: [PATCH 018/210] doc: add link to jetbrains documentation --- lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java index 5c8a0597f1..d069e721fb 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java @@ -140,6 +140,7 @@ public String applyWithFile(String unix, File file) throws Exception { } private List getParams(File file) { + /* https://www.jetbrains.com/help/idea/command-line-formatter.html */ var builder = Stream. builder(); builder.add(binaryPath); builder.add("format"); From 23d98d203736b344f1853f652a6eb2f0c6a7f659 Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 6 Jan 2025 22:18:20 +0000 Subject: [PATCH 019/210] Published gradle/7.0.0 --- plugin-gradle/CHANGES.md | 2 ++ plugin-gradle/README.md | 62 ++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 3c6a994e83..64b6474ad1 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] + +## [7.0.0] - 2025-01-06 ## Headline changes - The long `7.0.0.BETAX` period is finally over, Spotless for Gradle 7.0 is here! - Full, no asterisk support for configuration cache (end of [#987](https://github.com/diffplug/spotless/issues/987)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 58db554e66..c152dc4dc2 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -14,9 +14,9 @@ output = [ ].join('\n'); --> [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.0.0.BETA4-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.0.0-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -128,10 +128,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -173,7 +173,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -372,8 +372,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -432,8 +432,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle spotless { // if you are using build.gradle.kts, instead of 'spotless {' use: @@ -522,7 +522,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -554,7 +554,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -590,7 +590,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -626,7 +626,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -658,7 +658,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -679,7 +679,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -698,7 +698,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -723,7 +723,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -761,7 +761,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -810,7 +810,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -904,7 +904,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -967,7 +967,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1087,7 +1087,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1119,7 +1119,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1155,7 +1155,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1184,7 +1184,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1585,7 +1585,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1671,9 +1671,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1706,11 +1706,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0.BETA4/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From da87a221a5a7950ce711d157accf368702a88152 Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 6 Jan 2025 22:21:06 +0000 Subject: [PATCH 020/210] Published maven/2.44.0 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 573080a102..079881e0c4 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.44.0] - 2025-01-06 ## Headline changes - The long `2.44.0.BETAX` period is finally over (sorry, there was [a problem in Gradle land](https://github.com/diffplug/spotless/issues/987)). - Spotless now supports [linting](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#lints) in addition to formatting. diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 3f27aa1085..914c85b266 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.44.0.BETA4-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.0.BETA4/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.44.0-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.0/index.html) [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.0.0-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.0.1-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -128,10 +128,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -173,7 +173,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -372,8 +372,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -432,8 +432,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle spotless { // if you are using build.gradle.kts, instead of 'spotless {' use: @@ -522,7 +522,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -554,7 +554,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -590,7 +590,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -626,7 +626,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -658,7 +658,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -679,7 +679,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -698,7 +698,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -723,7 +723,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -761,7 +761,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -810,7 +810,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -904,7 +904,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -967,7 +967,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1087,7 +1087,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1119,7 +1119,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1155,7 +1155,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1184,7 +1184,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1585,7 +1585,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1671,9 +1671,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1706,11 +1706,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.0/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From c442e3a507400bd9ae271e5d0df56ecd11d711e3 Mon Sep 17 00:00:00 2001 From: runner Date: Tue, 7 Jan 2025 16:33:06 +0000 Subject: [PATCH 026/210] Published maven/2.44.1 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 4ce9128ebd..8a3409e6c7 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.44.1] - 2025-01-07 ### Fixed * Deployment was missing part of the CDT formatter, now fixed. ([#2384](https://github.com/diffplug/spotless/issues/2384)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 914c85b266..d8b22465f8 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.44.0-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.0/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.44.1-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.1/index.html) [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.0.1-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.0.2-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -128,10 +128,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -173,7 +173,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -372,8 +372,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -432,8 +432,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle spotless { // if you are using build.gradle.kts, instead of 'spotless {' use: @@ -522,7 +522,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -554,7 +554,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -590,7 +590,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -626,7 +626,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -658,7 +658,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -679,7 +679,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -698,7 +698,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -723,7 +723,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -761,7 +761,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -810,7 +810,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -904,7 +904,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -967,7 +967,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1087,7 +1087,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1119,7 +1119,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1155,7 +1155,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1184,7 +1184,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1585,7 +1585,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1671,9 +1671,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1706,11 +1706,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.1/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From 6d03aed509e72e167d04978a72a66ab4e9aa248b Mon Sep 17 00:00:00 2001 From: runner Date: Tue, 14 Jan 2025 21:17:59 +0000 Subject: [PATCH 040/210] Published maven/2.44.2 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index c4c6d57eb9..1d63ed362e 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.44.2] - 2025-01-14 * Eclipse-based tasks can now handle parallel configuration ([#2389](https://github.com/diffplug/spotless/issues/2389)) ## [2.44.1] - 2025-01-07 diff --git a/plugin-maven/README.md b/plugin-maven/README.md index d8b22465f8..4c81cc289e 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.44.1-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.1/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.44.2-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.2/index.html) + /path/to/buf + + +``` + ## Python [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/python/Python.java). [available steps](https://github.com/diffplug/spotless/tree/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/python/Black.java). @@ -1218,17 +1230,17 @@ RDF parsing is done via [Apache Jena](https://jena.apache.org/) in the version t [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/protobuf/Protobuf.java). [available steps](https://github.com/diffplug/spotless/tree/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/protobuf). ```xml - - proto/*.proto - + + proto/*.proto + - - target/**/ - + + target/**/ + - + ``` From d6d42c13804a625b6c17aa7051bccbbfb0c8d786 Mon Sep 17 00:00:00 2001 From: zashroof Date: Wed, 22 Jan 2025 16:36:42 -0500 Subject: [PATCH 045/210] Update homepage README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a40b9edb0d..5ed1de0187 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ lib('yaml.JacksonYamlStep') +'{{yes}} | {{yes}} | [`generic.TrimTrailingWhitespaceStep`](lib/src/main/java/com/diffplug/spotless/generic/TrimTrailingWhitespaceStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`antlr4.Antlr4FormatterStep`](lib/src/main/java/com/diffplug/spotless/antlr4/Antlr4FormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`biome.BiomeStep`](lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | -| [`cpp.ClangFormatStep`](lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | +| [`cpp.ClangFormatStep`](lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`cpp.EclipseFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/cpp/EclipseFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: | | [`go.GofmtFormatStep`](lib/src/main/java/com/diffplug/spotless/go/GofmtFormatStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`gherkin.GherkinUtilsStep`](lib/src/main/java/com/diffplug/spotless/gherkin/GherkinUtilsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | @@ -156,7 +156,7 @@ lib('yaml.JacksonYamlStep') +'{{yes}} | {{yes}} | [`npm.PrettierFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`npm.TsFmtFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`pom.SortPomStep`](lib/src/main/java/com/diffplug/spotless/pom/SortPomStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | -| [`protobuf.BufStep`](lib/src/main/java/com/diffplug/spotless/protobuf/BufStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | +| [`protobuf.BufStep`](lib/src/main/java/com/diffplug/spotless/protobuf/BufStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`python.BlackStep`](lib/src/main/java/com/diffplug/spotless/python/BlackStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`rdf.RdfFormatterStep`](lib/src/main/java/com/diffplug/spotless/rdf/RdfFormatterStep.java) | :white_large_square: | :+1: | :white_large_square: | :white_large_square: | | [`scala.ScalaFmtStep`](lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java) | :+1: | :+1: | :+1: | :white_large_square: | From 2c7656075e75f887ee65009b52a643581f6778ff Mon Sep 17 00:00:00 2001 From: zashroof Date: Wed, 22 Jan 2025 16:48:23 -0500 Subject: [PATCH 046/210] Fix README style --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5ed1de0187..a40b9edb0d 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ lib('yaml.JacksonYamlStep') +'{{yes}} | {{yes}} | [`generic.TrimTrailingWhitespaceStep`](lib/src/main/java/com/diffplug/spotless/generic/TrimTrailingWhitespaceStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`antlr4.Antlr4FormatterStep`](lib/src/main/java/com/diffplug/spotless/antlr4/Antlr4FormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`biome.BiomeStep`](lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | -| [`cpp.ClangFormatStep`](lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | +| [`cpp.ClangFormatStep`](lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`cpp.EclipseFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/cpp/EclipseFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: | | [`go.GofmtFormatStep`](lib/src/main/java/com/diffplug/spotless/go/GofmtFormatStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`gherkin.GherkinUtilsStep`](lib/src/main/java/com/diffplug/spotless/gherkin/GherkinUtilsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | @@ -156,7 +156,7 @@ lib('yaml.JacksonYamlStep') +'{{yes}} | {{yes}} | [`npm.PrettierFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`npm.TsFmtFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`pom.SortPomStep`](lib/src/main/java/com/diffplug/spotless/pom/SortPomStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | -| [`protobuf.BufStep`](lib/src/main/java/com/diffplug/spotless/protobuf/BufStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | +| [`protobuf.BufStep`](lib/src/main/java/com/diffplug/spotless/protobuf/BufStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`python.BlackStep`](lib/src/main/java/com/diffplug/spotless/python/BlackStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`rdf.RdfFormatterStep`](lib/src/main/java/com/diffplug/spotless/rdf/RdfFormatterStep.java) | :white_large_square: | :+1: | :white_large_square: | :white_large_square: | | [`scala.ScalaFmtStep`](lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java) | :+1: | :+1: | :+1: | :white_large_square: | From 5a8069373a89d4e1cfe4f15c21171938875d0a22 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 09:42:18 +0800 Subject: [PATCH 047/210] chore(deps): update plugin com.gradle.develocity to v3.19.1 (#2407) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index ada3768759..16a7ef904f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -20,7 +20,7 @@ plugins { // https://github.com/davidburstrom/version-compatibility-gradle-plugin/tags id 'io.github.davidburstrom.version-compatibility' version '0.5.0' apply false // https://plugins.gradle.org/plugin/com.gradle.develocity - id 'com.gradle.develocity' version '3.19' + id 'com.gradle.develocity' version '3.19.1' // https://github.com/equodev/equo-ide/blob/main/plugin-gradle/CHANGELOG.md id 'dev.equo.ide' version '1.7.8' apply false } From 29f88a498bb46a374c79fe493958dfb7e79620f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Jan 2025 18:18:47 +0800 Subject: [PATCH 048/210] chore(deps): update dependency gradle to v8.12.1 (#2411) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a793a8..e18bc253b8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 662da8c339848f0f79dab11dd69fbe1dd22c89a7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 20:34:03 +0800 Subject: [PATCH 049/210] chore(deps): update plugin com.github.spotbugs to v6.1.3 (#2401) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 16a7ef904f..df67386b1d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,7 +12,7 @@ plugins { // https://github.com/gradle-nexus/publish-plugin/releases id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' apply false // https://github.com/spotbugs/spotbugs-gradle-plugin/releases - id 'com.github.spotbugs' version '6.1.0' apply false + id 'com.github.spotbugs' version '6.1.3' apply false // https://github.com/diffplug/spotless-changelog/blob/main/CHANGELOG.md id 'com.diffplug.spotless-changelog' version '3.1.2' apply false // https://github.com/radarsh/gradle-test-logger-plugin/blob/develop/CHANGELOG.md From 1e69a03fa32cc589ae9097e89fe6b60f2622c456 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 10:52:45 +0800 Subject: [PATCH 050/210] chore(deps): update plugin com.gradle.plugin-publish to v1.3.1 (#2415) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index df67386b1d..2ca7c46cf4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,7 +8,7 @@ pluginManagement { plugins { id 'com.diffplug.spotless' version '7.0.2' apply false // https://plugins.gradle.org/plugin/com.gradle.plugin-publish - id 'com.gradle.plugin-publish' version '1.3.0' apply false + id 'com.gradle.plugin-publish' version '1.3.1' apply false // https://github.com/gradle-nexus/publish-plugin/releases id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' apply false // https://github.com/spotbugs/spotbugs-gradle-plugin/releases From 5a5db69db6254de76c2b33ca4c1f76d3da5d62b3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 10:56:59 +0000 Subject: [PATCH 051/210] chore(config): migrate renovate config (#2417) * chore(config): migrate config renovate.json * Update and rename renovate.json to .github/renovate.json5 --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Zongle Wang --- renovate.json => .github/renovate.json5 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename renovate.json => .github/renovate.json5 (67%) diff --git a/renovate.json b/.github/renovate.json5 similarity index 67% rename from renovate.json rename to .github/renovate.json5 index 2b278dfe17..ef44cb00f9 100644 --- a/renovate.json +++ b/.github/renovate.json5 @@ -1,14 +1,14 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base" + "config:recommended", ], "packageRules": [ { "groupName": "Ktlint", "enabled": false, - "matchPackagePatterns": [ - "com.pinterest.ktlint:*" + "matchPackageNames": [ + "/com.pinterest.ktlint:*/", ] } ] From 9a44f536fe2e7acc3f9c706ce620a6686d0b262b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:34:31 +0800 Subject: [PATCH 052/210] chore(deps): update plugin com.github.spotbugs to v6.1.4 (#2420) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 2ca7c46cf4..62aec6d7c7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,7 +12,7 @@ plugins { // https://github.com/gradle-nexus/publish-plugin/releases id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' apply false // https://github.com/spotbugs/spotbugs-gradle-plugin/releases - id 'com.github.spotbugs' version '6.1.3' apply false + id 'com.github.spotbugs' version '6.1.4' apply false // https://github.com/diffplug/spotless-changelog/blob/main/CHANGELOG.md id 'com.diffplug.spotless-changelog' version '3.1.2' apply false // https://github.com/radarsh/gradle-test-logger-plugin/blob/develop/CHANGELOG.md From 5cf14e657847f115c95f356119c9e00437fcfd7e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Feb 2025 14:08:46 +0800 Subject: [PATCH 053/210] chore(deps): update plugin com.github.spotbugs to v6.1.5 (#2422) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 62aec6d7c7..d666da242b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,7 +12,7 @@ plugins { // https://github.com/gradle-nexus/publish-plugin/releases id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' apply false // https://github.com/spotbugs/spotbugs-gradle-plugin/releases - id 'com.github.spotbugs' version '6.1.4' apply false + id 'com.github.spotbugs' version '6.1.5' apply false // https://github.com/diffplug/spotless-changelog/blob/main/CHANGELOG.md id 'com.diffplug.spotless-changelog' version '3.1.2' apply false // https://github.com/radarsh/gradle-test-logger-plugin/blob/develop/CHANGELOG.md From e4c3bc7077404949607eccd048ff1dae074a49b4 Mon Sep 17 00:00:00 2001 From: luc0001r Date: Fri, 14 Feb 2025 20:37:55 +0100 Subject: [PATCH 054/210] use latest maven-plugin-development from GradleX --- plugin-maven/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index edef810a62..f0b1b29508 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -1,9 +1,9 @@ -import de.benediktritter.maven.plugin.development.task.GenerateHelpMojoSourcesTask -import de.benediktritter.maven.plugin.development.task.GenerateMavenPluginDescriptorTask +import org.gradlex.maven.plugin.development.task.GenerateHelpMojoSourcesTask +import org.gradlex.maven.plugin.development.task.GenerateMavenPluginDescriptorTask plugins { - // https://www.benediktritter.de/maven-plugin-development/#release-history - id 'de.benediktritter.maven-plugin-development' version '0.4.3' + // https://github.com/gradlex-org/maven-plugin-development + id 'org.gradlex.maven-plugin-development' version '1.0.3' } apply from: rootProject.file('gradle/changelog.gradle') From 1fb5d3378967d17a0171f7b2d762d667df313ec8 Mon Sep 17 00:00:00 2001 From: luc0001r Date: Fri, 14 Feb 2025 20:38:32 +0100 Subject: [PATCH 055/210] make configuration cache works without issues --- gradle/java-publish.gradle | 24 ++++++++++++++---------- plugin-maven/build.gradle | 7 ------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/gradle/java-publish.gradle b/gradle/java-publish.gradle index d6f0afa5a0..08f2a41417 100644 --- a/gradle/java-publish.gradle +++ b/gradle/java-publish.gradle @@ -107,17 +107,22 @@ model { artifactId project.ext.artifactId version project.version + def projectExtArtifactId = project.ext.artifactId + def projectDescription = project.description + def projectOrg = project.org + def rootProjectName = rootProject.name + pom.withXml { // add MavenCentral requirements to the POM asNode().children().last() + { resolveStrategy = Closure.DELEGATE_FIRST - name project.ext.artifactId - description project.description - url "https://github.com/$%7Bproject.org%7D/$%7BrootProject.name%7D" + name projectExtArtifactId + description projectDescription + url "https://github.com/$%7BprojectOrg%7D/$%7BrootProjectName%7D" scm { - url "https://github.com/$%7Bproject.org%7D/$%7BrootProject.name%7D" - connection "scm:git:https://github.com/${project.org}/${rootProject.name}.git" - developerConnection "scm:git:ssh:git@github.com/${project.org}/${rootProject.name}.git" + url "https://github.com/$%7BprojectOrg%7D/$%7BrootProjectName%7D" + connection "scm:git:https://github.com/${projectOrg}/${rootProjectName}.git" + developerConnection "scm:git:ssh:git@github.com/${projectOrg}/${rootProjectName}.git" } licenses { if (isExt) { @@ -188,13 +193,12 @@ if (System.env['JITPACK'] == 'true' || version.endsWith('-SNAPSHOT')) { dependsOn changelogTasks.named('changelogCheck') } // ensures that changelog bump and push only happens if the publish was successful - def thisProj = project changelogTasks.named('changelogBump').configure { - dependsOn ":${thisProj.path}:publishPluginMavenPublicationToSonatypeRepository" + dependsOn project.path + ":publishPluginMavenPublicationToSonatypeRepository" dependsOn ":closeAndReleaseSonatypeStagingRepository" // if we have a Gradle plugin, we need to push it up to the plugin portal too - if (thisProj.tasks.names.contains('publishPlugins')) { - dependsOn thisProj.tasks.named('publishPlugins') + if (project.tasks.names.contains('publishPlugins')) { + dependsOn project.tasks.named('publishPlugins') } } } diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index f0b1b29508..7932d4a007 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -19,13 +19,6 @@ mavenPlugin { description = project.description } -tasks.withType(GenerateMavenPluginDescriptorTask).configureEach { - notCompatibleWithConfigurationCache('https://github.com/britter/maven-plugin-development/issues/8') -} -tasks.withType(GenerateHelpMojoSourcesTask).configureEach { - notCompatibleWithConfigurationCache('https://github.com/britter/maven-plugin-development/issues/8') -} - String VER_MAVEN_API = '3.0' String VER_ECLIPSE_AETHER = '1.1.0' String VER_PLEXUS_RESOURCES = '1.3.0' From d6154e3fd1af0cd17c0f7013ef15f2f3003092b6 Mon Sep 17 00:00:00 2001 From: luc0001r Date: Fri, 14 Feb 2025 20:49:30 +0100 Subject: [PATCH 056/210] added changelog info --- CHANGES.md | 1 + gradle/java-publish.gradle | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b170b7086d..41990c2fd4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] * Support for`clang-format` on maven-plugin ([#2406](https://github.com/diffplug/spotless/pull/2406)) +* Adopt new version of `maven-plugin-development` from GradleX ([#2395](https://github.com/diffplug/spotless/pull/2395)) ## [3.0.2] - 2025-01-14 ### Fixed diff --git a/gradle/java-publish.gradle b/gradle/java-publish.gradle index 08f2a41417..99879e6b2e 100644 --- a/gradle/java-publish.gradle +++ b/gradle/java-publish.gradle @@ -193,12 +193,13 @@ if (System.env['JITPACK'] == 'true' || version.endsWith('-SNAPSHOT')) { dependsOn changelogTasks.named('changelogCheck') } // ensures that changelog bump and push only happens if the publish was successful + def thisProj = project changelogTasks.named('changelogBump').configure { - dependsOn project.path + ":publishPluginMavenPublicationToSonatypeRepository" + dependsOn ":${thisProj.path}:publishPluginMavenPublicationToSonatypeRepository" dependsOn ":closeAndReleaseSonatypeStagingRepository" // if we have a Gradle plugin, we need to push it up to the plugin portal too - if (project.tasks.names.contains('publishPlugins')) { - dependsOn project.tasks.named('publishPlugins') + if (thisProj.tasks.names.contains('publishPlugins')) { + dependsOn thisProj.tasks.named('publishPlugins') } } } From cdb609ea190bb3203800829e8ccbcb0eadfd900b Mon Sep 17 00:00:00 2001 From: luc0001r Date: Fri, 14 Feb 2025 20:52:04 +0100 Subject: [PATCH 057/210] added changelog info in the right place --- CHANGES.md | 1 - plugin-maven/CHANGES.md | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 41990c2fd4..b170b7086d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,6 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] * Support for`clang-format` on maven-plugin ([#2406](https://github.com/diffplug/spotless/pull/2406)) -* Adopt new version of `maven-plugin-development` from GradleX ([#2395](https://github.com/diffplug/spotless/pull/2395)) ## [3.0.2] - 2025-01-14 ### Fixed diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index aacb203c53..c737b29a43 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,6 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] * Support for `clang-format` ([#2406](https://github.com/diffplug/spotless/pull/2406)) +* Adopt new version of `maven-plugin-development` from GradleX ([#2395](https://github.com/diffplug/spotless/pull/2395)) ## [2.44.2] - 2025-01-14 * Eclipse-based tasks can now handle parallel configuration ([#2389](https://github.com/diffplug/spotless/issues/2389)) From fd5970c17f51b88d1644db275ac4d3991174b3b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:03:56 +0800 Subject: [PATCH 058/210] chore(deps): update plugin com.gradle.develocity to v3.19.2 (#2425) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index d666da242b..da86467edd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -20,7 +20,7 @@ plugins { // https://github.com/davidburstrom/version-compatibility-gradle-plugin/tags id 'io.github.davidburstrom.version-compatibility' version '0.5.0' apply false // https://plugins.gradle.org/plugin/com.gradle.develocity - id 'com.gradle.develocity' version '3.19.1' + id 'com.gradle.develocity' version '3.19.2' // https://github.com/equodev/equo-ide/blob/main/plugin-gradle/CHANGELOG.md id 'dev.equo.ide' version '1.7.8' apply false } From f519ed36a2c5ad5d90976e9b93697b2fe5dde914 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 20 Feb 2025 13:31:55 +0100 Subject: [PATCH 059/210] feat: allow overriding classLoader for jarstate Opening up usage of spotless-lib in `spotless-cli` --- .../java/com/diffplug/spotless/JarState.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/JarState.java b/lib/src/main/java/com/diffplug/spotless/JarState.java index 8680932b9e..76dee4f438 100644 --- a/lib/src/main/java/com/diffplug/spotless/JarState.java +++ b/lib/src/main/java/com/diffplug/spotless/JarState.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. @@ -28,6 +28,11 @@ import java.util.Set; import java.util.stream.Collectors; +import javax.annotation.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Grabs a jar and its dependencies from maven, * and makes it easy to access the collection in @@ -37,6 +42,21 @@ * catch changes in a SNAPSHOT version. */ public final class JarState implements Serializable { + + private static final Logger logger = LoggerFactory.getLogger(JarState.class); + + // Let the classloader be overridden for tools using different approaches to classloading + @Nullable + private static ClassLoader forcedClassLoader = null; + + /** Overrides the classloader used by all JarStates. */ + public static void setForcedClassLoader(@Nullable ClassLoader forcedClassLoader) { + if (!Objects.equals(JarState.forcedClassLoader, forcedClassLoader)) { + logger.info("Overriding the forced classloader for JarState from {} to {}", JarState.forcedClassLoader, forcedClassLoader); + } + JarState.forcedClassLoader = forcedClassLoader; + } + /** A lazily evaluated JarState, which becomes a set of files when serialized. */ public static class Promised implements Serializable { private static final long serialVersionUID = 1L; @@ -125,26 +145,36 @@ URL[] jarUrls() { } /** - * Returns a classloader containing the only jars in this JarState. + * Returns either a forcedClassloader ({@code JarState.setForcedClassLoader()}) or a classloader containing the only jars in this JarState. * Look-up of classes in the {@code org.slf4j} package * are not taken from the JarState, but instead redirected to the class loader of this class to enable * passthrough logging. *
* The lifetime of the underlying cacheloader is controlled by {@link SpotlessCache}. + * + * @see com.diffplug.spotless.JarState#setForcedClassLoader(ClassLoader) */ public ClassLoader getClassLoader() { + if (forcedClassLoader != null) { + return forcedClassLoader; + } return SpotlessCache.instance().classloader(this); } /** - * Returns a classloader containing the only jars in this JarState. + * Returns either a forcedClassloader ({@code JarState.setForcedClassLoader}) or a classloader containing the only jars in this JarState. * Look-up of classes in the {@code org.slf4j} package * are not taken from the JarState, but instead redirected to the class loader of this class to enable * passthrough logging. *
- * The lifetime of the underlying cacheloader is controlled by {@link SpotlessCache}. + * The lifetime of the underlying cacheloader is controlled by {@link SpotlessCache} + * + * @see com.diffplug.spotless.JarState#setForcedClassLoader(ClassLoader) */ public ClassLoader getClassLoader(Serializable key) { + if (forcedClassLoader != null) { + return forcedClassLoader; + } return SpotlessCache.instance().classloader(key, this); } } From 88d3c318a06a48e20e5d843930a638ff75ae7a27 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 20 Feb 2025 13:35:02 +0100 Subject: [PATCH 060/210] chore: update changelog for reflecting overridable classLoader in JarState --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index b170b7086d..d7abd321fa 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] +### Added * Support for`clang-format` on maven-plugin ([#2406](https://github.com/diffplug/spotless/pull/2406)) +* Allow overriding classLoader for all `JarState`s to enable spotless-cli ([#xxx](https://github.com/diffplug/spotless/pull/XXX)) ## [3.0.2] - 2025-01-14 ### Fixed From 8ee1dfe45e3ca426ed82376c61be5f7af7144352 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 20 Feb 2025 16:16:12 +0100 Subject: [PATCH 061/210] chore: provide test to make sure overriding classloader works --- .../com/diffplug/spotless/JarStateTest.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 lib/src/test/java/com/diffplug/spotless/JarStateTest.java diff --git a/lib/src/test/java/com/diffplug/spotless/JarStateTest.java b/lib/src/test/java/com/diffplug/spotless/JarStateTest.java new file mode 100644 index 0000000000..f44aa4a0b3 --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/JarStateTest.java @@ -0,0 +1,107 @@ +/* + * 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; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.util.stream.Collectors; + +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class JarStateTest { + + @TempDir + java.nio.file.Path tempDir; + + File a; + + File b; + + Provisioner provisioner = (withTransitives, deps) -> deps.stream().map(name -> name.equals("a") ? a : b).collect(Collectors.toSet()); + + @BeforeEach + void setUp() throws IOException { + a = Files.createTempFile(tempDir, "a", ".class").toFile(); + Files.writeString(a.toPath(), "a"); + b = Files.createTempFile(tempDir, "b", ".class").toFile(); + Files.writeString(b.toPath(), "b"); + } + + @AfterEach + void tearDown() { + JarState.setForcedClassLoader(null); + } + + @Test + void itCreatesClassloaderWhenForcedClassLoaderNotSet() throws IOException { + JarState state1 = JarState.from(a.getName(), provisioner); + JarState state2 = JarState.from(b.getName(), provisioner); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(state1.getClassLoader()).isNotNull(); + softly.assertThat(state2.getClassLoader()).isNotNull(); + }); + } + + @Test + void itReturnsForcedClassloaderIfSetNoMatterIfSetBeforeOrAfterCreation() throws IOException { + JarState stateA = JarState.from(a.getName(), provisioner); + ClassLoader forcedClassLoader = new URLClassLoader(new java.net.URL[0]); + JarState.setForcedClassLoader(forcedClassLoader); + JarState stateB = JarState.from(b.getName(), provisioner); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(stateA.getClassLoader()).isSameAs(forcedClassLoader); + softly.assertThat(stateB.getClassLoader()).isSameAs(forcedClassLoader); + }); + } + + @Test + void itReturnsForcedClassloaderEvenWhenRountripSerialized() throws IOException, ClassNotFoundException { + JarState stateA = JarState.from(a.getName(), provisioner); + ClassLoader forcedClassLoader = new URLClassLoader(new java.net.URL[0]); + JarState.setForcedClassLoader(forcedClassLoader); + JarState stateB = JarState.from(b.getName(), provisioner); + + JarState stateARoundtripSerialized = roundtripSerialize(stateA); + JarState stateBRoundtripSerialized = roundtripSerialize(stateB); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(stateARoundtripSerialized.getClassLoader()).isSameAs(forcedClassLoader); + softly.assertThat(stateBRoundtripSerialized.getClassLoader()).isSameAs(forcedClassLoader); + }); + } + + private JarState roundtripSerialize(JarState state) throws IOException, ClassNotFoundException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (ObjectOutputStream oOut = new ObjectOutputStream(outputStream)) { + oOut.writeObject(state); + } + try (ObjectInputStream oIn = new ObjectInputStream(new java.io.ByteArrayInputStream(outputStream.toByteArray()))) { + return (JarState) oIn.readObject(); + } + } + +} From 06c6ca8ba332472c41a92dffcc2b436b3d4b5a6e Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 20 Feb 2025 16:19:34 +0100 Subject: [PATCH 062/210] chore: insert created PR# --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index d7abd321fa..6e706fc8e4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Support for`clang-format` on maven-plugin ([#2406](https://github.com/diffplug/spotless/pull/2406)) -* Allow overriding classLoader for all `JarState`s to enable spotless-cli ([#xxx](https://github.com/diffplug/spotless/pull/XXX)) +* Allow overriding classLoader for all `JarState`s to enable spotless-cli ([#2427](https://github.com/diffplug/spotless/pull/2427)) ## [3.0.2] - 2025-01-14 ### Fixed From 62eff174ee9faa4ce5ccbb52332085b0fa525323 Mon Sep 17 00:00:00 2001 From: runner Date: Thu, 20 Feb 2025 18:31:42 +0000 Subject: [PATCH 063/210] Published lib/3.1.0 --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 6e706fc8e4..eaebe45744 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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] + +## [3.1.0] - 2025-02-20 ### Added * Support for`clang-format` on maven-plugin ([#2406](https://github.com/diffplug/spotless/pull/2406)) * Allow overriding classLoader for all `JarState`s to enable spotless-cli ([#2427](https://github.com/diffplug/spotless/pull/2427)) From 4dd0095437906713fc6bad3a2e160646e11b419a Mon Sep 17 00:00:00 2001 From: runner Date: Thu, 20 Feb 2025 23:03:51 +0000 Subject: [PATCH 064/210] Published maven/2.44.3 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index c737b29a43..8b036b98f2 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.44.3] - 2025-02-20 * Support for `clang-format` ([#2406](https://github.com/diffplug/spotless/pull/2406)) * Adopt new version of `maven-plugin-development` from GradleX ([#2395](https://github.com/diffplug/spotless/pull/2395)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 459dd9f1d7..e04085d965 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.44.2-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.2/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.44.3-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.3/index.html) ${project.basedir}/eclipse-formatter.xml + + + + https://download.eclipse.org/eclipse/updates/4.26/ + https://some.internal.mirror/4-26-updates-p2/ + + ``` From 519d36c1177b28865181dbcca606ac3b3b369e79 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 14:03:46 +0800 Subject: [PATCH 074/210] fix(deps): update dependency org.eclipse.platform:org.eclipse.osgi to v3.23.0 (#2446) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib-extra/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib-extra/build.gradle b/lib-extra/build.gradle index 68862448b6..880830740b 100644 --- a/lib-extra/build.gradle +++ b/lib-extra/build.gradle @@ -21,7 +21,7 @@ dependencies { // the osgi dep is included in solstice, but it has some CVE's against it. // 3.18.500 is the oldest, most-compatible version with no CVE's // https://central.sonatype.com/artifact/org.eclipse.platform/org.eclipse.osgi/versions - implementation "org.eclipse.platform:org.eclipse.osgi:3.18.500" + implementation "org.eclipse.platform:org.eclipse.osgi:3.23.0" // testing testImplementation projects.testlib From f6da1c494e818bb0a6279e2db512e0bc874b1c2a Mon Sep 17 00:00:00 2001 From: Mattias Severson Date: Fri, 14 Mar 2025 06:38:15 +0100 Subject: [PATCH 075/210] Use palantir-java-format 2.57.0 on Java 21 (#2447) * bump palantir to version 2.57.0 improved code formatting for Java 21 ref: https://github.com/palantir/palantir-java-format/issues/952 * update readme files with changes * update copyright year in modified files * add "changed" labels --- CHANGES.md | 2 ++ .../com/diffplug/spotless/java/PalantirJavaFormatStep.java | 4 ++-- plugin-gradle/CHANGES.md | 2 ++ plugin-maven/CHANGES.md | 2 ++ .../diffplug/spotless/java/PalantirJavaFormatStepTest.java | 4 ++-- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index eaebe45744..9c7f3e0d39 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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] +### Changed +* Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) ## [3.1.0] - 2025-02-20 ### Added diff --git a/lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java b/lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java index 3b7d7c17a9..7745f6e879 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.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. @@ -29,7 +29,7 @@ public class PalantirJavaFormatStep implements Serializable { private static final String DEFAULT_STYLE = "PALANTIR"; private static final String NAME = "palantir-java-format"; public static final String MAVEN_COORDINATE = "com.palantir.javaformat:palantir-java-format:"; - private static final Jvm.Support JVM_SUPPORT = Jvm. support(NAME).add(8, "1.1.0").add(11, "2.28.0").add(21, "2.39.0"); + private static final Jvm.Support JVM_SUPPORT = Jvm. support(NAME).add(8, "1.1.0").add(11, "2.28.0").add(21, "2.57.0"); /** The jar that contains the formatter. */ private final JarState.Promised jarState; diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 8bd24914b1..59b829359f 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Changed +* Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) ## [7.0.2] - 2025-01-14 ### Fixed diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 8b036b98f2..addbe10424 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Changed +* Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) ## [2.44.3] - 2025-02-20 * Support for `clang-format` ([#2406](https://github.com/diffplug/spotless/pull/2406)) diff --git a/testlib/src/test/java/com/diffplug/spotless/java/PalantirJavaFormatStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/PalantirJavaFormatStepTest.java index cb8777728b..6e197dc8fa 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/PalantirJavaFormatStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/PalantirJavaFormatStepTest.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. @@ -56,7 +56,7 @@ void behavior() throws Exception { @Test void formatJavadoc() throws Exception { - FormatterStep step = PalantirJavaFormatStep.create("2.39.0", "PALANTIR", true, TestProvisioner.mavenCentral()); + FormatterStep step = PalantirJavaFormatStep.create("2.57.0", "PALANTIR", true, TestProvisioner.mavenCentral()); StepHarness.forStep(step) .testResource("java/palantirjavaformat/JavaCodeWithJavaDocUnformatted.test", "java/palantirjavaformat/JavaCodeWithJavaDocFormatted.test") .testResource("java/palantirjavaformat/JavaCodeWithPackageUnformatted.test", "java/palantirjavaformat/JavaCodeWithPackageFormatted.test"); From 1e628a1f215fd5ba679a82a8d02c462486159c07 Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 14 Mar 2025 11:04:50 +0100 Subject: [PATCH 076/210] fix: try online install after ERESOLVE (#2448) --- .../com/diffplug/spotless/npm/NodeApp.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/NodeApp.java b/lib/src/main/java/com/diffplug/spotless/npm/NodeApp.java index 932a148626..19eb584c57 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/NodeApp.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/NodeApp.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -98,18 +98,28 @@ private void optimizedNpmInstall() { if (!offlineInstallFailed(e.getResult())) { throw e; // pass through } - // if the npm install fails with message "No matching version found for @", we try again without the offline flag + // if the npm install fails in a way that might be caused by missing dependency information, we try again without the offline flag npmProcessFactory.createNpmInstallProcess(nodeServerLayout, formatterStepLocations, PREFER_ONLINE).waitFor(); } } - private boolean offlineInstallFailed(ProcessRunner.Result result) { + private static boolean offlineInstallFailed(ProcessRunner.Result result) { if (result == null) { return false; // no result, something else must have happened } if (result.exitCode() == 0) { return false; // all is well } - return result.stdOutUtf8().contains("code ETARGET") && result.stdOutUtf8().contains("No matching version found for"); // offline install failed, needs online install + var installOutput = result.stdOutUtf8(); + // offline install failed, needs online install + return isNoMatchingVersionFound(installOutput) || isCannotResolveDependencyTree(installOutput); + } + + private static boolean isNoMatchingVersionFound(String installOutput) { + return installOutput.contains("code ETARGET") && installOutput.contains("No matching version found for"); + } + + private static boolean isCannotResolveDependencyTree(String installOutput) { + return installOutput.contains("code ERESOLVE") && installOutput.contains("unable to resolve dependency tree"); } } From b6bf416dda59d7db56c2074caf5fd85d5808eaba Mon Sep 17 00:00:00 2001 From: Joshua Gleitze Date: Fri, 14 Mar 2025 11:08:03 +0100 Subject: [PATCH 077/210] docs: document ERESOLVE fix --- CHANGES.md | 1 + plugin-gradle/CHANGES.md | 1 + plugin-maven/CHANGES.md | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 9c7f3e0d39..7d16300cce 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) +* Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) ## [3.1.0] - 2025-02-20 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 59b829359f..b40b63b4c8 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -5,6 +5,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) +* Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) ## [7.0.2] - 2025-01-14 ### Fixed diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index addbe10424..483258c36a 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -5,6 +5,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) +* Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) ## [2.44.3] - 2025-02-20 * Support for `clang-format` ([#2406](https://github.com/diffplug/spotless/pull/2406)) From 8095512f521772b621898891eb56817507c0100f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:52:11 +0000 Subject: [PATCH 078/210] fix(deps): update dependency org.junit.jupiter:junit-jupiter to v5.12.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1da5b0337b..6ab7b9b519 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,7 +29,7 @@ VER_SLF4J=[1.6,2.0[ # Used in multiple places VER_DURIAN=1.2.0 VER_JGIT=6.10.0.202406032230-r -VER_JUNIT=5.12.0 +VER_JUNIT=5.12.1 VER_ASSERTJ=3.27.3 VER_MOCKITO=5.16.0 VER_SELFIE=2.4.2 \ No newline at end of file From 822b52da39d36dcd53cc61bbec27bc49d14f44e8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 16 Mar 2025 14:53:14 +0800 Subject: [PATCH 079/210] fix(deps): update dependency org.mockito:mockito-core to v5.16.1 (#2452) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6ab7b9b519..5e3200d34b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,5 +31,5 @@ VER_DURIAN=1.2.0 VER_JGIT=6.10.0.202406032230-r VER_JUNIT=5.12.1 VER_ASSERTJ=3.27.3 -VER_MOCKITO=5.16.0 +VER_MOCKITO=5.16.1 VER_SELFIE=2.4.2 \ No newline at end of file From 668ce10128cbbf983222a11a61a81d7a163235b2 Mon Sep 17 00:00:00 2001 From: Paul Merlin Date: Sat, 22 Mar 2025 03:53:20 +0100 Subject: [PATCH 080/210] Enable :gradle-plugin strict validation Enable Gradle Plugin types strict validation by the :gradle-plugin:validatePlugins task. The task now applies more rules for plugin types. Add missing mandatory cacheability annotations on SpotlessTask, SpotlessApply, SpotlessCheck and SpotlessDiagnoseTask. --- plugin-gradle/build.gradle | 3 +++ .../main/java/com/diffplug/gradle/spotless/SpotlessApply.java | 4 +++- .../main/java/com/diffplug/gradle/spotless/SpotlessCheck.java | 4 +++- .../com/diffplug/gradle/spotless/SpotlessDiagnoseTask.java | 4 +++- .../main/java/com/diffplug/gradle/spotless/SpotlessTask.java | 4 +++- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/plugin-gradle/build.gradle b/plugin-gradle/build.gradle index 4f82f713bf..5211428f8b 100644 --- a/plugin-gradle/build.gradle +++ b/plugin-gradle/build.gradle @@ -33,6 +33,9 @@ apply from: rootProject.file('gradle/special-tests.gradle') tasks.withType(Test).configureEach { testLogging.showStandardStreams = true } +tasks.validatePlugins { + enableStricterValidation = true +} ////////////////////////// // GRADLE PLUGIN PORTAL // diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.java index f38745a6b0..c623669ab1 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.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. @@ -25,7 +25,9 @@ import org.gradle.api.file.FileVisitDetails; import org.gradle.api.file.FileVisitor; import org.gradle.api.tasks.TaskAction; +import org.gradle.work.DisableCachingByDefault; +@DisableCachingByDefault(because = "not worth caching") public abstract class SpotlessApply extends SpotlessTaskService.ClientTask { @TaskAction public void performAction() { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.java index dba219ff06..175a828a66 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.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. @@ -32,12 +32,14 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.TaskAction; +import org.gradle.work.DisableCachingByDefault; import org.jetbrains.annotations.NotNull; import com.diffplug.spotless.FileSignature; import com.diffplug.spotless.ThrowingEx; import com.diffplug.spotless.extra.integration.DiffMessageFormatter; +@DisableCachingByDefault(because = "not worth caching") public abstract class SpotlessCheck extends SpotlessTaskService.ClientTask { @Internal public abstract Property getEncoding(); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessDiagnoseTask.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessDiagnoseTask.java index 6dcba72864..68f6e63e75 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessDiagnoseTask.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessDiagnoseTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -25,12 +25,14 @@ import org.gradle.api.DefaultTask; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.UntrackedTask; import com.diffplug.spotless.Formatter; import com.diffplug.spotless.PaddedCell; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +@UntrackedTask(because = "undeclared inputs/outputs") public class SpotlessDiagnoseTask extends DefaultTask { SpotlessTask source; diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java index e31be63143..713c9a2e86 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2024 DiffPlug + * Copyright 2020-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; +import org.gradle.work.DisableCachingByDefault; import org.gradle.work.Incremental; import com.diffplug.spotless.ConfigurationCacheHackList; @@ -43,6 +44,7 @@ import com.diffplug.spotless.LintSuppression; import com.diffplug.spotless.extra.GitRatchet; +@DisableCachingByDefault(because = "abstract definition") public abstract class SpotlessTask extends DefaultTask { @Internal abstract Property getTaskService(); From fc0ec004f0b52ca33e5030efc0b2ddfb8e1b4990 Mon Sep 17 00:00:00 2001 From: Paul Merlin Date: Sat, 22 Mar 2025 04:46:28 +0100 Subject: [PATCH 081/210] Update CHANGES.md for enabling Gradle's stricter plugin types validation --- plugin-gradle/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index b40b63b4c8..5d2cb19742 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -6,6 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) +* Apply Gradle's strict plugin types validation to the Spotless plugin. ([#2454](https://github.com/diffplug/spotless/pull/2454)) ## [7.0.2] - 2025-01-14 ### Fixed From f9c14d88c7fc21f61715636806f66b5f572c0dab Mon Sep 17 00:00:00 2001 From: Tomas Bjerre Date: Thu, 27 Mar 2025 18:44:48 +0100 Subject: [PATCH 082/210] chore: formatting --- .../main/java/com/diffplug/spotless/FormatterProperties.java | 2 +- .../java/com/diffplug/gradle/spotless/BaseGroovyExtension.java | 2 +- .../main/java/com/diffplug/gradle/spotless/CppExtension.java | 2 +- .../main/java/com/diffplug/gradle/spotless/JavaExtension.java | 2 +- .../test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java | 2 +- .../java/com/diffplug/spotless/FormatterPropertiesTest.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java b/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java index 455318e38f..ad180ab77a 100644 --- a/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java +++ b/lib/src/main/java/com/diffplug/spotless/FormatterProperties.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. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java index 37712a470b..15e042962e 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java index db7d9bee9a..4dcb033fc5 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.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. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index 343092b4ad..b4bffc6b20 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.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. diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java index 862f82010f..df47de98b5 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaEclipseTest.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. diff --git a/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java b/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java index 58ae1c913e..6356e02660 100644 --- a/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.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. From 81f2f8bb742a98c2f7e69bc7e2e10fb6b2d6c75c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 19:00:30 +0000 Subject: [PATCH 083/210] fix(deps): update dependency org.mockito:mockito-core to v5.17.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5e3200d34b..10de201dab 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,5 +31,5 @@ VER_DURIAN=1.2.0 VER_JGIT=6.10.0.202406032230-r VER_JUNIT=5.12.1 VER_ASSERTJ=3.27.3 -VER_MOCKITO=5.16.1 +VER_MOCKITO=5.17.0 VER_SELFIE=2.4.2 \ No newline at end of file From 60993fdedff91eeebf2ef016893b1ee433811a3f Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 7 Apr 2025 13:05:19 -0700 Subject: [PATCH 084/210] Fix the Android Kotlin warning and adjust its position. --- plugin-gradle/README.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 7c067adb73..2067222fbf 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -435,19 +435,6 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T - `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) - `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) -> [!WARNING] -> The target is usually inferred automatically from the java source sets. However, Spotless cannot automatically detect [android](https://github.com/diffplug/spotless/issues/111) or [java-gradle-plugin](https://github.com/diffplug/spotless/issues/437) sources, but you can fix this easily: -> -> ```gradle -> spotless { -> kotlin { -> target 'src/*/kotlin/**/*.kt' -> target 'src/*/java/**/*.kt' -> } -> kotlinGradle { -> target '**/*.kts' -> } -> ``` ```gradle spotless { // if you are using build.gradle.kts, instead of 'spotless {' use: @@ -467,6 +454,16 @@ spotless { // if you are using build.gradle.kts, instead of 'spotless {' use: } ``` +> [!WARNING] +> The target is usually inferred automatically from the java source sets. However, Spotless cannot automatically detect [android](https://github.com/diffplug/spotless/issues/111) or [java-gradle-plugin](https://github.com/diffplug/spotless/issues/437) sources, but you can fix this easily: +> +> ```gradle +> spotless { +> kotlin { +> target 'src/*/kotlin/**/*.kt', 'src/*/java/**/*.kt' +> ... +> ``` + ### ktfmt [homepage](https://github.com/facebook/ktfmt). [changelog](https://github.com/facebook/ktfmt/releases). From fa3fd1e6cb99a6bb3b2a9c8b262db4666edf6ca7 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 7 Apr 2025 13:07:04 -0700 Subject: [PATCH 085/210] Add the cool blockquote warning trick to the other Android spot. --- plugin-gradle/README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 2067222fbf..ecd85930fc 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -207,13 +207,14 @@ spotless { -The target is usually inferred automatically from the java source sets. However, Spotless cannot automatically detect [android](https://github.com/diffplug/spotless/issues/111) or [java-gradle-plugin](https://github.com/diffplug/spotless/issues/437) sources, but you can fix this easily: - -```gradle -spotless { - java { - target 'src/*/java/**/*.java' -``` +> [!WARNING] +> The target is usually inferred automatically from the java source sets. However, Spotless cannot automatically detect [android](https://github.com/diffplug/spotless/issues/111) or [java-gradle-plugin](https://github.com/diffplug/spotless/issues/437) sources, but you can fix this easily: +> +> ```gradle +> spotless { +> java { +> target 'src/*/java/**/*.java' +> ``` ### removeUnusedImports From d25f04de3e75030c91962739bc99ea7d377d7678 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 7 Apr 2025 13:08:28 -0700 Subject: [PATCH 086/210] Minor tweak. --- plugin-gradle/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index ecd85930fc..ef7b6be888 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -460,9 +460,8 @@ spotless { // if you are using build.gradle.kts, instead of 'spotless {' use: > > ```gradle > spotless { -> kotlin { -> target 'src/*/kotlin/**/*.kt', 'src/*/java/**/*.kt' -> ... +> kotlin { +> target 'src/*/kotlin/**/*.kt', 'src/*/java/**/*.kt' > ``` ### ktfmt From da3b75b4cc8e50960d3dbbf2601d1ba4ab9613f1 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 7 Apr 2025 20:16:56 +0200 Subject: [PATCH 087/210] fix: separate node_modules dir per npm based formatter without this change, using the exact same npm-based formatter (e.g. prettier) in multiple formatters, we could end up using the same directory to store their node_modules inside. This could lead - especially when using parallel builds, to a lot of issues: - overwriting each others node_modules mid-flight - overwriting package.json mid-flight - starting multiple npm-based servers on the same directory (overwriting the port-file thus leading to cross-access between formatter steps and their corresponding node server). By applying this fix, each formatter will have its own separate node_modules directory. --- .../spotless/npm/EslintFormatterStep.java | 9 +- .../npm/NpmFormatterStepStateBase.java | 4 +- .../spotless/npm/PrettierFormatterStep.java | 9 +- .../gradle/spotless/FormatExtension.java | 2 +- .../gradle/spotless/JavascriptExtension.java | 4 +- .../gradle/spotless/TypescriptExtension.java | 4 +- .../spotless/PrettierIntegrationTest.java | 91 +++++++++++++++---- .../spotless/maven/FormatterFactory.java | 10 +- .../spotless/maven/FormatterStepConfig.java | 10 +- .../spotless/maven/FormattersHolder.java | 13 ++- .../spotless/maven/generic/Prettier.java | 4 +- .../maven/javascript/AbstractEslint.java | 4 +- .../prettier/PrettierFormatStepTest.java | 36 +++++++- .../spotless/npm/EslintFormatterStepTest.java | 5 +- .../npm/PrettierFormatterStepTest.java | 10 +- 15 files changed, 163 insertions(+), 52 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java b/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java index 70beaf91ca..d32f4e58b9 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.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. @@ -68,13 +68,14 @@ public static Map defaultDevDependenciesWithEslint(String versio return Collections.singletonMap("eslint", version); } - public static FormatterStep create(Map devDependencies, Provisioner provisioner, File projectDir, File buildDir, File cacheDir, NpmPathResolver npmPathResolver, EslintConfig eslintConfig) { + public static FormatterStep create(String formatName, Map devDependencies, Provisioner provisioner, File projectDir, File buildDir, File cacheDir, NpmPathResolver npmPathResolver, EslintConfig eslintConfig) { requireNonNull(devDependencies); requireNonNull(provisioner); requireNonNull(projectDir); requireNonNull(buildDir); - return FormatterStep.createLazy(NAME, - () -> new State(NAME, devDependencies, projectDir, buildDir, cacheDir, npmPathResolver, eslintConfig), + final String prefixedName = String.format("%s-%s", formatName, NAME); + return FormatterStep.createLazy(prefixedName, + () -> new State(prefixedName, devDependencies, projectDir, buildDir, cacheDir, npmPathResolver, eslintConfig), State::createFormatterFunc); } diff --git a/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java b/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java index 3ec06e0434..dd798e6e55 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.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. @@ -69,7 +69,7 @@ public static class Runtime { Runtime(NpmFormatterStepStateBase parent) { this.parent = parent; - this.nodeServerLayout = new NodeServerLayout(parent.locations.buildDir(), parent.npmConfig.getPackageJsonContent()); + this.nodeServerLayout = new NodeServerLayout(new File(parent.locations.buildDir(), parent.stepName), parent.npmConfig.getPackageJsonContent()); this.nodeServeApp = new NodeServeApp(nodeServerLayout, parent.npmConfig, parent.locations); } diff --git a/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java b/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java index 27a1002df5..0f81934e24 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.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. @@ -51,12 +51,13 @@ public static final Map defaultDevDependenciesWithPrettier(Strin return Collections.singletonMap("prettier", version); } - public static FormatterStep create(Map devDependencies, Provisioner provisioner, File projectDir, File buildDir, File cacheDir, NpmPathResolver npmPathResolver, PrettierConfig prettierConfig) { + public static FormatterStep create(String formatName, Map devDependencies, Provisioner provisioner, File projectDir, File buildDir, File cacheDir, NpmPathResolver npmPathResolver, PrettierConfig prettierConfig) { requireNonNull(devDependencies); requireNonNull(provisioner); requireNonNull(buildDir); - return FormatterStep.createLazy(NAME, - () -> new State(NAME, devDependencies, projectDir, buildDir, cacheDir, npmPathResolver, prettierConfig), + final String prefixedName = String.format("%s-%s", formatName, NAME); + return FormatterStep.createLazy(prefixedName, + () -> new State(prefixedName, devDependencies, projectDir, buildDir, cacheDir, npmPathResolver, prettierConfig), State::createFormatterFunc); } 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 69150724c1..712e6fe00a 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 @@ -798,7 +798,7 @@ public PrettierConfig config(final Map prettierConfig) { @Override protected FormatterStep createStep() { final Project project = getProject(); - return PrettierFormatterStep.create(devDependencies, provisioner(), project.getProjectDir(), + return PrettierFormatterStep.create(formatName(), devDependencies, provisioner(), project.getProjectDir(), project.getLayout().getBuildDirectory().getAsFile().get(), npmModulesCacheOrNull(), new NpmPathResolver(npmFileOrNull(), nodeFileOrNull(), npmrcFileOrNull(), Arrays.asList(project.getProjectDir(), project.getRootDir())), diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java index 5532045bc2..7968f86e28 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.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. @@ -106,7 +106,7 @@ public JavascriptEslintConfig(Map devDependencies) { public FormatterStep createStep() { final Project project = getProject(); - return EslintFormatterStep.create(devDependencies, provisioner(), project.getProjectDir(), + return EslintFormatterStep.create(NAME, devDependencies, provisioner(), project.getProjectDir(), project.getLayout().getBuildDirectory().getAsFile().get(), npmModulesCacheOrNull(), new NpmPathResolver(npmFileOrNull(), nodeFileOrNull(), npmrcFileOrNull(), Arrays.asList(project.getProjectDir(), project.getRootDir())), diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java index 39e050d51e..9794a3c349 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.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. @@ -214,7 +214,7 @@ public TypescriptEslintConfig tsconfigFile(Object path) { public FormatterStep createStep() { final Project project = getProject(); - return EslintFormatterStep.create(devDependencies, provisioner(), project.getProjectDir(), + return EslintFormatterStep.create(NAME, devDependencies, provisioner(), project.getProjectDir(), project.getLayout().getBuildDirectory().getAsFile().get(), npmModulesCacheOrNull(), new NpmPathResolver(npmFileOrNull(), nodeFileOrNull(), npmrcFileOrNull(), Arrays.asList(project.getProjectDir(), project.getRootDir())), diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java index b6547204b8..6c85949861 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.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,10 +15,18 @@ */ package com.diffplug.gradle.spotless; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import org.assertj.core.api.Assertions; import org.gradle.testkit.runner.BuildResult; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -51,7 +59,7 @@ void useInlineConfig(String prettierVersion) throws IOException { "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); switch (prettierVersion) { case PRETTIER_VERSION_2: assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_2.clean"); @@ -81,7 +89,7 @@ void verifyCleanSpotlessCheckWorks(String prettierVersion) throws IOException { "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessCheckFailsGracefully = gradleRunner().withArguments("--stacktrace", "spotlessCheck").buildAndFail(); - Assertions.assertThat(spotlessCheckFailsGracefully.getOutput()).contains("> The following files had format violations:"); + assertThat(spotlessCheckFailsGracefully.getOutput()).contains("> The following files had format violations:"); gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); gradleRunner().withArguments("--stacktrace", "spotlessCheck").build(); @@ -104,7 +112,7 @@ void useFileConfig(String prettierVersion) throws IOException { "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); switch (prettierVersion) { case PRETTIER_VERSION_2: assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_2.clean"); @@ -131,7 +139,7 @@ void chooseParserBasedOnFilename(String prettierVersion) throws IOException { "}"); setFile("dirty.json").toResource("npm/prettier/filename/dirty.json"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); assertFile("dirty.json").sameAsResource("npm/prettier/filename/clean.json"); } @@ -169,7 +177,7 @@ void useJavaCommunityPlugin(String prettierVersion) throws IOException { "}"); setFile("JavaTest.java").toResource("npm/prettier/plugins/java-test.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); assertFile("JavaTest.java").sameAsResource("npm/prettier/plugins/java-test.clean"); } @@ -202,7 +210,7 @@ void useJavaCommunityPluginFileConfig(String prettierVersion) throws IOException "}"); setFile("JavaTest.java").toResource("npm/prettier/plugins/java-test.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); assertFile("JavaTest.java").sameAsResource("npm/prettier/plugins/java-test.clean"); } @@ -226,8 +234,8 @@ void suggestsMissingJavaCommunityPlugin(String prettierVersion) throws IOExcepti "}"); setFile("JavaTest.java").toResource("npm/prettier/plugins/java-test.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail(); - Assertions.assertThat(spotlessApply.getOutput()).contains("Could not infer a parser"); - Assertions.assertThat(spotlessApply.getOutput()).contains("prettier-plugin-java"); + assertThat(spotlessApply.getOutput()).contains("Could not infer a parser"); + assertThat(spotlessApply.getOutput()).contains("prettier-plugin-java"); } @ParameterizedTest(name = "{index}: usePhpCommunityPlugin with prettier {0}") @@ -264,7 +272,7 @@ void usePhpCommunityPlugin(String prettierVersion) throws IOException { "}"); setFile("php-example.php").toResource("npm/prettier/plugins/php.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); assertFile("php-example.php").sameAsResource("npm/prettier/plugins/php.clean"); } @@ -324,9 +332,9 @@ void usePhpAndJavaCommunityPlugin(String prettierVersion) throws IOException { setFile("php-example.php").toResource("npm/prettier/plugins/php.dirty"); setFile("JavaTest.java").toResource("npm/prettier/plugins/java-test.dirty"); final BuildResult spotlessApply = gradleRunner().forwardOutput().withArguments("--stacktrace", "--info", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); final BuildResult spotlessApply2 = gradleRunner().forwardOutput().withArguments("--stacktrace", "--info", "spotlessApply").build(); - Assertions.assertThat(spotlessApply2.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply2.getOutput()).contains("BUILD SUCCESSFUL"); assertFile("php-example.php").sameAsResource("npm/prettier/plugins/php.clean"); assertFile("JavaTest.java").sameAsResource("npm/prettier/plugins/java-test.clean"); } @@ -355,7 +363,7 @@ void autodetectNpmrcFileConfig(String prettierVersion) throws IOException { "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail(); - Assertions.assertThat(spotlessApply.getOutput()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); + assertThat(spotlessApply.getOutput()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); } @ParameterizedTest(name = "{index}: verifyCleanAndSpotlessWorks with prettier {0}") @@ -377,9 +385,9 @@ void verifyCleanAndSpotlessWorks(String prettierVersion) throws IOException { "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "clean", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); final BuildResult spotlessApply2 = gradleRunner().withArguments("--stacktrace", "clean", "spotlessApply").build(); - Assertions.assertThat(spotlessApply2.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply2.getOutput()).contains("BUILD SUCCESSFUL"); } @ParameterizedTest(name = "{index}: verifyCleanAndSpotlessWithNpmInstallCacheWorks with prettier {0}") @@ -401,9 +409,9 @@ void verifyCleanAndSpotlessWithNpmInstallCacheWorks(String prettierVersion) thro "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "clean", "spotlessApply").build(); - Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); final BuildResult spotlessApply2 = gradleRunner().withArguments("--stacktrace", "clean", "spotlessApply").build(); - Assertions.assertThat(spotlessApply2.getOutput()).contains("BUILD SUCCESSFUL"); + assertThat(spotlessApply2.getOutput()).contains("BUILD SUCCESSFUL"); } @ParameterizedTest(name = "{index}: autodetectNpmrcFileConfig with prettier {0}") @@ -430,6 +438,51 @@ void pickupNpmrcFileConfig(String prettierVersion) throws IOException { "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail(); - Assertions.assertThat(spotlessApply.getOutput()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); + assertThat(spotlessApply.getOutput()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); + } + + @Test + void multiplePrettierSetupsDoNotIntersectOnNpmDir() throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "def prettierConfig = [:]", + "prettierConfig['printWidth'] = 120", + "spotless {", + " format 'mytypescript', {", + " target 'test.ts'", + " prettier().config(prettierConfig)", + " }", + " format 'json', {", + " target 'test.json'", + " prettier().config(prettierConfig)", + " }", + " javascript {", + " target 'test.js'", + " prettier().config(prettierConfig)", + " }", + "}"); + + setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); + setFile("test.json").toResource("npm/prettier/filetypes/json/json.dirty"); + setFile("test.js").toResource("npm/prettier/filetypes/javascript-es5/javascript-es5.dirty"); + + final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + + File buildFolder = new File(rootFolder(), "build"); + assertThat(buildFolder).isNotEmptyDirectory(); + + // verify it contains 3 folders containing "spotless-prettier" in it (recursively) - one for each format + try (Stream pathStream = Files.walk(buildFolder.toPath())) { + List nodeModulesDirs = pathStream + .sorted() + .filter(Files::isDirectory) + .filter(path -> path.getFileName().toString().contains("spotless-prettier")) + .collect(Collectors.toList()); + assertThat(nodeModulesDirs).hasSize(3); + } } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java index 456c31b9a3..541d7385eb 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.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. @@ -83,12 +83,12 @@ public final Set excludes() { return excludes == null ? emptySet() : Sets.newHashSet(excludes); } - public final Formatter newFormatter(Supplier> filesToFormat, FormatterConfig config) { + public final Formatter newFormatter(Supplier> filesToFormat, FormatterConfig config, int formatterIndex) { Charset formatterEncoding = encoding(config); LineEnding formatterLineEndings = lineEndings(config); LineEnding.Policy formatterLineEndingPolicy = formatterLineEndings.createPolicy(config.getFileLocator().getBaseDir(), filesToFormat); - FormatterStepConfig stepConfig = stepConfig(formatterEncoding, config); + FormatterStepConfig stepConfig = stepConfig(formatterEncoding, config, formatterIndex); List factories = gatherStepFactories(config.getGlobalStepFactories(), stepFactories); List formatterSteps = factories.stream() @@ -174,8 +174,8 @@ Optional ratchetFrom(FormatterConfig config) { } } - private FormatterStepConfig stepConfig(Charset encoding, FormatterConfig config) { - return new FormatterStepConfig(encoding, licenseHeaderDelimiter(), ratchetFrom(config), config.getProvisioner(), config.getFileLocator(), config.getSpotlessSetLicenseHeaderYearsFromGitHistory()); + private FormatterStepConfig stepConfig(Charset encoding, FormatterConfig config, int formatterIndex) { + return new FormatterStepConfig(encoding, licenseHeaderDelimiter(), ratchetFrom(config), config.getProvisioner(), config.getFileLocator(), config.getSpotlessSetLicenseHeaderYearsFromGitHistory(), String.format("%s-%d", "formatter", formatterIndex)); } private static List gatherStepFactories(List allGlobal, List allConfigured) { diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java index a1f2e52b41..ecaad55446 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 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. @@ -28,14 +28,16 @@ public class FormatterStepConfig { private final Provisioner provisioner; private final FileLocator fileLocator; private final Optional spotlessSetLicenseHeaderYearsFromGitHistory; + private final String name; - public FormatterStepConfig(Charset encoding, String licenseHeaderDelimiter, Optional ratchetFrom, Provisioner provisioner, FileLocator fileLocator, Optional spotlessSetLicenseHeaderYearsFromGitHistory) { + public FormatterStepConfig(Charset encoding, String licenseHeaderDelimiter, Optional ratchetFrom, Provisioner provisioner, FileLocator fileLocator, Optional spotlessSetLicenseHeaderYearsFromGitHistory, String name) { this.encoding = encoding; this.licenseHeaderDelimiter = licenseHeaderDelimiter; this.ratchetFrom = ratchetFrom; this.provisioner = provisioner; this.fileLocator = fileLocator; this.spotlessSetLicenseHeaderYearsFromGitHistory = spotlessSetLicenseHeaderYearsFromGitHistory; + this.name = name; } public Charset getEncoding() { @@ -61,4 +63,8 @@ public FileLocator getFileLocator() { public Optional spotlessSetLicenseHeaderYearsFromGitHistory() { return spotlessSetLicenseHeaderYearsFromGitHistory; } + + public String getName() { + return name; + } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormattersHolder.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormattersHolder.java index 9b279c8845..dea60739db 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormattersHolder.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormattersHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 DiffPlug + * Copyright 2021-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,14 @@ package com.diffplug.spotless.maven; import java.io.File; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.function.Supplier; +import java.util.stream.Collectors; import com.diffplug.spotless.Formatter; @@ -40,12 +43,16 @@ public String nameFor(FormatterFactory factory) { static FormattersHolder create(Map>> formatterFactoryToFiles, FormatterConfig config) { Map openFormatters = new LinkedHashMap<>(); try { - for (Entry>> entry : formatterFactoryToFiles.entrySet()) { + List>>> formatterEntries = new ArrayList<>(formatterFactoryToFiles.entrySet()); + for (int formatterIndex = 0; formatterIndex < formatterEntries.size(); formatterIndex++) { + Entry>> entry = formatterEntries.get(formatterIndex); FormatterFactory formatterFactory = entry.getKey(); Supplier> files = entry.getValue(); - Formatter formatter = formatterFactory.newFormatter(files, config); + Formatter formatter = formatterFactory.newFormatter(files, config, formatterIndex); openFormatters.put(formatterFactory, formatter); } + + System.out.println("Created formatters: " + openFormatters.keySet().stream().map(f -> f.includes()).collect(Collectors.toList())); } catch (RuntimeException openError) { try { close(openFormatters.values()); diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java index c6b3e46e3c..f747f8764a 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -103,7 +103,7 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) { File cacheDir = cacheDir(stepConfig); PrettierConfig prettierConfig = new PrettierConfig(configFileHandler, configInline); NpmPathResolver npmPathResolver = npmPathResolver(stepConfig); - return PrettierFormatterStep.create(devDependencies, stepConfig.getProvisioner(), baseDir, buildDir, cacheDir, npmPathResolver, prettierConfig); + return PrettierFormatterStep.create(stepConfig.getName(), devDependencies, stepConfig.getProvisioner(), baseDir, buildDir, cacheDir, npmPathResolver, prettierConfig); } private static IllegalArgumentException onlyOneConfig() { diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/AbstractEslint.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/AbstractEslint.java index ad113de833..2b85cdcebc 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/AbstractEslint.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/AbstractEslint.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -69,7 +69,7 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) { File baseDir = baseDir(stepConfig); File cacheDir = cacheDir(stepConfig); NpmPathResolver npmPathResolver = npmPathResolver(stepConfig); - return EslintFormatterStep.create(devDependencies, stepConfig.getProvisioner(), baseDir, buildDir, cacheDir, npmPathResolver, eslintConfig(stepConfig)); + return EslintFormatterStep.create(stepConfig.getName(), devDependencies, stepConfig.getProvisioner(), baseDir, buildDir, cacheDir, npmPathResolver, eslintConfig(stepConfig)); } private static IllegalArgumentException onlyOneConfig() { diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java index abba35e72c..f5f5bddccd 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -17,7 +17,13 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -158,6 +164,34 @@ void multiple_prettier_configs() throws Exception { } + /** + * This test is to ensure that we can have multiple equivalent prettier instances in one spotless config. + */ + @Test + void multiple_equivalent_prettier_configs_do_not_intersect() throws Exception { + writePom( + formats( + groupWithSteps("myjson", including("test.json"), + "", + ""), + groupWithSteps("myts", including("test.ts"), + "", + ""))); + + setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); + setFile("test.json").toResource("npm/prettier/filetypes/json/json.dirty"); + mavenRunner().withArguments("spotless:apply").runNoError(); + + // check that each prettier instance has its own node_modules directory + File targetDir = new File(rootFolder(), "target"); + try (Stream files = Files.walk(targetDir.toPath())) { + List prettierFolders = files.filter(Files::isDirectory) + .filter(path -> path.getFileName().toString().contains("spotless-prettier")) + .collect(Collectors.toList()); + assertThat(prettierFolders).hasSize(2); // one for each prettier instance + } + } + @Test void custom_plugin() throws Exception { writePomWithFormatSteps( diff --git a/testlib/src/test/java/com/diffplug/spotless/npm/EslintFormatterStepTest.java b/testlib/src/test/java/com/diffplug/spotless/npm/EslintFormatterStepTest.java index da00e37d35..6b8debedfb 100644 --- a/testlib/src/test/java/com/diffplug/spotless/npm/EslintFormatterStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/npm/EslintFormatterStepTest.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. @@ -58,6 +58,7 @@ void formattingUsingRulesetsFile(String ruleSetName) throws Exception { final String cleanFile = filedir + "javascript-es6.clean"; final FormatterStep formatterStep = EslintFormatterStep.create( + "ESLINT_TEST", devDependenciesForRuleset.get(ruleSetName), TestProvisioner.mavenCentral(), projectDir(), @@ -100,6 +101,7 @@ void formattingUsingRulesetsFile(String ruleSetName) throws Exception { final String cleanFile = filedir + "typescript.clean"; final FormatterStep formatterStep = EslintFormatterStep.create( + "ESLINT_TEST", devDependenciesForRuleset.get(ruleSetName), TestProvisioner.mavenCentral(), projectDir(), @@ -157,6 +159,7 @@ void formattingUsingInlineXoConfig() throws Exception { final String cleanFile = filedir + "typescript.clean"; final FormatterStep formatterStep = EslintFormatterStep.create( + "ESLINT_TEST", EslintStyleGuide.TS_XO_TYPESCRIPT.mergedWith(EslintFormatterStep.defaultDevDependenciesForTypescript()), TestProvisioner.mavenCentral(), projectDir(), diff --git a/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.java b/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.java index 54ce09e7e8..915d757d33 100644 --- a/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.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. @@ -63,6 +63,7 @@ private void runTestUsingPrettier(String fileType, Map dependenc final String cleanFile = filedir + fileType + ".clean"; final FormatterStep formatterStep = PrettierFormatterStep.create( + "PRETTIER_TEST", dependencies, TestProvisioner.mavenCentral(), projectDir(), @@ -90,6 +91,7 @@ void parserInferenceBasedOnExplicitFilepathIsWorking(String prettierVersion) thr final String cleanFile = filedir + "json.clean"; final FormatterStep formatterStep = PrettierFormatterStep.create( + "PRETTIER_TEST", ImmutableMap.of("prettier", prettierVersion), TestProvisioner.mavenCentral(), projectDir(), @@ -112,6 +114,7 @@ void parserInferenceBasedOnFilenameIsWorking(String prettierVersion) throws Exce final String cleanFile = filedir + "clean.json"; final FormatterStep formatterStep = PrettierFormatterStep.create( + "PRETTIER_TEST", ImmutableMap.of("prettier", prettierVersion), TestProvisioner.mavenCentral(), projectDir(), @@ -128,6 +131,7 @@ void parserInferenceBasedOnFilenameIsWorking(String prettierVersion) throws Exce @Test void verifyPrettierErrorMessageIsRelayed() throws Exception { FormatterStep formatterStep = PrettierFormatterStep.create( + "PRETTIER_TEST", PrettierFormatterStep.defaultDevDependenciesWithPrettier("2.8.8"), TestProvisioner.mavenCentral(), projectDir(), @@ -137,7 +141,7 @@ void verifyPrettierErrorMessageIsRelayed() throws Exception { new PrettierConfig(null, ImmutableMap.of("parser", "postcss"))); try (StepHarnessWithFile stepHarness = StepHarnessWithFile.forStep(this, formatterStep)) { stepHarness.expectLintsOfResource("npm/prettier/filetypes/scss/scss.dirty") - .toBe("LINE_UNDEFINED prettier-format(com.diffplug.spotless.npm.SimpleRestClient$SimpleRestResponseException) Unexpected response status code at /prettier/format [HTTP 500] -- (Error while formatting: Error: Couldn't resolve parser \"postcss\") (...)"); + .toBe("LINE_UNDEFINED PRETTIER_TEST-prettier-format(com.diffplug.spotless.npm.SimpleRestClient$SimpleRestResponseException) Unexpected response status code at /prettier/format [HTTP 500] -- (Error while formatting: Error: Couldn't resolve parser \"postcss\") (...)"); } } } @@ -154,6 +158,7 @@ void runFormatTest(String prettierVersion, PrettierConfig config, String cleanFi final String cleanFile = FILEDIR + "typescript." + cleanFileNameSuffix + ".clean"; final FormatterStep formatterStep = PrettierFormatterStep.create( + "PRETTIER_TEST", ImmutableMap.of("prettier", prettierVersion), TestProvisioner.mavenCentral(), projectDir(), @@ -210,6 +215,7 @@ protected void setupTest(API api) { @Override protected FormatterStep create() { return PrettierFormatterStep.create( + "PRETTIER_TEST", ImmutableMap.of("prettier", prettierVersion), TestProvisioner.mavenCentral(), projectDir(), From 4589ca9dcd1d56792296dd6794dd76db59fcd735 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 7 Apr 2025 20:58:51 +0200 Subject: [PATCH 088/210] docs: add node_modules separation to CHANGELOG --- CHANGES.md | 1 + plugin-gradle/CHANGES.md | 1 + plugin-maven/CHANGES.md | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 7d16300cce..8e2b6ac202 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) +* **BREAKING** Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same, to prevent race conditions when running in parallel. For this, the API of npm-based formatter steps has been changed. ([#TODO](https://github.com/diffplug/spotless/pull/TODO)) ## [3.1.0] - 2025-02-20 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 5d2cb19742..733d5cf3dc 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -7,6 +7,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) * Apply Gradle's strict plugin types validation to the Spotless plugin. ([#2454](https://github.com/diffplug/spotless/pull/2454)) +* Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same to prevent race conditions when running in parallel. ([#TODO](https://github.com/diffplug/spotless/pull/TODO)) ## [7.0.2] - 2025-01-14 ### Fixed diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 483258c36a..f46eebf703 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -6,6 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) +* Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same to prevent race conditions when running in parallel. ([#TODO](https://github.com/diffplug/spotless/pull/TODO)) ## [2.44.3] - 2025-02-20 * Support for `clang-format` ([#2406](https://github.com/diffplug/spotless/pull/2406)) From 215793d2709c546e76f985fd4987506bb9410006 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 7 Apr 2025 22:33:34 +0200 Subject: [PATCH 089/210] docs: apply correct pr number Refs: #2462 --- CHANGES.md | 2 +- plugin-gradle/CHANGES.md | 2 +- plugin-maven/CHANGES.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 8e2b6ac202..fe1e97c286 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,7 +13,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) -* **BREAKING** Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same, to prevent race conditions when running in parallel. For this, the API of npm-based formatter steps has been changed. ([#TODO](https://github.com/diffplug/spotless/pull/TODO)) +* **BREAKING** Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same, to prevent race conditions when running in parallel. For this, the API of npm-based formatter steps has been changed. ([#2462](https://github.com/diffplug/spotless/pull/2462)) ## [3.1.0] - 2025-02-20 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 733d5cf3dc..c402a1b09b 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -7,7 +7,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) * Apply Gradle's strict plugin types validation to the Spotless plugin. ([#2454](https://github.com/diffplug/spotless/pull/2454)) -* Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same to prevent race conditions when running in parallel. ([#TODO](https://github.com/diffplug/spotless/pull/TODO)) +* Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same to prevent race conditions when running in parallel. ([#2462](https://github.com/diffplug/spotless/pull/2462)) ## [7.0.2] - 2025-01-14 ### Fixed diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index f46eebf703..f9ea744bae 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -6,7 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) -* Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same to prevent race conditions when running in parallel. ([#TODO](https://github.com/diffplug/spotless/pull/TODO)) +* Assert that each npm-based step uses its own `node_modules` directory, even when configured exactly the same to prevent race conditions when running in parallel. ([#2462](https://github.com/diffplug/spotless/pull/2462)) ## [2.44.3] - 2025-02-20 * Support for `clang-format` ([#2406](https://github.com/diffplug/spotless/pull/2406)) From fe34e9cd07287486b9d544f7c18e11299e6cef67 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 7 Apr 2025 22:41:40 +0200 Subject: [PATCH 090/210] chore: add input validation for formatName Refs: #2462 --- .../main/java/com/diffplug/spotless/npm/EslintFormatterStep.java | 1 + .../java/com/diffplug/spotless/npm/PrettierFormatterStep.java | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java b/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java index d32f4e58b9..2f0f016476 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java @@ -69,6 +69,7 @@ public static Map defaultDevDependenciesWithEslint(String versio } public static FormatterStep create(String formatName, Map devDependencies, Provisioner provisioner, File projectDir, File buildDir, File cacheDir, NpmPathResolver npmPathResolver, EslintConfig eslintConfig) { + requireNonNull(formatName); requireNonNull(devDependencies); requireNonNull(provisioner); requireNonNull(projectDir); diff --git a/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java b/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java index 0f81934e24..6a79116435 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java @@ -52,6 +52,7 @@ public static final Map defaultDevDependenciesWithPrettier(Strin } public static FormatterStep create(String formatName, Map devDependencies, Provisioner provisioner, File projectDir, File buildDir, File cacheDir, NpmPathResolver npmPathResolver, PrettierConfig prettierConfig) { + requireNonNull(formatName); requireNonNull(devDependencies); requireNonNull(provisioner); requireNonNull(buildDir); From 0fa3cabc9ed5780f8d9033b0c1d27d81c1d750c2 Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 7 Apr 2025 22:46:21 +0000 Subject: [PATCH 091/210] Published lib/3.1.1 --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 7d16300cce..0a043ffa24 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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] + +## [3.1.1] - 2025-04-07 ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) From 1b1a4fbbb446585627f9da03eab5986d73afa457 Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 7 Apr 2025 22:47:49 +0000 Subject: [PATCH 092/210] Published gradle/7.0.3 --- plugin-gradle/CHANGES.md | 2 ++ plugin-gradle/README.md | 62 ++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 5d2cb19742..1ddd31cc52 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] + +## [7.0.3] - 2025-04-07 ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index ef7b6be888..da51e31244 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -14,9 +14,9 @@ output = [ ].join('\n'); --> [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.0.2-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.0.3-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -128,10 +128,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -173,7 +173,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -373,8 +373,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -433,8 +433,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle @@ -533,7 +533,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -565,7 +565,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -601,7 +601,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -637,7 +637,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -669,7 +669,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -690,7 +690,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -709,7 +709,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -734,7 +734,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -772,7 +772,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -821,7 +821,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -915,7 +915,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -978,7 +978,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1098,7 +1098,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1130,7 +1130,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1166,7 +1166,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1195,7 +1195,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1596,7 +1596,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1682,9 +1682,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1717,11 +1717,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.2/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From 0ca99e5315d8fe4ff599e61fa1673e4f10354d53 Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 7 Apr 2025 22:49:46 +0000 Subject: [PATCH 093/210] Published maven/2.44.4 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 483258c36a..abf33d63fb 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.44.4] - 2025-04-07 ### Changed * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 6c2b4b0491..c1a346926b 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.44.3-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.3/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.44.4-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.4/index.html) [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.0.3-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.0.4-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -128,10 +128,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -173,7 +173,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -373,8 +373,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -433,8 +433,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle @@ -533,7 +533,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -565,7 +565,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -601,7 +601,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -637,7 +637,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -669,7 +669,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -690,7 +690,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -709,7 +709,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -734,7 +734,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -772,7 +772,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -821,7 +821,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -915,7 +915,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -978,7 +978,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1098,7 +1098,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1130,7 +1130,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1166,7 +1166,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1195,7 +1195,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1596,7 +1596,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1682,9 +1682,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1717,11 +1717,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.3/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From a76bd6e6c81717b8ab9d55ec4b6d470f24001ac6 Mon Sep 17 00:00:00 2001 From: runner Date: Tue, 27 May 2025 22:00:56 +0000 Subject: [PATCH 123/210] Published maven/2.44.5 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 4dd01135b2..d09ac6144f 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.44.5] - 2025-05-27 ### Changed * Bump default `eclipse` version to latest `4.34` -> `4.35`. ([#2458](https://github.com/diffplug/spotless/pull/2458)) * Bump default `greclipse` version to latest `4.32` -> `4.35`. ([#2458](https://github.com/diffplug/spotless/pull/2458)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index c1a346926b..cafb11ea43 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.44.4-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.4/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.44.5-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.5/index.html) + @@ -228,6 +229,12 @@ any other maven phase (i.e. compile) then it can be configured as below; ``` +### removeWildcardImports + +```xml + +``` + ### google-java-format [homepage](https://github.com/google/google-java-format). [changelog](https://github.com/google/google-java-format/releases). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/GoogleJavaFormat.java). diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java index b0692446b7..9fdb794eb1 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -76,6 +76,10 @@ public void addRemoveUnusedImports(RemoveUnusedImports removeUnusedImports) { addStepFactory(removeUnusedImports); } + public void addRemoveWildcardImports(RemoveWildcardImports removeWildcardImports) { + addStepFactory(removeWildcardImports); + } + public void addFormatAnnotations(FormatAnnotations formatAnnotations) { addStepFactory(formatAnnotations); } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/RemoveWildcardImports.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/RemoveWildcardImports.java new file mode 100644 index 0000000000..8620088a08 --- /dev/null +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/RemoveWildcardImports.java @@ -0,0 +1,28 @@ +/* + * 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.maven.java; + +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.java.RemoveWildcardImportsStep; +import com.diffplug.spotless.maven.FormatterStepConfig; +import com.diffplug.spotless.maven.FormatterStepFactory; + +public class RemoveWildcardImports implements FormatterStepFactory { + @Override + public FormatterStep newFormatterStep(FormatterStepConfig config) { + return RemoveWildcardImportsStep.create(); + } +} diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveWildcardImportsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveWildcardImportsStepTest.java new file mode 100644 index 0000000000..4d4ade94d0 --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveWildcardImportsStepTest.java @@ -0,0 +1,33 @@ +/* + * 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.maven.java; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.maven.MavenIntegrationHarness; + +class RemoveWildcardImportsStepTest extends MavenIntegrationHarness { + + @Test + void testRemoveWildcardImports() throws Exception { + writePomWithJavaSteps(""); + + String path = "src/main/java/test.java"; + setFile(path).toResource("java/removewildcardimports/JavaCodeWildcardsUnformatted.test"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile(path).sameAsResource("java/removewildcardimports/JavaCodeWildcardsFormatted.test"); + } +} diff --git a/testlib/src/main/resources/java/removewildcardimports/JavaCodeWildcardsFormatted.test b/testlib/src/main/resources/java/removewildcardimports/JavaCodeWildcardsFormatted.test new file mode 100644 index 0000000000..85ee903fc5 --- /dev/null +++ b/testlib/src/main/resources/java/removewildcardimports/JavaCodeWildcardsFormatted.test @@ -0,0 +1,4 @@ +import java.util.List; +import mylib.Helper; + +public class Test {} \ No newline at end of file diff --git a/testlib/src/main/resources/java/removewildcardimports/JavaCodeWildcardsUnformatted.test b/testlib/src/main/resources/java/removewildcardimports/JavaCodeWildcardsUnformatted.test new file mode 100644 index 0000000000..74646094ae --- /dev/null +++ b/testlib/src/main/resources/java/removewildcardimports/JavaCodeWildcardsUnformatted.test @@ -0,0 +1,9 @@ +import java.util.*; +import static java.util.Collections.*; +import java.util.List; +import mylib.Helper; +import io.quarkus.maven.dependency.*; +import static io.quarkus.vertx.web.Route.HttpMethod.*; +import static org.springframework.web.reactive.function.BodyInserters.*; + +public class Test {} \ No newline at end of file From a7532e08ffd4f9aa86912a34d49709d576e687bd Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 11:59:58 +0200 Subject: [PATCH 134/210] Add project icon for IntelliJ IDEA --- .gitignore | 1 + .idea/icon.png | Bin 0 -> 1639 bytes 2 files changed, 1 insertion(+) create mode 100644 .idea/icon.png diff --git a/.gitignore b/.gitignore index ab04bc7021..2f8c81aca6 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ local.properties ## Directory-based project format: .idea/ +!.idea/icon.png # if you remove the above rule, at least ignore the following: # User-specific stuff: diff --git a/.idea/icon.png b/.idea/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2e97f5f723ea389e304eaaba5021b3304364823a GIT binary patch literal 1639 zcmV-t2AKJYP)grn?Hf)%zs;XL4 zi2ET(2t^x!Dbkgpwop=1@?%Fw$G-9L@uGOUD``~x7@#O>3fNi$RjUGzCIny+V7&n5 z0Conz1i(6p7VnN7J3i^}?|(z9)%Pq55EZ;hv&hoTq zl=o~o*7bnu0|Ww0rPXRZk`9Gh+!ak431Gg9WW^{b2|Ci33m^}m@&WuGz*>NkFcZ7w zae#UaPUoTKo}L~{V`Jl0IgW4KxbdDwqmdZIs_iw%+b_Pu_cDN4Iot_Q0hAF??F7^> zNIx?$K+p=Xld@UI#>TWpqtP#BQ-y(ii6`v`ns+t7-__OirtpFQq)!7N-|zPqjE|2$ z=5o1ePo6y4a{G4A(_l^kg}ne(DCW=U1eod6o(D&O(B;@qX#sgbv40ec($dnf$z%$o zFyV`yG&D5a05H3IK_o<+JODq7Td`nfDG1vJ|%#s4~gJL2o{i08! z(Xe*Ay?@=hb$=c_c<>7>eodp`d6{>|JxJn$FC@4s&O+Q92=HMP-&Pn$eT~F5tMGkmuMq@rw*qOKu1C-))x4tfB=Hl*4ASP{|y8#3;6{$gFtSiCHAX? z0>mMtW_aa^P)I;?bMrUt?d|jMUMj@eO%E?b=@&h~!hK;M?*M;b+(LIn7U)P868Wo) zfHiB@1Zrz*zn_?z+|GqXymJI|SAgl$viX+CLQ$V7k&TtYY&Kt;n6PaJ?FMqR5Ev*Z z;0~Rgoo`fCRozR*QC3#AkXk@I6bd1N>gwt#?u5AmgulU-o5)$DlQox zvIrCupwsDY@n`ped>wxprPpb=gWK({0+6PF#5ceyD?qE&Mn>s_I9n8NCzlVU+1c4b zIb2x@A%nr-=T7K=v@M#(%*>2d4wr-gCgUN*&oznlpmg1(Rv}VTrG#`Em3k_ffI1{$ zivnm)NUkgjQBQ0TC)6OyzJVO>-@K4?-4*7(wthK8Ss4Q^mx~V%4TFatvp9q}0X{ig zNydP()o3DoJ|CYu3s~{P3Nf5*lgacz4p)*lATh8M6ySEd*K#MTS#jNUC-&ffm&28O zK9C3n1x!y*^UEk?${fu?QF`w@cQ}9kyv5;g)FtES?(RNRUS7_m9s?OzymmMoPe4Nh z|6|A;QFw8lkDQ^Qp?ynnbaZrlC@p}_YzTQg9+ku4sK+L)INK34Xn?0`q)TanQ?tOR zC-(D^htSB#h>29y*pe@8Cy$JcM91T77YO~3&O#YXqi4>Xc?sl0YtBjj!Hh5CMgFCl zk;PY|F`p?#1dNW3Ru2viw!xAMlrI8o{C0uN35P5J8F&MByZxEAwze;WMZwj0T`RL( zp~OifeF0pFyUO8kl*zD6c(pfg-Yj;xT!wS!&NW`VcySL3K;vDKeHO%b++cz034Kxn z`B$L;@zUaps6n@cOHBa&lHs}(DgkT*@CtwuiR&biUL_w0F#I}WYK)DIX^ci=Xo*$V z1iURy*-4>_6vL#VuK=(r#orI`&L2O1d`nA9i&M5wNmg2=@$7PFmw{^lY(RZ|{pZVd z9$DWX_zA#XKv$%j8WG1du2{4WJ#+hP9K!!^2zkdVSI*l%*g)gp|S+07u9u z1lF%#KYI4;* Date: Tue, 24 Jun 2025 15:06:33 +0200 Subject: [PATCH 135/210] activate formatAnnotations() --- gradle/spotless.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/spotless.gradle b/gradle/spotless.gradle index 677630ac69..1a10f7239d 100644 --- a/gradle/spotless.gradle +++ b/gradle/spotless.gradle @@ -22,7 +22,7 @@ spotless { eclipse().configFile rootProject.file('gradle/spotless.eclipseformat.xml') trimTrailingWhitespace() removeUnusedImports() - // TODO: formatAnnotations() + formatAnnotations() custom 'noInternalDeps', noInternalDepsClosure } } From 39d16538cab0e36323a0bf816b58dcc7f96c3768 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Fri, 9 May 2025 20:37:46 +0200 Subject: [PATCH 136/210] refactor: move `idea` to generic formatters as it can handle various file formats besides java. --- .../spotless/{java => generic}/IdeaStep.java | 4 +- .../gradle/spotless/FormatExtension.java | 40 +++++++++++++++++++ .../gradle/spotless/JavaExtension.java | 40 ------------------- .../gradle/spotless/JavaIdeaTest.java | 2 +- .../spotless/maven/FormatterFactory.java | 7 +++- .../maven/{java => generic}/Idea.java | 6 +-- .../diffplug/spotless/maven/java/Java.java | 4 -- .../maven/{java => generic}/IdeaTest.java | 4 +- .../diffplug/spotless/ResourceHarness.java | 2 +- .../com/diffplug/spotless/tag/IdeaTest.java | 2 +- .../{java => generic}/IdeaStepTest.java | 4 +- 11 files changed, 58 insertions(+), 57 deletions(-) rename lib/src/main/java/com/diffplug/spotless/{java => generic}/IdeaStep.java (98%) rename plugin-maven/src/main/java/com/diffplug/spotless/maven/{java => generic}/Idea.java (90%) rename plugin-maven/src/test/java/com/diffplug/spotless/maven/{java => generic}/IdeaTest.java (93%) rename testlib/src/test/java/com/diffplug/spotless/{java => generic}/IdeaStepTest.java (97%) diff --git a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java similarity index 98% rename from lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java rename to lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java index d069e721fb..60f51d5d42 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/IdeaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 DiffPlug + * Copyright 2024-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.diffplug.spotless.java; +package com.diffplug.spotless.generic; import java.io.File; import java.io.IOException; 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 40069850c5..d60dec3af0 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 @@ -65,6 +65,7 @@ import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep; import com.diffplug.spotless.generic.EndWithNewlineStep; import com.diffplug.spotless.generic.FenceStep; +import com.diffplug.spotless.generic.IdeaStep; import com.diffplug.spotless.generic.IndentStep; import com.diffplug.spotless.generic.LicenseHeaderStep; import com.diffplug.spotless.generic.LicenseHeaderStep.YearMode; @@ -960,6 +961,45 @@ public EclipseWtpConfig eclipseWtp(EclipseWtpFormatterStep type, String version) return new EclipseWtpConfig(type, version); } + public IdeaConfig idea() { + return new IdeaConfig(); + } + + public class IdeaConfig { + private String binaryPath; + private String configPath; + private boolean withDefaults = false; + + IdeaConfig() { + addStep(createStep()); + } + + private FormatterStep createStep() { + return IdeaStep.create(withDefaults, binaryPath, configPath); + } + + public IdeaConfig binaryPath(String binaryPath) { + requireNonNull(binaryPath); + this.binaryPath = binaryPath; + replaceStep(createStep()); + return this; + } + + public IdeaConfig configPath(String configPath) { + requireNonNull(configPath); + this.configPath = configPath; + replaceStep(createStep()); + return this; + } + + public IdeaConfig withDefaults(Boolean withDefaults) { + requireNonNull(withDefaults); + this.withDefaults = withDefaults; + replaceStep(createStep()); + return this; + } + } + /** *
 	 * spotless {
diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java
index 8440fc4d73..f0530fb968 100644
--- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java
+++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java
@@ -38,7 +38,6 @@
 import com.diffplug.spotless.java.CleanthatJavaStep;
 import com.diffplug.spotless.java.FormatAnnotationsStep;
 import com.diffplug.spotless.java.GoogleJavaFormatStep;
-import com.diffplug.spotless.java.IdeaStep;
 import com.diffplug.spotless.java.ImportOrderStep;
 import com.diffplug.spotless.java.PalantirJavaFormatStep;
 import com.diffplug.spotless.java.RemoveUnusedImportsStep;
@@ -358,45 +357,6 @@ public EclipseConfig withP2Mirrors(Map mirrors) {
 
 	}
 
-	public IdeaConfig idea() {
-		return new IdeaConfig();
-	}
-
-	public class IdeaConfig {
-		private String binaryPath;
-		private String configPath;
-		private boolean withDefaults = false;
-
-		IdeaConfig() {
-			addStep(createStep());
-		}
-
-		private FormatterStep createStep() {
-			return IdeaStep.create(withDefaults, binaryPath, configPath);
-		}
-
-		public IdeaConfig binaryPath(String binaryPath) {
-			Objects.requireNonNull(binaryPath);
-			this.binaryPath = binaryPath;
-			replaceStep(createStep());
-			return this;
-		}
-
-		public IdeaConfig configPath(String configPath) {
-			Objects.requireNonNull(configPath);
-			this.configPath = configPath;
-			replaceStep(createStep());
-			return this;
-		}
-
-		public IdeaConfig withDefaults(Boolean withDefaults) {
-			Objects.requireNonNull(withDefaults);
-			this.withDefaults = withDefaults;
-			replaceStep(createStep());
-			return this;
-		}
-	}
-
 	/** Removes newlines between type annotations and types. */
 	public FormatAnnotationsConfig formatAnnotations() {
 		return new FormatAnnotationsConfig();
diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java
index b154c2d851..bea9272236 100644
--- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java
+++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/JavaIdeaTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2024 DiffPlug
+ * Copyright 2020-2025 DiffPlug
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java
index 456c31b9a3..143bd56e69 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.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.
@@ -38,6 +38,7 @@
 import com.diffplug.spotless.LineEnding;
 import com.diffplug.spotless.maven.generic.EclipseWtp;
 import com.diffplug.spotless.maven.generic.EndWithNewline;
+import com.diffplug.spotless.maven.generic.Idea;
 import com.diffplug.spotless.maven.generic.Indent;
 import com.diffplug.spotless.maven.generic.Jsr223;
 import com.diffplug.spotless.maven.generic.LicenseHeader;
@@ -147,6 +148,10 @@ public final void addPrettier(Prettier prettier) {
 		addStepFactory(prettier);
 	}
 
+	public final void addIdea(Idea idea) {
+		addStepFactory(idea);
+	}
+
 	public final void addToggleOffOn(ToggleOffOn toggle) {
 		this.toggle = toggle;
 	}
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
similarity index 90%
rename from plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java
rename to plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
index 8981a9dc9b..c908fe77c9 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Idea.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.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.
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.diffplug.spotless.maven.java;
+package com.diffplug.spotless.maven.generic;
 
 import org.apache.maven.plugins.annotations.Parameter;
 
 import com.diffplug.spotless.FormatterStep;
-import com.diffplug.spotless.java.IdeaStep;
+import com.diffplug.spotless.generic.IdeaStep;
 import com.diffplug.spotless.maven.FormatterStepConfig;
 import com.diffplug.spotless.maven.FormatterStepFactory;
 
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java
index dc5de3df25..9fdb794eb1 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java
@@ -68,10 +68,6 @@ public void addImportOrder(ImportOrder importOrder) {
 		addStepFactory(importOrder);
 	}
 
-	public void addIdea(Idea idea) {
-		addStepFactory(idea);
-	}
-
 	public void addPalantirJavaFormat(PalantirJavaFormat palantirJavaFormat) {
 		addStepFactory(palantirJavaFormat);
 	}
diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/generic/IdeaTest.java
similarity index 93%
rename from plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java
rename to plugin-maven/src/test/java/com/diffplug/spotless/maven/generic/IdeaTest.java
index c11b2a64d1..c368213437 100644
--- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/IdeaTest.java
+++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/generic/IdeaTest.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.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.diffplug.spotless.maven.java;
+package com.diffplug.spotless.maven.generic;
 
 import org.junit.jupiter.api.Test;
 
diff --git a/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java b/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java
index 0bac44952f..caf668ae8d 100644
--- a/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java
+++ b/testlib/src/main/java/com/diffplug/spotless/ResourceHarness.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.
diff --git a/testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java b/testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java
index 79813d91d9..c9f351cdcb 100644
--- a/testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java
+++ b/testlib/src/main/java/com/diffplug/spotless/tag/IdeaTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021-2024 DiffPlug
+ * Copyright 2021-2025 DiffPlug
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
similarity index 97%
rename from testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java
rename to testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
index 98de28627a..d365782db1 100644
--- a/testlib/src/test/java/com/diffplug/spotless/java/IdeaStepTest.java
+++ b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 DiffPlug
+ * Copyright 2024-2025 DiffPlug
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.diffplug.spotless.java;
+package com.diffplug.spotless.generic;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;

From 599ad51622d0223dbbda8f013e38959ae656f6be Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Mon, 12 May 2025 21:06:26 +0200
Subject: [PATCH 137/210] refactor: use builder for idea-step creation

---
 .../diffplug/spotless/generic/IdeaStep.java   | 99 ++++++++++++++-----
 .../gradle/spotless/FormatExtension.java      | 14 +--
 .../diffplug/spotless/maven/generic/Idea.java |  6 +-
 .../spotless/generic/IdeaStepTest.java        | 12 +--
 4 files changed, 92 insertions(+), 39 deletions(-)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index 60f51d5d42..775660257f 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -21,12 +21,14 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.slf4j.Logger;
@@ -40,51 +42,70 @@
 
 public final class IdeaStep {
 
+	public static final String NAME = "IDEA";
+
 	private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class);
 
 	private IdeaStep() {}
 
-	public static FormatterStep create() {
-		return create(true);
+	public static IdeaStepBuilder create() {
+		return new IdeaStepBuilder();
 	}
 
-	public static FormatterStep create(boolean withDefaults) {
-		return create(withDefaults, null);
+	private static FormatterStep create(@Nonnull IdeaStepBuilder builder) {
+		Objects.requireNonNull(builder);
+		return FormatterStep.createLazy(NAME,
+				() -> createState(builder),
+				state -> state);
 	}
 
-	public static FormatterStep create(boolean withDefaults,
-			@Nullable String binaryPath) {
-		return create(withDefaults, binaryPath, null);
+	private static State createState(@Nonnull IdeaStepBuilder builder) {
+		return new State(Objects.requireNonNull(builder));
 	}
 
-	public static FormatterStep create(boolean withDefaults,
-			@Nullable String binaryPath, @Nullable String codeStyleSettingsPath) {
-		return FormatterStep.createLazy("IDEA",
-				() -> createState(withDefaults, binaryPath, codeStyleSettingsPath),
-				state -> state);
-	}
+	public static final class IdeaStepBuilder {
+		private static final String DEFAULT_IDEA = "idea";
+
+		private boolean useDefaults = true;
+		@Nonnull
+		private String binaryPath = DEFAULT_IDEA;
+		@Nullable
+		private String codeStyleSettingsPath;
+
+		public IdeaStepBuilder setUseDefaults(boolean useDefaults) {
+			this.useDefaults = useDefaults;
+			return this;
+		}
+
+		public IdeaStepBuilder setBinaryPath(@Nonnull String binaryPath) {
+			this.binaryPath = Objects.requireNonNull(binaryPath);
+			return this;
+		}
+
+		public IdeaStepBuilder setCodeStyleSettingsPath(@Nullable String codeStyleSettingsPath) {
+			this.codeStyleSettingsPath = codeStyleSettingsPath;
+			return this;
+		}
 
-	private static State createState(boolean withDefaults,
-			@Nullable String binaryPath, @Nullable String codeStyleSettingsPath) {
-		return new State(withDefaults, binaryPath, codeStyleSettingsPath);
+		public FormatterStep build() {
+			return create(this);
+		}
 	}
 
 	private static class State
 			implements FormatterFunc.NeedsFile, Serializable {
 
 		private static final long serialVersionUID = -1825662355363926318L;
-		private static final String DEFAULT_IDEA = "idea";
 
 		private String binaryPath;
 		@Nullable
 		private String codeStyleSettingsPath;
 		private boolean withDefaults;
 
-		private State(boolean withDefaults, @Nullable String binaryPath,
-				@Nullable String codeStyleSettingsPath) {
-			this.withDefaults = withDefaults;
-			this.codeStyleSettingsPath = codeStyleSettingsPath;
-			this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA);
+		private State(@Nonnull IdeaStepBuilder builder) {
+			this.withDefaults = builder.useDefaults;
+			this.codeStyleSettingsPath = builder.codeStyleSettingsPath;
+			this.binaryPath = builder.binaryPath;
 			resolveFullBinaryPathAndCheckVersion();
 		}
 
@@ -113,10 +134,38 @@ private String pathToExe() {
 			if (binaryPath == null) {
 				throw new IllegalStateException("binaryPath is not set");
 			}
-			if (new File(binaryPath).exists()) {
-				return binaryPath;
+			return macOsFix(binaryPath);
+		}
+
+		@CheckForNull
+		private static String macOsFix(String binaryPath) {
+			if (!isMacOs()) {
+				if (new File(binaryPath).exists()) {
+					return binaryPath;
+				}
+				return null; // search in PATH
+			}
+			// on macOS, the binary is located in the .app bundle which might be invisible to the user
+			// we try need to append the path to the binary
+			File binary = new File(binaryPath);
+			if (!binary.exists()) {
+				// maybe it is bundle path without .app? (might be hidden by os)
+				binary = new File(binaryPath + ".app");
+				if (!binary.exists()) {
+					return binaryPath; // fallback: do nothing
+				}
+			}
+			if (binaryPath.endsWith(".app") || binary.isDirectory()) {
+				binary = new File(binary, "Contents/MacOS/idea");
 			}
-			return null; // search in PATH
+			if (binary.isFile() && binary.canExecute()) {
+				return binary.getPath();
+			}
+			return binaryPath; // fallback: do nothing
+		}
+
+		private static boolean isMacOs() {
+			return System.getProperty("os.name").toLowerCase().contains("mac");
 		}
 
 		@Override
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 d60dec3af0..ab93e53881 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
@@ -966,35 +966,35 @@ public IdeaConfig idea() {
 	}
 
 	public class IdeaConfig {
-		private String binaryPath;
-		private String configPath;
-		private boolean withDefaults = false;
+		private final IdeaStep.IdeaStepBuilder builder;
 
 		IdeaConfig() {
+			this.builder = IdeaStep.create();
 			addStep(createStep());
 		}
 
 		private FormatterStep createStep() {
-			return IdeaStep.create(withDefaults, binaryPath, configPath);
+			return builder.build();
 		}
 
 		public IdeaConfig binaryPath(String binaryPath) {
 			requireNonNull(binaryPath);
-			this.binaryPath = binaryPath;
+			builder.setBinaryPath(binaryPath);
 			replaceStep(createStep());
 			return this;
 		}
 
+		// TODO (simschla, 11.05.2025): rename
 		public IdeaConfig configPath(String configPath) {
 			requireNonNull(configPath);
-			this.configPath = configPath;
+			builder.setCodeStyleSettingsPath(configPath);
 			replaceStep(createStep());
 			return this;
 		}
 
 		public IdeaConfig withDefaults(Boolean withDefaults) {
 			requireNonNull(withDefaults);
-			this.withDefaults = withDefaults;
+			builder.setUseDefaults(withDefaults);
 			replaceStep(createStep());
 			return this;
 		}
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
index c908fe77c9..67a4d5b556 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
@@ -35,6 +35,10 @@ public class Idea implements FormatterStepFactory {
 
 	@Override
 	public FormatterStep newFormatterStep(FormatterStepConfig config) {
-		return IdeaStep.create(withDefaults, binaryPath, configPath);
+		return IdeaStep.create()
+				.setUseDefaults(withDefaults)
+				.setCodeStyleSettingsPath(configPath)
+				.setBinaryPath(binaryPath)
+				.build();
 	}
 }
diff --git a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
index d365782db1..328d9f934e 100644
--- a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
+++ b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
@@ -31,7 +31,7 @@ class IdeaStepTest extends ResourceHarness {
 
 	@Test
 	void name() throws Exception {
-		FormatterStep step = IdeaStep.create(true, "idea");
+		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("idea").build();
 
 		String name = step.getName();
 
@@ -43,7 +43,7 @@ void notFormattings() throws Exception {
 		File cleanFile = newFile("clean.java");
 		String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java");
 		Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(true, "idea");
+		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("/Users/simschla/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea").build();
 
 		var result = step.format(cleanJava, cleanFile);
 
@@ -56,7 +56,7 @@ void formattings() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(true, "idea");
+		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("/Users/simschla/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea").build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -69,7 +69,7 @@ void formattingsWorkWithDefaultParameters() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create();
+		FormatterStep step = IdeaStep.create().build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -82,7 +82,7 @@ void formattingsWithOutDefaultDoesNothing() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(false, "idea");
+		FormatterStep step = IdeaStep.create().setUseDefaults(false).setBinaryPath("idea").build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -95,7 +95,7 @@ void configureFile() throws Exception {
 		File cleanFile = newFile("clean.java");
 		String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java");
 		Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(true, "idea");
+		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("idea").build();
 
 		var result = step.format(cleanJava, cleanFile);
 

From d771a9caa0c0e821504e7cbe52640abdd5011bf7 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Tue, 13 May 2025 17:58:11 +0200
Subject: [PATCH 138/210] chore: provide custom idea.properties with custom
 config/system paths

---
 .../diffplug/spotless/generic/IdeaStep.java   | 96 +++++++++++++++----
 .../gradle/spotless/FormatExtension.java      |  2 +-
 .../diffplug/spotless/maven/generic/Idea.java |  2 +-
 .../spotless/generic/IdeaStepTest.java        | 22 +++--
 4 files changed, 96 insertions(+), 26 deletions(-)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index 775660257f..066e47577f 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -16,13 +16,19 @@
 package com.diffplug.spotless.generic;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.UUID;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -44,12 +50,16 @@ public final class IdeaStep {
 
 	public static final String NAME = "IDEA";
 
+	public static final String IDEA_EXECUTABLE_DEFAULT = "idea";
+
 	private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class);
+	public static final String IDEA_CONFIG_PATH_PROPERTY = "idea.config.path";
+	public static final String IDEA_SYSTEM_PATH_PROPERTY = "idea.system.path";
 
 	private IdeaStep() {}
 
-	public static IdeaStepBuilder create() {
-		return new IdeaStepBuilder();
+	public static IdeaStepBuilder create(@Nonnull File buildDir) {
+		return new IdeaStepBuilder(Objects.requireNonNull(buildDir));
 	}
 
 	private static FormatterStep create(@Nonnull IdeaStepBuilder builder) {
@@ -64,13 +74,20 @@ private static State createState(@Nonnull IdeaStepBuilder builder) {
 	}
 
 	public static final class IdeaStepBuilder {
-		private static final String DEFAULT_IDEA = "idea";
 
 		private boolean useDefaults = true;
 		@Nonnull
-		private String binaryPath = DEFAULT_IDEA;
+		private String binaryPath = IDEA_EXECUTABLE_DEFAULT;
 		@Nullable
 		private String codeStyleSettingsPath;
+		private final Map ideaProperties = new HashMap<>();
+
+		@Nonnull
+		private final File buildDir;
+
+		private IdeaStepBuilder(@Nonnull File buildDir) {
+			this.buildDir = Objects.requireNonNull(buildDir);
+		}
 
 		public IdeaStepBuilder setUseDefaults(boolean useDefaults) {
 			this.useDefaults = useDefaults;
@@ -87,6 +104,14 @@ public IdeaStepBuilder setCodeStyleSettingsPath(@Nullable String codeStyleSettin
 			return this;
 		}
 
+		public IdeaStepBuilder setIdeaProperties(@Nonnull Map ideaProperties) {
+			if (ideaProperties.containsKey(IDEA_CONFIG_PATH_PROPERTY) || ideaProperties.containsKey(IDEA_SYSTEM_PATH_PROPERTY)) {
+				throw new IllegalArgumentException("Cannot override IDEA config or system path");
+			}
+			this.ideaProperties.putAll(ideaProperties);
+			return this;
+		}
+
 		public FormatterStep build() {
 			return create(this);
 		}
@@ -97,22 +122,27 @@ private static class State
 
 		private static final long serialVersionUID = -1825662355363926318L;
 
-		private String binaryPath;
+		private final String buildDir;
+		private final String uniquePath;
+		private final String binaryPath;
 		@Nullable
-		private String codeStyleSettingsPath;
-		private boolean withDefaults;
+		private final String codeStyleSettingsPath; // TODO make sure to save content in state
+		private final boolean withDefaults;
+		private final TreeMap ideaProperties;
 
 		private State(@Nonnull IdeaStepBuilder builder) {
+			this.buildDir = ThrowingEx.get(builder.buildDir::getCanonicalPath);
+			this.uniquePath = UUID.randomUUID().toString();
 			this.withDefaults = builder.useDefaults;
 			this.codeStyleSettingsPath = builder.codeStyleSettingsPath;
-			this.binaryPath = builder.binaryPath;
-			resolveFullBinaryPathAndCheckVersion();
+			this.ideaProperties = new TreeMap<>(builder.ideaProperties);
+			this.binaryPath = resolveFullBinaryPathAndCheckVersion(builder.binaryPath);
 		}
 
-		private void resolveFullBinaryPathAndCheckVersion() {
+		private static String resolveFullBinaryPathAndCheckVersion(String binaryPath) {
 			var exe = ForeignExe
-					.nameAndVersion(this.binaryPath, "IntelliJ IDEA")
-					.pathToExe(pathToExe())
+					.nameAndVersion(binaryPath, "IntelliJ IDEA")
+					.pathToExe(pathToExe(binaryPath))
 					.versionRegex(Pattern.compile("(IntelliJ IDEA) .*"))
 					.fixCantFind(
 							"IDEA executable cannot be found on your machine, "
@@ -120,7 +150,7 @@ private void resolveFullBinaryPathAndCheckVersion() {
 					.fixWrongVersion("Provided binary is not IDEA, "
 							+ "please check it and fix the problem; or report the problem");
 			try {
-				this.binaryPath = exe.confirmVersionAndGetAbsolutePath();
+				return exe.confirmVersionAndGetAbsolutePath();
 			} catch (IOException e) {
 				throw new IllegalArgumentException("binary cannot be found", e);
 			} catch (InterruptedException e) {
@@ -130,10 +160,7 @@ private void resolveFullBinaryPathAndCheckVersion() {
 		}
 
 		@CheckForNull
-		private String pathToExe() {
-			if (binaryPath == null) {
-				throw new IllegalStateException("binaryPath is not set");
-			}
+		private static String pathToExe(String binaryPath) {
 			return macOsFix(binaryPath);
 		}
 
@@ -177,7 +204,8 @@ public String applyWithFile(String unix, File file) throws Exception {
 				List params = getParams(tempFile);
 
 				try (ProcessRunner runner = new ProcessRunner()) {
-					var result = runner.exec(params);
+					Map env = createEnv();
+					var result = runner.exec(null, env, null, params);
 					LOGGER.debug("command finished with stdout: {}",
 							result.assertExitZero(StandardCharsets.UTF_8));
 
@@ -188,6 +216,38 @@ public String applyWithFile(String unix, File file) throws Exception {
 			}
 		}
 
+		private Map createEnv() {
+			File ideaProps = createIdeaPropertiesFile();
+			Map env = Map.ofEntries(
+					Map.entry("IDEA_PROPERTIES", ThrowingEx.get(ideaProps::getCanonicalPath)));
+			return env;
+		}
+
+		private File createIdeaPropertiesFile() {
+			Path ideaProps = new File(buildDir).toPath().resolve(uniquePath).resolve("idea.properties");
+
+			if (Files.exists(ideaProps)) {
+				return ideaProps.toFile(); // only create if it does not exist
+			}
+
+			ThrowingEx.run(() -> Files.createDirectories(ideaProps.getParent()));
+
+			Path configPath = ideaProps.getParent().resolve("config");
+			Path systemPath = ideaProps.getParent().resolve("system");
+
+			Properties properties = new Properties();
+			properties.putAll(ideaProperties);
+			properties.put(IDEA_CONFIG_PATH_PROPERTY, ThrowingEx.get(configPath.toFile()::getCanonicalPath));
+			properties.put(IDEA_SYSTEM_PATH_PROPERTY, ThrowingEx.get(systemPath.toFile()::getCanonicalPath));
+
+			try (FileOutputStream out = new FileOutputStream(ideaProps.toFile())) {
+				properties.store(out, "Generated by spotless");
+			} catch (IOException e) {
+				throw new IllegalStateException("Failed to create IDEA properties file", e);
+			}
+			return ideaProps.toFile();
+		}
+
 		private List getParams(File file) {
 			/* https://www.jetbrains.com/help/idea/command-line-formatter.html */
 			var builder = Stream. builder();
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 ab93e53881..b1f8cb9d6b 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
@@ -969,7 +969,7 @@ public class IdeaConfig {
 		private final IdeaStep.IdeaStepBuilder builder;
 
 		IdeaConfig() {
-			this.builder = IdeaStep.create();
+			this.builder = IdeaStep.create(getProject().getLayout().getBuildDirectory().getAsFile().get());
 			addStep(createStep());
 		}
 
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
index 67a4d5b556..ab9de41a08 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
@@ -35,7 +35,7 @@ public class Idea implements FormatterStepFactory {
 
 	@Override
 	public FormatterStep newFormatterStep(FormatterStepConfig config) {
-		return IdeaStep.create()
+		return IdeaStep.create(config.getFileLocator().getBuildDir())
 				.setUseDefaults(withDefaults)
 				.setCodeStyleSettingsPath(configPath)
 				.setBinaryPath(binaryPath)
diff --git a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
index 328d9f934e..05b643805e 100644
--- a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
+++ b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
@@ -24,6 +24,7 @@
 import com.diffplug.common.io.Files;
 import com.diffplug.spotless.FormatterStep;
 import com.diffplug.spotless.ResourceHarness;
+import com.diffplug.spotless.ThrowingEx;
 import com.diffplug.spotless.tag.IdeaTest;
 
 @IdeaTest
@@ -31,7 +32,7 @@ class IdeaStepTest extends ResourceHarness {
 
 	@Test
 	void name() throws Exception {
-		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("idea").build();
+		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
 
 		String name = step.getName();
 
@@ -43,7 +44,7 @@ void notFormattings() throws Exception {
 		File cleanFile = newFile("clean.java");
 		String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java");
 		Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("/Users/simschla/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea").build();
+		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
 
 		var result = step.format(cleanJava, cleanFile);
 
@@ -56,7 +57,7 @@ void formattings() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("/Users/simschla/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea").build();
+		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -69,7 +70,7 @@ void formattingsWorkWithDefaultParameters() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create().build();
+		FormatterStep step = IdeaStep.create(buildDir()).build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -82,7 +83,7 @@ void formattingsWithOutDefaultDoesNothing() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create().setUseDefaults(false).setBinaryPath("idea").build();
+		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(false).build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -95,11 +96,20 @@ void configureFile() throws Exception {
 		File cleanFile = newFile("clean.java");
 		String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java");
 		Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create().setUseDefaults(true).setBinaryPath("idea").build();
+		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
 
 		var result = step.format(cleanJava, cleanFile);
 
 		Assertions.assertEquals(cleanJava, result,
 				"formatting was applied to clean file");
 	}
+
+	private File buildDir = null;
+
+	protected File buildDir() {
+		if (this.buildDir == null) {
+			this.buildDir = ThrowingEx.get(() -> newFolder("build-dir"));
+		}
+		return this.buildDir;
+	}
 }

From 619051c723ff4428251496ccf22b828a0f203014 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Tue, 13 May 2025 20:18:22 +0200
Subject: [PATCH 139/210] chore: fix formatter to use UTF-8 (as asserted by
 spotless)

---
 lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index 066e47577f..7c76bb8aa1 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -260,6 +260,7 @@ private List getParams(File file) {
 				builder.add("-s");
 				builder.add(codeStyleSettingsPath);
 			}
+			builder.add("-charset").add("UTF-8");
 			builder.add(ThrowingEx.get(file::getCanonicalPath));
 			return builder.build().collect(Collectors.toList());
 		}

From 0570c6af0575664bac88951418ac6c4aff3c0bdc Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Tue, 13 May 2025 21:08:39 +0200
Subject: [PATCH 140/210] feat: allow specifying idea execs not on path

---
 .gitignore                                    |  1 +
 gradle/special-tests.gradle                   |  4 +
 .../diffplug/spotless/generic/IdeaStep.java   | 19 ++--
 .../spotless/generic/TestEnvVars.java         | 93 +++++++++++++++++++
 4 files changed, 110 insertions(+), 7 deletions(-)
 create mode 100644 lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java

diff --git a/.gitignore b/.gitignore
index 2f8c81aca6..28ce16fa21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
 # Project-specific stuff
 userHome/
 workspace/
+testenv.properties
 
 ### Gradle ###
 .gradle
diff --git a/gradle/special-tests.gradle b/gradle/special-tests.gradle
index 29295b19ec..1931043e42 100644
--- a/gradle/special-tests.gradle
+++ b/gradle/special-tests.gradle
@@ -38,5 +38,9 @@ tasks.named('test').configure {
 special.forEach { tag ->
 	tasks.register("test${tag.capitalize()}", Test) {
 		useJUnitPlatform { includeTags tag }
+		if (rootProject.file('testenv.properties').exists()) {
+			systemProperty 'testenv.properties.path', rootProject.file('testenv.properties').canonicalPath
+		}
 	}
 }
+
diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index 7c76bb8aa1..b758b0e6d4 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -161,17 +161,22 @@ private static String resolveFullBinaryPathAndCheckVersion(String binaryPath) {
 
 		@CheckForNull
 		private static String pathToExe(String binaryPath) {
-			return macOsFix(binaryPath);
+			String testEnvBinaryPath = TestEnvVars.read().get(String.format("%s.%s", IdeaStep.class.getName(), "binaryPath"));
+			if (testEnvBinaryPath != null) {
+				return testEnvBinaryPath;
+			}
+			if (isMacOs()) {
+				return macOsFix(binaryPath);
+			}
+			if (new File(binaryPath).exists()) {
+				return binaryPath;
+			}
+			return null; // search in PATH
 		}
 
 		@CheckForNull
 		private static String macOsFix(String binaryPath) {
-			if (!isMacOs()) {
-				if (new File(binaryPath).exists()) {
-					return binaryPath;
-				}
-				return null; // search in PATH
-			}
+
 			// on macOS, the binary is located in the .app bundle which might be invisible to the user
 			// we try need to append the path to the binary
 			File binary = new File(binaryPath);
diff --git a/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java b/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
new file mode 100644
index 0000000000..c0966c511f
--- /dev/null
+++ b/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
@@ -0,0 +1,93 @@
+/*
+ * 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.generic;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.annotation.Nullable;
+
+class TestEnvVars {
+
+	private final Map envVars;
+
+	private static TestEnvVars INSTANCE;
+
+	private TestEnvVars(Map envVars) {
+		this.envVars = Map.copyOf(envVars);
+	}
+
+	public static synchronized TestEnvVars read() {
+		if (INSTANCE == null) {
+			INSTANCE = new TestEnvVars(readTestEnvVars());
+		}
+		return INSTANCE;
+	}
+
+	private static Map readTestEnvVars() {
+		Map envVars = new HashMap<>();
+		Optional resolvedTestenvProps = candidateTestEnvLocations().filter(Files::exists).findFirst();
+		resolvedTestenvProps.ifPresent(testenvProps -> {
+			try (var reader = Files.newBufferedReader(testenvProps)) {
+				java.util.Properties properties = new java.util.Properties();
+				properties.load(reader);
+				for (String name : properties.stringPropertyNames()) {
+					envVars.put(name, properties.getProperty(name));
+				}
+			} catch (IOException e) {
+				throw new RuntimeException("Failed to read test environment variables", e);
+			}
+		});
+		return envVars;
+	}
+
+	private static Stream candidateTestEnvLocations() {
+		Stream.Builder builder = Stream.builder();
+		if (System.getProperty("testenv.properties.path") != null) {
+			builder.add(Path.of(System.getProperty("testenv.properties.path")));
+		}
+		builder.add(
+				Path.of(System.getProperty("user.dir"), "testenv.properties"));
+		builder.add(
+				Path.of(System.getProperty("user.dir")).getParent().resolve("testenv.properties"));
+		return builder.build();
+	}
+
+	public @Nullable String get(String key) {
+		return envVars.get(key);
+	}
+
+	public String getOrDefault(String key, String defaultValue) {
+		return envVars.getOrDefault(key, defaultValue);
+	}
+
+	public String getOrThrow(String key) {
+		String value = envVars.get(key);
+		if (value == null) {
+			throw new IllegalArgumentException("Environment variable " + key + " not found");
+		}
+		return value;
+	}
+
+	public boolean hasKey(String key) {
+		return envVars.containsKey(key);
+	}
+}

From 1027acacaf7196a8d61beeb49111620ab98ad63c Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Fri, 16 May 2025 20:49:35 +0200
Subject: [PATCH 141/210] refactor: turn ideastep into autoclosable
 implementation

---
 .../diffplug/spotless/generic/IdeaStep.java   | 73 +++++++++++++------
 1 file changed, 51 insertions(+), 22 deletions(-)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index b758b0e6d4..7adbd12762 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -65,8 +65,7 @@ public static IdeaStepBuilder create(@Nonnull File buildDir) {
 	private static FormatterStep create(@Nonnull IdeaStepBuilder builder) {
 		Objects.requireNonNull(builder);
 		return FormatterStep.createLazy(NAME,
-				() -> createState(builder),
-				state -> state);
+				() -> createState(builder), State::toFunc);
 	}
 
 	private static State createState(@Nonnull IdeaStepBuilder builder) {
@@ -117,22 +116,19 @@ public FormatterStep build() {
 		}
 	}
 
-	private static class State
-			implements FormatterFunc.NeedsFile, Serializable {
+	private static class State implements Serializable {
 
-		private static final long serialVersionUID = -1825662355363926318L;
+		private static final long serialVersionUID = -1426311255869303398L;
 
-		private final String buildDir;
-		private final String uniquePath;
+		private final File uniqueBuildFolder;
 		private final String binaryPath;
 		@Nullable
-		private final String codeStyleSettingsPath; // TODO make sure to save content in state
+		private final String codeStyleSettingsPath;
 		private final boolean withDefaults;
 		private final TreeMap ideaProperties;
 
 		private State(@Nonnull IdeaStepBuilder builder) {
-			this.buildDir = ThrowingEx.get(builder.buildDir::getCanonicalPath);
-			this.uniquePath = UUID.randomUUID().toString();
+			this.uniqueBuildFolder = new File(builder.buildDir, UUID.randomUUID().toString());
 			this.withDefaults = builder.useDefaults;
 			this.codeStyleSettingsPath = builder.codeStyleSettingsPath;
 			this.ideaProperties = new TreeMap<>(builder.ideaProperties);
@@ -174,7 +170,6 @@ private static String pathToExe(String binaryPath) {
 			return null; // search in PATH
 		}
 
-		@CheckForNull
 		private static String macOsFix(String binaryPath) {
 
 			// on macOS, the binary is located in the .app bundle which might be invisible to the user
@@ -200,22 +195,18 @@ private static boolean isMacOs() {
 			return System.getProperty("os.name").toLowerCase().contains("mac");
 		}
 
-		@Override
-		public String applyWithFile(String unix, File file) throws Exception {
+		private String format(IdeaStepFormatterCleanupResources ideaStepFormatterCleanupResources, String unix, File file) throws Exception {
 			// since we cannot directly work with the file, we need to write the unix string to a temporary file
 			File tempFile = File.createTempFile("spotless", file.getName());
 			try {
 				Files.write(tempFile.toPath(), unix.getBytes(StandardCharsets.UTF_8));
 				List params = getParams(tempFile);
 
-				try (ProcessRunner runner = new ProcessRunner()) {
-					Map env = createEnv();
-					var result = runner.exec(null, env, null, params);
-					LOGGER.debug("command finished with stdout: {}",
-							result.assertExitZero(StandardCharsets.UTF_8));
-
-					return Files.readString(tempFile.toPath(), StandardCharsets.UTF_8);
-				}
+				Map env = createEnv();
+				var result = ideaStepFormatterCleanupResources.runner.exec(null, env, null, params);
+				LOGGER.debug("command finished with stdout: {}",
+						result.assertExitZero(StandardCharsets.UTF_8));
+				return Files.readString(tempFile.toPath(), StandardCharsets.UTF_8);
 			} finally {
 				Files.delete(tempFile.toPath());
 			}
@@ -229,7 +220,7 @@ private Map createEnv() {
 		}
 
 		private File createIdeaPropertiesFile() {
-			Path ideaProps = new File(buildDir).toPath().resolve(uniquePath).resolve("idea.properties");
+			Path ideaProps = this.uniqueBuildFolder.toPath().resolve("idea.properties");
 
 			if (Files.exists(ideaProps)) {
 				return ideaProps.toFile(); // only create if it does not exist
@@ -269,5 +260,43 @@ private List getParams(File file) {
 			builder.add(ThrowingEx.get(file::getCanonicalPath));
 			return builder.build().collect(Collectors.toList());
 		}
+
+		private FormatterFunc.Closeable toFunc() {
+			IdeaStepFormatterCleanupResources ideaStepFormatterCleanupResources = new IdeaStepFormatterCleanupResources(uniqueBuildFolder, new ProcessRunner());
+			return FormatterFunc.Closeable.of(ideaStepFormatterCleanupResources, this::format);
+		}
+	}
+
+	private static class IdeaStepFormatterCleanupResources implements AutoCloseable {
+		@Nonnull
+		private final File uniqueBuildFolder;
+		@Nonnull
+		private final ProcessRunner runner;
+
+		public IdeaStepFormatterCleanupResources(@Nonnull File uniqueBuildFolder, @Nonnull ProcessRunner runner) {
+			this.uniqueBuildFolder = uniqueBuildFolder;
+			this.runner = runner;
+		}
+
+		@Override
+		public void close() throws Exception {
+			// close the runner
+			runner.close();
+			// delete the unique build folder
+			if (uniqueBuildFolder.exists()) {
+				// delete the unique build folder recursively
+				try (Stream paths = Files.walk(uniqueBuildFolder.toPath())) {
+					paths.sorted((o1, o2) -> o2.compareTo(o1)) // delete files first
+							.forEach(path -> {
+								try {
+									Files.delete(path);
+								} catch (IOException e) {
+									LOGGER.warn("Failed to delete file: {}", path, e);
+								}
+							});
+				}
+			}
+		}
+
 	}
 }

From 7b2b21cc66feabaca446d506d079d557d624be75 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Sun, 18 May 2025 21:40:54 +0200
Subject: [PATCH 142/210] refactor: adapt creation pipeline to allow createLazy
 to work with function pointers

---
 .../diffplug/spotless/generic/IdeaStep.java   | 38 +++++++++++++++----
 .../gradle/spotless/FormatExtension.java      |  2 +-
 .../diffplug/spotless/maven/generic/Idea.java |  2 +-
 .../spotless/generic/IdeaStepTest.java        | 12 +++---
 4 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index 7adbd12762..fd975e4df4 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -48,27 +48,34 @@
 
 public final class IdeaStep {
 
+	private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class);
+
 	public static final String NAME = "IDEA";
 
 	public static final String IDEA_EXECUTABLE_DEFAULT = "idea";
 
-	private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class);
 	public static final String IDEA_CONFIG_PATH_PROPERTY = "idea.config.path";
 	public static final String IDEA_SYSTEM_PATH_PROPERTY = "idea.system.path";
+	@Nonnull
+	private final IdeaStepBuilder builder;
 
-	private IdeaStep() {}
+	private IdeaStep(@Nonnull IdeaStepBuilder builder) {
+		this.builder = builder;
+	}
 
-	public static IdeaStepBuilder create(@Nonnull File buildDir) {
+	public static IdeaStepBuilder newBuilder(@Nonnull File buildDir) {
 		return new IdeaStepBuilder(Objects.requireNonNull(buildDir));
 	}
 
-	private static FormatterStep create(@Nonnull IdeaStepBuilder builder) {
-		Objects.requireNonNull(builder);
-		return FormatterStep.createLazy(NAME,
-				() -> createState(builder), State::toFunc);
+	private static FormatterStep create(IdeaStepBuilder builder) {
+		return new IdeaStep(builder).createFormatterStep();
 	}
 
-	private static State createState(@Nonnull IdeaStepBuilder builder) {
+	private FormatterStep createFormatterStep() {
+		return FormatterStep.createLazy(NAME, this::createState, State::toFunc);
+	}
+
+	private State createState() {
 		return new State(Objects.requireNonNull(builder));
 	}
 
@@ -114,6 +121,17 @@ public IdeaStepBuilder setIdeaProperties(@Nonnull Map ideaProper
 		public FormatterStep build() {
 			return create(this);
 		}
+
+		@Override
+		public String toString() {
+			return String.format(
+					"IdeaStepBuilder[useDefaults=%s, binaryPath=%s, codeStyleSettingsPath=%s, ideaProperties=%s, buildDir=%s]",
+					this.useDefaults,
+					this.binaryPath,
+					this.codeStyleSettingsPath,
+					this.ideaProperties,
+					this.buildDir);
+		}
 	}
 
 	private static class State implements Serializable {
@@ -128,6 +146,7 @@ private static class State implements Serializable {
 		private final TreeMap ideaProperties;
 
 		private State(@Nonnull IdeaStepBuilder builder) {
+			LOGGER.debug("Creating {} state with configuration {}", NAME, builder);
 			this.uniqueBuildFolder = new File(builder.buildDir, UUID.randomUUID().toString());
 			this.withDefaults = builder.useDefaults;
 			this.codeStyleSettingsPath = builder.codeStyleSettingsPath;
@@ -203,7 +222,9 @@ private String format(IdeaStepFormatterCleanupResources ideaStepFormatterCleanup
 				List params = getParams(tempFile);
 
 				Map env = createEnv();
+				LOGGER.info("Launching IDEA formatter for orig file {} with params: {} and env: {}", file, params, env);
 				var result = ideaStepFormatterCleanupResources.runner.exec(null, env, null, params);
+				LOGGER.debug("command finished with exit code: {}", result.exitCode());
 				LOGGER.debug("command finished with stdout: {}",
 						result.assertExitZero(StandardCharsets.UTF_8));
 				return Files.readString(tempFile.toPath(), StandardCharsets.UTF_8);
@@ -236,6 +257,7 @@ private File createIdeaPropertiesFile() {
 			properties.put(IDEA_CONFIG_PATH_PROPERTY, ThrowingEx.get(configPath.toFile()::getCanonicalPath));
 			properties.put(IDEA_SYSTEM_PATH_PROPERTY, ThrowingEx.get(systemPath.toFile()::getCanonicalPath));
 
+			LOGGER.debug("Creating IDEA properties file at {} with content: {}", ideaProps, properties);
 			try (FileOutputStream out = new FileOutputStream(ideaProps.toFile())) {
 				properties.store(out, "Generated by spotless");
 			} catch (IOException e) {
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 b1f8cb9d6b..f457500ee7 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
@@ -969,7 +969,7 @@ public class IdeaConfig {
 		private final IdeaStep.IdeaStepBuilder builder;
 
 		IdeaConfig() {
-			this.builder = IdeaStep.create(getProject().getLayout().getBuildDirectory().getAsFile().get());
+			this.builder = IdeaStep.newBuilder(getProject().getLayout().getBuildDirectory().getAsFile().get());
 			addStep(createStep());
 		}
 
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
index ab9de41a08..0e09b8f1a7 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
@@ -35,7 +35,7 @@ public class Idea implements FormatterStepFactory {
 
 	@Override
 	public FormatterStep newFormatterStep(FormatterStepConfig config) {
-		return IdeaStep.create(config.getFileLocator().getBuildDir())
+		return IdeaStep.newBuilder(config.getFileLocator().getBuildDir())
 				.setUseDefaults(withDefaults)
 				.setCodeStyleSettingsPath(configPath)
 				.setBinaryPath(binaryPath)
diff --git a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
index 05b643805e..fad95e10f4 100644
--- a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
+++ b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
@@ -32,7 +32,7 @@ class IdeaStepTest extends ResourceHarness {
 
 	@Test
 	void name() throws Exception {
-		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
+		FormatterStep step = IdeaStep.newBuilder(buildDir()).setUseDefaults(true).build();
 
 		String name = step.getName();
 
@@ -44,7 +44,7 @@ void notFormattings() throws Exception {
 		File cleanFile = newFile("clean.java");
 		String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java");
 		Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
+		FormatterStep step = IdeaStep.newBuilder(buildDir()).setUseDefaults(true).build();
 
 		var result = step.format(cleanJava, cleanFile);
 
@@ -57,7 +57,7 @@ void formattings() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
+		FormatterStep step = IdeaStep.newBuilder(buildDir()).setUseDefaults(true).build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -70,7 +70,7 @@ void formattingsWorkWithDefaultParameters() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(buildDir()).build();
+		FormatterStep step = IdeaStep.newBuilder(buildDir()).build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -83,7 +83,7 @@ void formattingsWithOutDefaultDoesNothing() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(false).build();
+		FormatterStep step = IdeaStep.newBuilder(buildDir()).setUseDefaults(false).build();
 
 		var result = step.format(dirtyJava, dirtyFile);
 
@@ -96,7 +96,7 @@ void configureFile() throws Exception {
 		File cleanFile = newFile("clean.java");
 		String cleanJava = ResourceHarness.getTestResource("java/idea/full.clean.java");
 		Files.write(cleanJava, cleanFile, StandardCharsets.UTF_8);
-		FormatterStep step = IdeaStep.create(buildDir()).setUseDefaults(true).build();
+		FormatterStep step = IdeaStep.newBuilder(buildDir()).setUseDefaults(true).build();
 
 		var result = step.format(cleanJava, cleanFile);
 

From 412430deb47dd0126e90bef6d37d686244663513 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Mon, 19 May 2025 21:01:25 +0200
Subject: [PATCH 143/210] chore: add testIdea to ci

---
 .github/workflows/ci.yml | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e5de52b4d9..051f9802c5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -59,6 +59,9 @@ jobs:
             jre: 11
             os: ubuntu-latest
             shfmt-version: v3.8.0
+          - kind: idea
+            jre: 11
+            os: ubuntu-latest
     runs-on: ${{ matrix.os }}
     steps:
       - name: Checkout
@@ -91,6 +94,16 @@ jobs:
       - name: Test shfmt
         if: matrix.kind == 'shfmt'
         run: ./gradlew testShfmt
+      - name: Test idea
+        if: matrix.kind == 'idea'
+        run: |
+          download_link=$(curl https://data.services.jetbrains.com/products/releases\?code\=IIC\&latest\=true\&type\=release | jq -r '.IIC[0].downloads.linux.link')
+          curl --location "$download_link" -o idea.tar.gz
+          tar -xf idea.tar.gz
+          cd idea-IC*
+          export PATH=${PATH}:$(pwd)/bin
+          cd ..
+          ./gradlew testIdea
       - name: junit result
         uses: mikepenz/action-junit-report@v5
         if: always() # always run even if the previous step fails

From b686a1c56248314dfeedeed94a012c167fca9773 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Fri, 20 Jun 2025 21:40:41 +0200
Subject: [PATCH 144/210] docs: start documenting idea usage

---
 plugin-gradle/README.md | 42 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md
index 7a2c6b42b7..148f01bcce 100644
--- a/plugin-gradle/README.md
+++ b/plugin-gradle/README.md
@@ -55,7 +55,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui
   - [Requirements](#requirements)
   - [Linting](#linting)
 - **Languages**
-  - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat))
+  - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea))
   - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy))
   - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier))
   - [Scala](#scala) ([scalafmt](#scalafmt))
@@ -65,7 +65,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui
   - [FreshMark](#freshmark) aka markdown
   - [Flexmark](#flexmark) aka markdown
   - [Antlr4](#antlr4) ([antlr4formatter](#antlr4formatter))
-  - [SQL](#sql) ([dbeaver](#dbeaver), [prettier](#prettier))
+  - [SQL](#sql) ([dbeaver](#dbeaver), [prettier](#prettier), [IntelliJ IDEA](#intellij-idea))
   - [Maven POM](#maven-pom) ([sortPom](#sortpom))
   - [Typescript](#typescript) ([tsfmt](#tsfmt), [prettier](#prettier), [ESLint](#eslint-typescript), [Biome](#biome))
   - [Javascript](#javascript) ([prettier](#prettier), [ESLint](#eslint-javascript), [Biome](#biome))
@@ -78,6 +78,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui
     - [clang-format](#clang-format)
     - [eclipse web tools platform](#eclipse-web-tools-platform)
     - [Biome](#biome) ([binary detection](#biome-binary), [config file](#biome-configuration-file), [input language](#biome-input-language))
+    - [IntelliJ IDEA](#intellij-idea)
 - **Language independent**
   - [Generic steps](#generic-steps)
   - [License header](#license-header) ([slurp year from git](#retroactively-slurp-years-from-git-history))
@@ -198,6 +199,7 @@ spotless {
     eclipse()            // has its own section below
     prettier()           // has its own section below
     clangFormat()        // has its own section below
+    idea()               // has its own section below
 
     formatAnnotations()  // fixes formatting of type annotations, see below
 
@@ -754,6 +756,7 @@ spotless {
 
     dbeaver()  // has its own section below
     prettier() // has its own section below
+    idea()     // has its own section below
   }
 }
 ```
@@ -1581,9 +1584,42 @@ The following languages are currently recognized:
 * `ts?` -- TypeScript, with or without JSX, depending on the file extension
 * `json` -- JSON
 
+## IntelliJ IDEA
+
+[homepage](https://www.jetbrains.com/idea/). [changelog](https://www.jetbrains.com/idea/whatsnew/). 
+
+`IntelliJ IDEA` is a powerful IDE for java, kotlin and many more languages. There are [specific variants](https://www.jetbrains.com/products/) for almost any modern language
+and a plethora of [plugins](https://plugins.jetbrains.com/).
+
+Spotless provides access to IntelliJ IDEA's command line formatter. 
+
+
+```gradle
+spotless {
+  format 'myFormatter', {
+    // you have to set the target manually
+    target 'src/main/**/*.java','jbang/*.java'
+
+    idea()
+      .codeStyleSettingsPath('/path/to/config') // if you have custom formatting rules, see below for how to get them
+      .withDefaults(true) // Use the default code style settings when the code style is not defined for a file type (default: true)
+
+    // if idea is not on your path, you must specify the path to the executable
+    idea().binaryPath('/path/to/idea')
+  }
+}
+```
+
+### How to generate code style settings files
+TODO
+
+### Limitations
+- Currently, only IntelliJ IDEA is supported - none of the other jetbrains IDE. Consider opening a PR if you want to change this.
+- Launching IntelliJ IDEA from the command line is pretty expensive and as of now, we do this for each file. If you want to change this, consider opening a PR.
+
 ## Generic steps
 
-[Prettier](#prettier), [eclipse wtp](#eclipse-web-tools-platform), and [license header](#license-header) are available in every format, and they each have their own section. As mentioned in the [quickstart](#quickstart), there are a variety of simple generic steps which are also available in every format, here are examples of these:
+[Prettier](#prettier), [eclipse wtp](#eclipse-web-tools-platform), [IntelliJ IDEA](#intellij-idea) and [license header](#license-header) are available in every format, and they each have their own section. As mentioned in the [quickstart](#quickstart), there are a variety of simple generic steps which are also available in every format, here are examples of these:
 
 ```gradle
 spotless {

From 3277660331bf2945ccf8e786461410d12b7f37c1 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Fri, 20 Jun 2025 21:40:58 +0200
Subject: [PATCH 145/210] chore: adapt api for idea step

---
 .../java/com/diffplug/gradle/spotless/FormatExtension.java     | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

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 f457500ee7..3b96a85394 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
@@ -984,8 +984,7 @@ public IdeaConfig binaryPath(String binaryPath) {
 			return this;
 		}
 
-		// TODO (simschla, 11.05.2025): rename
-		public IdeaConfig configPath(String configPath) {
+		public IdeaConfig codeStyleSettingsPath(String configPath) {
 			requireNonNull(configPath);
 			builder.setCodeStyleSettingsPath(configPath);
 			replaceStep(createStep());

From 6d71e4d594528ad13a15a4a5f7d07fe7c78d3e60 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Wed, 25 Jun 2025 20:17:02 +0200
Subject: [PATCH 146/210] docs: add documentation for IntelliJ codestyle

---
 INTELLIJ_IDEA_SCREENSHOTS.md          |  16 +++++++++
 _images/intellij_export_codestyle.png | Bin 0 -> 133848 bytes
 plugin-gradle/README.md               |   7 ++--
 plugin-maven/README.md                |  49 +++++++++++++++++++++++---
 4 files changed, 64 insertions(+), 8 deletions(-)
 create mode 100644 INTELLIJ_IDEA_SCREENSHOTS.md
 create mode 100644 _images/intellij_export_codestyle.png

diff --git a/INTELLIJ_IDEA_SCREENSHOTS.md b/INTELLIJ_IDEA_SCREENSHOTS.md
new file mode 100644
index 0000000000..31e264b5ea
--- /dev/null
+++ b/INTELLIJ_IDEA_SCREENSHOTS.md
@@ -0,0 +1,16 @@
+# Extracting Code Style from IntelliJ IDEA
+
+## 1. Exporting Code Style Settings to a file
+To export code style settings from IntelliJ IDEA to a file, go to
+`Settings | Editor | Code Style` and click on the gear icon next to the scheme name.
+
+![Exporting code style settings](_images/intellij_export_codestyle.png)
+
+## 2. Using IntelliJ's active code style directly
+If you have your code style settings checked into version control (in your `.idea` directory), 
+you can use the active code style directly in Spotless without exporting it to a file. 
+The file can be found at `.idea/codeStyles/Project.xml`.
+
+## Upstream documentation
+More details can be found in the [IntelliJ IDEA documentation](https://www.jetbrains.com/help/idea/command-line-formatter.html#options)
+for the command line formatter, which is what Spotless uses under the hood.
diff --git a/_images/intellij_export_codestyle.png b/_images/intellij_export_codestyle.png
new file mode 100644
index 0000000000000000000000000000000000000000..e0c98d2cdbd1b987c118a1ebeabc536fc6d1d1a8
GIT binary patch
literal 133848
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
P2=LKX*HtT1wSMwHd2Wgy

literal 0
HcmV?d00001

diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md
index 148f01bcce..f775bf58a8 100644
--- a/plugin-gradle/README.md
+++ b/plugin-gradle/README.md
@@ -1593,7 +1593,6 @@ and a plethora of [plugins](https://plugins.jetbrains.com/).
 
 Spotless provides access to IntelliJ IDEA's command line formatter. 
 
-
 ```gradle
 spotless {
   format 'myFormatter', {
@@ -1601,8 +1600,8 @@ spotless {
     target 'src/main/**/*.java','jbang/*.java'
 
     idea()
-      .codeStyleSettingsPath('/path/to/config') // if you have custom formatting rules, see below for how to get them
-      .withDefaults(true) // Use the default code style settings when the code style is not defined for a file type (default: true)
+      .codeStyleSettingsPath('/path/to/config') // if you have custom formatting rules, see below for how to extract/reference them
+      .withDefaults(false) // Disable using default code style settings when no custom code style is defined for a file type (default: true)
 
     // if idea is not on your path, you must specify the path to the executable
     idea().binaryPath('/path/to/idea')
@@ -1611,7 +1610,7 @@ spotless {
 ```
 
 ### How to generate code style settings files
-TODO
+See [here](../INTELLIJ_IDEA_SCREENSHOTS.md) for an explanation on how to extract or reference existing code style files. 
 
 ### Limitations
 - Currently, only IntelliJ IDEA is supported - none of the other jetbrains IDE. Consider opening a PR if you want to change this.
diff --git a/plugin-maven/README.md b/plugin-maven/README.md
index b27ddc4eab..b6c238940c 100644
--- a/plugin-maven/README.md
+++ b/plugin-maven/README.md
@@ -38,15 +38,15 @@ user@machine repo % mvn spotless:check
 - [**Quickstart**](#quickstart)
   - [Requirements](#requirements)
   - [Binding to maven phase](#binding-to-maven-phase)
-- **Languages**
-  - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat))
+- **Languages** // TODO add idea
+  - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat),[IntelliiJ IDEA](#intellij-idea))
   - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy))
   - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier))
   - [Scala](#scala) ([scalafmt](#scalafmt))
   - [C/C++](#cc) ([eclipse cdt](#eclipse-cdt), [clang-format](#clang-format))
   - [Python](#python) ([black](#black))
   - [Antlr4](#antlr4) ([antlr4formatter](#antlr4formatter))
-  - [Sql](#sql) ([dbeaver](#dbeaver))
+  - [Sql](#sql) ([dbeaver](#dbeaver), [prettier](#prettier), [IntelliJ IDEA](#intellij-idea))
   - [Maven Pom](#maven-pom) ([sortPom](#sortpom))
   - [Markdown](#markdown) ([flexmark](#flexmark))
   - [Typescript](#typescript) ([tsfmt](#tsfmt), [prettier](#prettier), [ESLint](#eslint-typescript), [Biome](#biome))
@@ -61,6 +61,7 @@ user@machine repo % mvn spotless:check
     - [Prettier](#prettier) ([plugins](#prettier-plugins), [npm detection](#npm-detection), [`.npmrc` detection](#npmrc-detection), [caching `npm install` results](#caching-results-of-npm-install))
     - [eclipse web tools platform](#eclipse-web-tools-platform)
     - [Biome](#biome) ([binary detection](#biome-binary), [config file](#biome-configuration-file), [input language](#biome-input-language))
+    - [IntelliJ IDEA](#intellij-idea)
 - **Language independent**
   - [Generic steps](#generic-steps)
   - [License header](#license-header) ([slurp year from git](#retroactively-slurp-years-from-git-history))
@@ -194,6 +195,7 @@ any other maven phase (i.e. compile) then it can be configured as below;
      
               
              
+                 
 
      
       
@@ -665,6 +667,7 @@ Additionally, `editorConfigOverride` options will override what's supplied in `.
 
       
      
+         
   
 
 ```
@@ -1666,9 +1669,47 @@ The following languages are currently recognized:
 * `ts?` -- TypeScript, with or without JSX, depending on the file extension
 * `json` -- JSON
 
+## IntelliJ IDEA
+
+[homepage](https://www.jetbrains.com/idea/). [changelog](https://www.jetbrains.com/idea/whatsnew/).
+
+`IntelliJ IDEA` is a powerful IDE for java, kotlin and many more languages. There are [specific variants](https://www.jetbrains.com/products/) for almost any modern language
+and a plethora of [plugins](https://plugins.jetbrains.com/).
+
+Spotless provides access to IntelliJ IDEA's command line formatter.
+
+```xml
+
+  
+    
+      
+        src/main/**/*.java
+        jbang/*.java
+      
+
+      
+        
+        /path/to/config
+        
+        false
+        
+        /path/to/idea
+      
+    
+  
+
+```
+
+### How to generate code style settings files
+See [here](../INTELLIJ_IDEA_SCREENSHOTS.md) for an explanation on how to extract or reference existing code style files.
+
+### Limitations
+- Currently, only IntelliJ IDEA is supported - none of the other jetbrains IDE. Consider opening a PR if you want to change this.
+- Launching IntelliJ IDEA from the command line is pretty expensive and as of now, we do this for each file. If you want to change this, consider opening a PR.
+
 ## Generic steps
 
-[Prettier](#prettier), [eclipse wtp](#eclipse-web-tools-platform), and [license header](#license-header) are available in every format, and they each have their own section. As mentioned in the [quickstart](#quickstart), there are a variety of simple generic steps which are also available in every format, here are examples of these:
+[Prettier](#prettier), [eclipse wtp](#eclipse-web-tools-platform), [IntelliJ IDEA](#intellij-idea) and [license header](#license-header) are available in every format, and they each have their own section. As mentioned in the [quickstart](#quickstart), there are a variety of simple generic steps which are also available in every format, here are examples of these:
 
 ```xml
  

From 50e2589256943684356134261a17970411877e6e Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Wed, 25 Jun 2025 21:24:49 +0200
Subject: [PATCH 147/210] fix(mvn): pass developer root dir to maven tests

---
 .../spotless/generic/TestEnvVars.java         |  3 +++
 plugin-maven/build.gradle                     |  1 +
 .../diffplug/spotless/maven/generic/Idea.java |  6 ++---
 .../maven/MavenIntegrationHarness.java        | 10 +++++--
 .../diffplug/spotless/maven/MavenRunner.java  | 26 +++++++++++++++++--
 5 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java b/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
index c0966c511f..f341f09b99 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
@@ -64,6 +64,9 @@ private static Stream candidateTestEnvLocations() {
 		if (System.getProperty("testenv.properties.path") != null) {
 			builder.add(Path.of(System.getProperty("testenv.properties.path")));
 		}
+		if (System.getProperty("spotlessProjectDir") != null) {
+			builder.add(Path.of(System.getProperty("spotlessProjectDir"), "testenv.properties"));
+		}
 		builder.add(
 				Path.of(System.getProperty("user.dir"), "testenv.properties"));
 		builder.add(
diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle
index 7932d4a007..d8e5f90770 100644
--- a/plugin-maven/build.gradle
+++ b/plugin-maven/build.gradle
@@ -55,6 +55,7 @@ dependencies {
 apply from: rootProject.file('gradle/special-tests.gradle')
 tasks.withType(Test).configureEach {
 	systemProperty 'spotlessMavenPluginVersion', project.version
+	systemProperty 'spotlessProjectDir', "${project.rootProject.projectDir}".toString()
 	dependsOn 'publishToMavenLocal'
 	dependsOn ':lib:publishToMavenLocal'
 	dependsOn ':lib-extra:publishToMavenLocal'
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
index 0e09b8f1a7..2c3b5587a3 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Idea.java
@@ -28,16 +28,16 @@ public class Idea implements FormatterStepFactory {
 	private String binaryPath;
 
 	@Parameter
-	private String configPath;
+	private String codeStyleSettingsPath;
 
 	@Parameter
-	private Boolean withDefaults = false;
+	private Boolean withDefaults = true;
 
 	@Override
 	public FormatterStep newFormatterStep(FormatterStepConfig config) {
 		return IdeaStep.newBuilder(config.getFileLocator().getBuildDir())
 				.setUseDefaults(withDefaults)
-				.setCodeStyleSettingsPath(configPath)
+				.setCodeStyleSettingsPath(codeStyleSettingsPath)
 				.setBinaryPath(binaryPath)
 				.build();
 	}
diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java
index 0d0582e180..f3e1f30355 100644
--- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java
+++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.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.
@@ -213,9 +213,15 @@ protected void writePom(String[] executions, String[] configuration, String[] de
 	}
 
 	protected MavenRunner mavenRunner() throws IOException {
-		return MavenRunner.create()
+		MavenRunner mavenRunner = MavenRunner.create()
 				.withProjectDir(rootFolder())
 				.withRunner(runner);
+		System.getProperties().forEach((key, value) -> {
+			if (key instanceof String && ((String) key).startsWith("spotless") && value instanceof String) {
+				mavenRunner.withSystemProperty((String) key, (String) value);
+			}
+		});
+		return mavenRunner;
 	}
 
 	private static ProcessRunner runner;
diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java
index c8d845f8a2..6e22fe5e31 100644
--- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java
+++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2023 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.
@@ -23,6 +23,8 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import com.diffplug.spotless.Jvm;
 import com.diffplug.spotless.ProcessRunner;
@@ -41,6 +43,7 @@ private MavenRunner() {}
 	private File projectDir;
 	private String[] args;
 	private Map environment = new HashMap<>();
+	private Map systemProperties = new HashMap<>();
 	private ProcessRunner runner;
 
 	public MavenRunner withProjectDir(File projectDir) {
@@ -64,12 +67,31 @@ public MavenRunner withRemoteDebug(int port) {
 		return this;
 	}
 
+	public MavenRunner withSystemProperty(String key, String value) {
+		systemProperties.put(key, value);
+		return this;
+	}
+
+	private Map calculateEnvironment() {
+		Map env = new HashMap<>(environment);
+		if (!systemProperties.isEmpty()) {
+			// add system properties as environment variables as MAVEN_OPTS or append if already there
+			String sysProps = systemProperties.entrySet().stream()
+					.map(entry -> String.format("-D%s=%s", entry.getKey(), entry.getValue()))
+					.collect(Collectors.joining(" "));
+			String mavenOpts = Stream.of(env.getOrDefault("MAVEN_OPTS", ""), sysProps)
+					.collect(Collectors.joining(" "));
+			env.put("MAVEN_OPTS", mavenOpts.trim());
+		}
+		return env;
+	}
+
 	private ProcessRunner.Result run() throws IOException, InterruptedException {
 		Objects.requireNonNull(projectDir, "Need to call withProjectDir() first");
 		Objects.requireNonNull(args, "Need to call withArguments() first");
 		// run Maven with the given args in the given directory
 		String argsString = "-e " + String.join(" ", Arrays.asList(args));
-		return runner.shellWinUnix(projectDir, environment, "mvnw " + argsString, "./mvnw " + argsString);
+		return runner.shellWinUnix(projectDir, calculateEnvironment(), "mvnw " + argsString, "./mvnw " + argsString);
 	}
 
 	/** Runs the command and asserts that exit code is 0. */

From 3000ad8fcf38428b89ce4c2403446251720a04f0 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Sun, 29 Jun 2025 20:51:02 +0200
Subject: [PATCH 148/210] style: reformat with spotless

---
 .../diffplug/spotless/generic/IdeaStep.java   |  7 ++----
 .../gradle/spotless/FormatExtension.java      | 24 +++++++------------
 2 files changed, 10 insertions(+), 21 deletions(-)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index fd975e4df4..e14e975cb5 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -84,8 +84,7 @@ public static final class IdeaStepBuilder {
 		private boolean useDefaults = true;
 		@Nonnull
 		private String binaryPath = IDEA_EXECUTABLE_DEFAULT;
-		@Nullable
-		private String codeStyleSettingsPath;
+		@Nullable private String codeStyleSettingsPath;
 		private final Map ideaProperties = new HashMap<>();
 
 		@Nonnull
@@ -140,8 +139,7 @@ private static class State implements Serializable {
 
 		private final File uniqueBuildFolder;
 		private final String binaryPath;
-		@Nullable
-		private final String codeStyleSettingsPath;
+		@Nullable private final String codeStyleSettingsPath;
 		private final boolean withDefaults;
 		private final TreeMap ideaProperties;
 
@@ -190,7 +188,6 @@ private static String pathToExe(String binaryPath) {
 		}
 
 		private static String macOsFix(String binaryPath) {
-
 			// on macOS, the binary is located in the .app bundle which might be invisible to the user
 			// we try need to append the path to the binary
 			File binary = new File(binaryPath);
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 3b96a85394..1216b15864 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
@@ -218,8 +218,7 @@ public void encoding(String charset) {
 	protected FileCollection target, targetExclude;
 
 	/** The value from which files will be excluded if their content contain it. */
-	@Nullable
-	protected String targetExcludeContentPattern = null;
+	@Nullable protected String targetExcludeContentPattern = null;
 
 	protected boolean isLicenseHeaderStep(FormatterStep formatterStep) {
 		String formatterStepName = formatterStep.getName();
@@ -687,17 +686,13 @@ public abstract static class NpmStepConfig> {
 
 		public static final String SPOTLESS_NPM_INSTALL_CACHE_DEFAULT_NAME = "spotless-npm-install-cache";
 
-		@Nullable
-		protected Object npmFile;
+		@Nullable protected Object npmFile;
 
-		@Nullable
-		protected Object nodeFile;
+		@Nullable protected Object nodeFile;
 
-		@Nullable
-		protected Object npmInstallCache;
+		@Nullable protected Object npmInstallCache;
 
-		@Nullable
-		protected Object npmrcFile;
+		@Nullable protected Object npmrcFile;
 
 		protected Project project;
 
@@ -771,11 +766,9 @@ protected void replaceStep() {
 
 	public class PrettierConfig extends NpmStepConfig {
 
-		@Nullable
-		Object prettierConfigFile;
+		@Nullable Object prettierConfigFile;
 
-		@Nullable
-		Map prettierConfig;
+		@Nullable Map prettierConfig;
 
 		final Map devDependencies;
 
@@ -815,8 +808,7 @@ protected FormatterStep createStep() {
 	 * format{ ... }.
 	 */
 	public class BiomeGeneric extends BiomeStepConfig {
-		@Nullable
-		String language;
+		@Nullable String language;
 
 		/**
 		 * Creates a new Biome config that downloads the Biome executable for the given

From b7aed375c0be85b27a1d9774f50f683b58e92767 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Sun, 29 Jun 2025 20:51:13 +0200
Subject: [PATCH 149/210] docs: update with PR-reference

---
 CHANGES.md               | 2 +-
 plugin-gradle/CHANGES.md | 2 +-
 plugin-maven/CHANGES.md  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 2d82b3c711..938e3c385c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -11,7 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
 
 ## [Unreleased]
 ### Added
-* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020))
+* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535))
 * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517))
 
 ## [3.1.2] - 2025-05-27
diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md
index e5c37e06a1..121d9d922c 100644
--- a/plugin-gradle/CHANGES.md
+++ b/plugin-gradle/CHANGES.md
@@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
 
 ## [Unreleased]
 ### Added
-* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020))
+* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535))
 * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517))
 
 ## [7.0.4] - 2025-05-27
diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md
index 06d09cc81d..cab00b07af 100644
--- a/plugin-maven/CHANGES.md
+++ b/plugin-maven/CHANGES.md
@@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
 
 ## [Unreleased]
 ### Added
-* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020))
+* Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535))
 * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517))
 
 ## [2.44.5] - 2025-05-27

From b5e117eb56264c8225f86f871969b2b54e2b8742 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Mon, 30 Jun 2025 08:16:23 +0200
Subject: [PATCH 150/210] fix: correct pmd warnings

---
 .../com/diffplug/spotless/generic/IdeaStep.java     | 13 +++++++++----
 .../com/diffplug/spotless/generic/TestEnvVars.java  |  3 ++-
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
index e14e975cb5..209a0d7560 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/IdeaStep.java
@@ -24,6 +24,7 @@
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
@@ -208,7 +209,7 @@ private static String macOsFix(String binaryPath) {
 		}
 
 		private static boolean isMacOs() {
-			return System.getProperty("os.name").toLowerCase().contains("mac");
+			return System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("mac");
 		}
 
 		private String format(IdeaStepFormatterCleanupResources ideaStepFormatterCleanupResources, String unix, File file) throws Exception {
@@ -244,10 +245,14 @@ private File createIdeaPropertiesFile() {
 				return ideaProps.toFile(); // only create if it does not exist
 			}
 
-			ThrowingEx.run(() -> Files.createDirectories(ideaProps.getParent()));
+			Path parent = ideaProps.getParent();
+			if (parent == null) {
+				throw new IllegalStateException(String.format("Parent directory for IDEA properties file %s cannot be null", ideaProps));
+			}
+			ThrowingEx.run(() -> Files.createDirectories(parent));
 
-			Path configPath = ideaProps.getParent().resolve("config");
-			Path systemPath = ideaProps.getParent().resolve("system");
+			Path configPath = parent.resolve("config");
+			Path systemPath = parent.resolve("system");
 
 			Properties properties = new Properties();
 			properties.putAll(ideaProperties);
diff --git a/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java b/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
index f341f09b99..8845fe9c0d 100644
--- a/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
+++ b/lib/src/main/java/com/diffplug/spotless/generic/TestEnvVars.java
@@ -20,6 +20,7 @@
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -70,7 +71,7 @@ private static Stream candidateTestEnvLocations() {
 		builder.add(
 				Path.of(System.getProperty("user.dir"), "testenv.properties"));
 		builder.add(
-				Path.of(System.getProperty("user.dir")).getParent().resolve("testenv.properties"));
+				Objects.requireNonNull(Path.of(System.getProperty("user.dir")).getParent()).resolve("testenv.properties"));
 		return builder.build();
 	}
 

From 044f98d88486f6c492927f6725109bacea051131 Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Mon, 30 Jun 2025 16:25:08 +0200
Subject: [PATCH 151/210] docs: fix typo

---
 plugin-maven/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugin-maven/README.md b/plugin-maven/README.md
index b6c238940c..212e16e48a 100644
--- a/plugin-maven/README.md
+++ b/plugin-maven/README.md
@@ -39,7 +39,7 @@ user@machine repo % mvn spotless:check
   - [Requirements](#requirements)
   - [Binding to maven phase](#binding-to-maven-phase)
 - **Languages** // TODO add idea
-  - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat),[IntelliiJ IDEA](#intellij-idea))
+  - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea))
   - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy))
   - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier))
   - [Scala](#scala) ([scalafmt](#scalafmt))

From 6c7ecf5322dfa6d04f952a4e4f96d05504ceedde Mon Sep 17 00:00:00 2001
From: Simon Gamma 
Date: Mon, 30 Jun 2025 16:26:46 +0200
Subject: [PATCH 152/210] chore: cleanups based on review

---
 plugin-maven/README.md                                          | 2 +-
 .../test/java/com/diffplug/spotless/generic/IdeaStepTest.java   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/plugin-maven/README.md b/plugin-maven/README.md
index 212e16e48a..2e5839e819 100644
--- a/plugin-maven/README.md
+++ b/plugin-maven/README.md
@@ -38,7 +38,7 @@ user@machine repo % mvn spotless:check
 - [**Quickstart**](#quickstart)
   - [Requirements](#requirements)
   - [Binding to maven phase](#binding-to-maven-phase)
-- **Languages** // TODO add idea
+- **Languages**
   - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea))
   - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy))
   - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier))
diff --git a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
index fad95e10f4..299ea4e45f 100644
--- a/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
+++ b/testlib/src/test/java/com/diffplug/spotless/generic/IdeaStepTest.java
@@ -79,7 +79,7 @@ void formattingsWorkWithDefaultParameters() throws Exception {
 	}
 
 	@Test
-	void formattingsWithOutDefaultDoesNothing() throws Exception {
+	void formattingsWithoutDefaultDoesNothing() throws Exception {
 		File dirtyFile = newFile("dirty.java");
 		String dirtyJava = ResourceHarness.getTestResource("java/idea/full.dirty.java");
 		Files.write(dirtyJava, dirtyFile, StandardCharsets.UTF_8);

From 9ed6289f33bad4982fa4769ec1573f008890969f Mon Sep 17 00:00:00 2001
From: Andre Wachsmuth 
Date: Tue, 1 Jul 2025 12:57:15 +0200
Subject: [PATCH 153/210] Remove BiomeFlavor enum

We only support biome (not rome) anymore, so the enum serves no purpose.
---
 .../biome/BiomeExecutableDownloader.java      |  8 +--
 .../{BiomeFlavor.java => BiomeSettings.java}  | 45 ++++++----------
 .../diffplug/spotless/biome/BiomeStep.java    | 36 +++++--------
 .../gradle/spotless/BiomeStepConfig.java      | 18 ++-----
 .../gradle/spotless/CssExtension.java         |  4 +-
 .../gradle/spotless/FormatExtension.java      |  5 +-
 .../gradle/spotless/JavascriptExtension.java  |  3 +-
 .../gradle/spotless/JsonExtension.java        |  3 +-
 .../gradle/spotless/TypescriptExtension.java  |  3 +-
 .../diffplug/spotless/maven/css/BiomeCss.java |  3 +-
 .../spotless/maven/generic/AbstractBiome.java | 18 +++----
 .../spotless/maven/generic/Biome.java         |  4 +-
 .../spotless/maven/javascript/BiomeJs.java    |  3 +-
 .../spotless/maven/json/BiomeJson.java        |  3 +-
 .../spotless/maven/typescript/BiomeTs.java    |  3 +-
 .../spotless/biome/BiomeStepTest.java         | 54 +++++++++----------
 16 files changed, 80 insertions(+), 133 deletions(-)
 rename lib/src/main/java/com/diffplug/spotless/biome/{BiomeFlavor.java => BiomeSettings.java} (53%)

diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java
index c01d11a20c..2bf02f3efb 100644
--- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java
+++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java
@@ -71,17 +71,13 @@ final class BiomeExecutableDownloader {
 
 	private final Path downloadDir;
 
-	private final BiomeFlavor flavor;
-
 	/**
 	 * Creates a new downloader for the Biome executable. The executable files are
 	 * stored in the given download directory.
 	 *
-	 * @param flavor Flavor of Biome to use.
 	 * @param downloadDir Directory where to store the downloaded executable.
 	 */
-	public BiomeExecutableDownloader(BiomeFlavor flavor, Path downloadDir) {
-		this.flavor = flavor;
+	public BiomeExecutableDownloader(Path downloadDir) {
 		this.downloadDir = downloadDir;
 	}
 
@@ -240,7 +236,7 @@ private String computeChecksum(Path file, String algorithm) throws IOException {
 	 * Finds the code name for the given operating system used by the Biome
 	 * executable download URL.
 	 *
-	 * @param os Desired operating system.
+	 * @param architecture Desired operating system architecture.
 	 * @return Code name for the Biome download URL.
 	 * @throws IOException When the given OS is not supported by Biome.
 	 */
diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeFlavor.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java
similarity index 53%
rename from lib/src/main/java/com/diffplug/spotless/biome/BiomeFlavor.java
rename to lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java
index bcb065edea..c2f7028bc5 100644
--- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeFlavor.java
+++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java
@@ -16,52 +16,38 @@
 package com.diffplug.spotless.biome;
 
 /**
- * The flavor of Biome to use. Exists for compatibility reason, may be removed
- * shortly.
- * 

- * Will be removed once the old Rome project is not supported anymore. + * Settings and constants for Biome to use. */ -public enum BiomeFlavor { - /** The new forked Biome project. */ - BIOME("biome", "1.2.0", "biome.json", "biome-%s-%s-%s", - "https://github.com/biomejs/biome/releases/download/cli%%2Fv%s/biome-%s"); +public final class BiomeSettings { + private final static String configName= "biome.json"; + private final static String defaultVersion = "1.2.0"; + private final static String downloadFilePattern = "biome-%s-%s-%s"; + private final static String shortName = "biome"; + private final static String urlPattern = "https://github.com/biomejs/biome/releases/download/cli%%2Fv%s/biome-%s"; - private final String configName; - private final String defaultVersion; - private final String downloadFilePattern; - private final String shortName; - private final String urlPattern; - - BiomeFlavor(String shortName, String defaultVersion, String configName, String downloadFilePattern, - String urlPattern) { - this.shortName = shortName; - this.defaultVersion = defaultVersion; - this.configName = configName; - this.downloadFilePattern = downloadFilePattern; - this.urlPattern = urlPattern; - } + private BiomeSettings() {} /** * @return The name of the default config file. */ - public String configName() { + public static String configName() { return configName; } /** * @return Default version to use when no version was set explicitly. */ - public String defaultVersion() { + public static String defaultVersion() { return defaultVersion; } /** * @return The pattern for {@link String#format(String, Object...) * String.format()} for the file name of a Biome executable for a - * certain version and architecure. The first parameter is the platform, + * certain version and architecture. The first parameter is the platform, * the second is the OS, the third is the architecture. */ - public String getDownloadFilePattern() { + public static String getDownloadFilePattern() { return downloadFilePattern; } @@ -71,15 +57,14 @@ public String getDownloadFilePattern() { * The first parameter is the version, the second parameter is the OS / * platform. */ - public String getUrlPattern() { + public static String getUrlPattern() { return urlPattern; } /** - * @return The short name of this flavor, i.e. rome or - * biome. + * @return The short name of this flavor, e.g. biome. */ - public String shortName() { + public static String shortName() { return shortName; } } diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java index 09a42ae4a0..b95068de70 100644 --- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java +++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java @@ -72,12 +72,6 @@ public class BiomeStep { */ private String language; - /** - * Biome flavor to use. Will be removed once we stop supporting the deprecated Rome project. - */ - @Deprecated - private final BiomeFlavor flavor; - /** * Path to the Biome executable. Can be null, but either a path to * the executable of a download directory and version must be given. The path @@ -103,32 +97,30 @@ public class BiomeStep { * @return The name of this format step, i.e. biome or rome. */ public String name() { - return flavor.shortName(); + return BiomeSettings.shortName(); } /** * Creates a Biome step that format code by downloading to the given Biome * version. The executable is downloaded from the network. * - * @param flavor Flavor of Biome to use. * @param version Version of the Biome executable to download. * @param downloadDir Directory where to place the downloaded executable. * @return A new Biome step that download the executable from the network. */ - public static BiomeStep withExeDownload(BiomeFlavor flavor, String version, String downloadDir) { - return new BiomeStep(flavor, version, null, downloadDir); + public static BiomeStep withExeDownload(String version, String downloadDir) { + return new BiomeStep(version, null, downloadDir); } /** * Creates a Biome step that formats code by delegating to the Biome executable * located at the given path. * - * @param flavor Flavor of Biome to use. * @param pathToExe Path to the Biome executable to use. * @return A new Biome step that format with the given executable. */ - public static BiomeStep withExePath(BiomeFlavor flavor, String pathToExe) { - return new BiomeStep(flavor, null, pathToExe, null); + public static BiomeStep withExePath(String pathToExe) { + return new BiomeStep(null, pathToExe, null); } /** @@ -156,8 +148,8 @@ private static void attemptToAddPosixPermission(Path file, PosixFilePermission p * * @return The default version for Biome. */ - private static String defaultVersion(BiomeFlavor flavor) { - return flavor.defaultVersion(); + private static String defaultVersion() { + return BiomeSettings.defaultVersion(); } /** @@ -200,12 +192,12 @@ private static String resolveNameAgainstPath(String name) throws IOException, In * Checks the Biome config path. When the config path does not exist or when it * does not contain a file named {@code biome.json}, an error is thrown. */ - private static void validateBiomeConfigPath(BiomeFlavor flavor, String configPath) { + private static void validateBiomeConfigPath(String configPath) { if (configPath == null) { return; } var path = Paths.get(configPath); - var config = path.resolve(flavor.configName()); + var config = path.resolve(BiomeSettings.configName()); if (!Files.exists(path)) { throw new IllegalArgumentException("Biome config directory does not exist: " + path); } @@ -227,14 +219,12 @@ private static void validateBiomeExecutable(String resolvedPathToExe) { /** * Creates a new Biome step with the configuration from the given builder. * - * @param flavor Flavor of Biome to use. * @param version Version of the Biome executable to download. * @param pathToExe Path to the Biome executable to use. * @param downloadDir Directory where to place the downloaded executable. */ - private BiomeStep(BiomeFlavor flavor, String version, String pathToExe, String downloadDir) { - this.flavor = flavor; - this.version = version != null && !version.isBlank() ? version : defaultVersion(flavor); + private BiomeStep(String version, String pathToExe, String downloadDir) { + this.version = version != null && !version.isBlank() ? version : defaultVersion(); this.pathToExe = pathToExe; this.downloadDir = downloadDir; } @@ -306,7 +296,7 @@ public BiomeStep withLanguage(String language) { private State createState() throws IOException, InterruptedException { var resolvedPathToExe = resolveExe(); validateBiomeExecutable(resolvedPathToExe); - validateBiomeConfigPath(flavor, configPath); + validateBiomeConfigPath(configPath); logger.debug("Using Biome executable located at '{}'", resolvedPathToExe); var exeSignature = FileSignature.signAsList(Collections.singleton(new File(resolvedPathToExe))); makeExecutable(resolvedPathToExe); @@ -337,7 +327,7 @@ private String resolveExe() throws IOException, InterruptedException { return pathToExe; } } else { - var downloader = new BiomeExecutableDownloader(flavor, Paths.get(downloadDir)); + var downloader = new BiomeExecutableDownloader(Paths.get(downloadDir)); var downloaded = downloader.ensureDownloaded(version).toString(); makeExecutable(downloaded); return downloaded; diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java index 776c844d9b..992b5b393f 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java @@ -23,10 +23,10 @@ import javax.annotation.Nullable; +import com.diffplug.spotless.biome.BiomeSettings; import org.gradle.api.Project; import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.biome.BiomeStep; public abstract class BiomeStepConfig> { @@ -48,12 +48,6 @@ public abstract class BiomeStepConfig> { @Nullable private Object downloadDir; - /** - * The flavor of Biome to use. Will be removed when we stop support the - * deprecated Rome project. - */ - private final BiomeFlavor flavor; - /** * Optional path to the Biome executable. Either a version or a * pathToExe should be specified. When not given, an attempt is @@ -93,11 +87,9 @@ public abstract class BiomeStepConfig> { @Nullable private String version; - protected BiomeStepConfig(Project project, Consumer replaceStep, BiomeFlavor flavor, - String version) { + protected BiomeStepConfig(Project project, Consumer replaceStep, String version) { this.project = requireNonNull(project); this.replaceStep = requireNonNull(replaceStep); - this.flavor = flavor; this.version = version; } @@ -224,10 +216,10 @@ private File findDataDir() { private BiomeStep newBuilder() { if (pathToExe != null) { var resolvedPathToExe = resolvePathToExe(); - return BiomeStep.withExePath(flavor, resolvedPathToExe); + return BiomeStep.withExePath(resolvedPathToExe); } else { var downloadDir = resolveDownloadDir(); - return BiomeStep.withExeDownload(flavor, version, downloadDir); + return BiomeStep.withExeDownload(version, downloadDir); } } @@ -260,7 +252,7 @@ private String resolveDownloadDir() { if (downloadDir != null) { return project.file(downloadDir).toString(); } else { - return findDataDir().toPath().resolve(flavor.shortName()).toString(); + return findDataDir().toPath().resolve(BiomeSettings.shortName()).toString(); } } } diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java index f3dd15ccb3..f1e844e153 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java @@ -17,8 +17,6 @@ import javax.inject.Inject; -import com.diffplug.spotless.biome.BiomeFlavor; - /** Gradle step for formatting CSS files. */ public class CssExtension extends FormatExtension { private static final String CSS_FILE_EXTENSION = "**/*.css"; @@ -73,7 +71,7 @@ public class BiomeCss extends BiomeStepConfig { * @param version Biome version to use. */ public BiomeCss(String version) { - super(getProject(), CssExtension.this::replaceStep, BiomeFlavor.BIOME, version); + super(getProject(), CssExtension.this::replaceStep, version); } @Override 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 40069850c5..d0ea378958 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 @@ -59,7 +59,6 @@ import com.diffplug.spotless.OnMatch; import com.diffplug.spotless.Provisioner; import com.diffplug.spotless.SerializedFunction; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.cpp.ClangFormatStep; import com.diffplug.spotless.extra.EclipseBasedStepBuilder; import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep; @@ -825,13 +824,13 @@ public class BiomeGeneric extends BiomeStepConfig { * null. */ public BiomeGeneric(String version) { - super(getProject(), FormatExtension.this::replaceStep, BiomeFlavor.BIOME, version); + super(getProject(), FormatExtension.this::replaceStep, version); } /** * Sets the language (syntax) of the input files to format. When * null or the empty string, the language is detected automatically - * from the file name. Currently the following languages are supported by Biome: + * from the file name. Currently, the following languages are supported by Biome: *

    *
  • js (JavaScript)
  • *
  • jsx (JavaScript + JSX)
  • diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java index 5532045bc2..6d329cfb51 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java @@ -30,7 +30,6 @@ import com.diffplug.common.collect.ImmutableList; import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.npm.EslintConfig; import com.diffplug.spotless.npm.EslintFormatterStep; import com.diffplug.spotless.npm.NpmPathResolver; @@ -169,7 +168,7 @@ public class BiomeJs extends BiomeStepConfig { * @param version Biome version to use. */ public BiomeJs(String version) { - super(getProject(), JavascriptExtension.this::replaceStep, BiomeFlavor.BIOME, version); + super(getProject(), JavascriptExtension.this::replaceStep, version); } @Override diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java index 47db97b2e6..063e1d8ae9 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java @@ -22,7 +22,6 @@ import javax.inject.Inject; import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.json.JacksonJsonConfig; import com.diffplug.spotless.json.JacksonJsonStep; import com.diffplug.spotless.json.JsonPatchStep; @@ -192,7 +191,7 @@ public class BiomeJson extends BiomeStepConfig { * @param version Biome version to use. */ public BiomeJson(String version) { - super(getProject(), JsonExtension.this::replaceStep, BiomeFlavor.BIOME, version); + super(getProject(), JsonExtension.this::replaceStep, version); } @Override diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java index 39e050d51e..e227cfb790 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java @@ -30,7 +30,6 @@ import com.diffplug.gradle.spotless.JavascriptExtension.EslintBaseConfig; import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.npm.EslintConfig; import com.diffplug.spotless.npm.EslintFormatterStep; import com.diffplug.spotless.npm.EslintTypescriptConfig; @@ -254,7 +253,7 @@ public class BiomeTs extends BiomeStepConfig { * @param version Biome version to use. */ public BiomeTs(String version) { - super(getProject(), TypescriptExtension.this::replaceStep, BiomeFlavor.BIOME, version); + super(getProject(), TypescriptExtension.this::replaceStep, version); } @Override diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.java index ca96f47cfe..dc45ecbead 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.java @@ -15,7 +15,6 @@ */ package com.diffplug.spotless.maven.css; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.maven.generic.AbstractBiome; /** @@ -23,7 +22,7 @@ */ public class BiomeCss extends AbstractBiome { public BiomeCss() { - super(BiomeFlavor.BIOME); + super(); } @Override diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java index f1473adf45..1ca39af989 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java @@ -17,28 +17,24 @@ import java.nio.file.Paths; +import com.diffplug.spotless.biome.BiomeSettings; import org.apache.maven.plugins.annotations.Parameter; import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.biome.BiomeStep; import com.diffplug.spotless.maven.FormatterStepConfig; import com.diffplug.spotless.maven.FormatterStepFactory; /** - * Factory for creating the Biome formatter step that can format format code in - * various types of language with Biome. Currently Biome supports JavaScript, + * Factory for creating the Biome formatter step that can format code in + * various types of language with Biome. Currently, Biome supports JavaScript, * TypeScript, JSX, TSX, and JSON. See also https://github.com/biomejs/biome. It * delegates to the Biome CLI executable. */ public abstract class AbstractBiome implements FormatterStepFactory { - /** Biome flavor to use. */ - private BiomeFlavor flavor; - protected AbstractBiome(BiomeFlavor flavor) { - this.flavor = flavor; - } + protected AbstractBiome() {} /** * Optional path to the directory with configuration file for Biome. The file @@ -138,10 +134,10 @@ public FormatterStep newFormatterStep(FormatterStepConfig config) { private BiomeStep newBuilder(FormatterStepConfig config) { if (pathToExe != null) { var resolvedExePath = resolveExePath(config); - return BiomeStep.withExePath(flavor, resolvedExePath); + return BiomeStep.withExePath(resolvedExePath); } else { var downloadDir = resolveDownloadDir(config); - return BiomeStep.withExeDownload(flavor, version, downloadDir); + return BiomeStep.withExeDownload(version, downloadDir); } } @@ -190,7 +186,7 @@ private String resolveDownloadDir(FormatterStepConfig config) { if (downloadDir != null && !downloadDir.isBlank()) { return fileLocator.getBaseDir().toPath().resolve(downloadDir).toAbsolutePath().toString(); } else { - return fileLocator.getDataDir().toPath().resolve(flavor.shortName()).toString(); + return fileLocator.getDataDir().toPath().resolve(BiomeSettings.shortName()).toString(); } } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.java index 99cede1065..873dc1506a 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.java @@ -17,8 +17,6 @@ import org.apache.maven.plugins.annotations.Parameter; -import com.diffplug.spotless.biome.BiomeFlavor; - /** * Generic Biome formatter step that detects the language of the input file from * the file name. It should be specified as a formatter step for a generic @@ -26,7 +24,7 @@ */ public class Biome extends AbstractBiome { public Biome() { - super(BiomeFlavor.BIOME); + super(); } /** diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.java index b610a5b63b..82abf05592 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.java @@ -15,7 +15,6 @@ */ package com.diffplug.spotless.maven.javascript; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.maven.generic.AbstractBiome; /** @@ -23,7 +22,7 @@ */ public class BiomeJs extends AbstractBiome { public BiomeJs() { - super(BiomeFlavor.BIOME); + super(); } @Override diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.java index f52b490d69..046cc51e1d 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.java @@ -15,7 +15,6 @@ */ package com.diffplug.spotless.maven.json; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.maven.generic.AbstractBiome; /** @@ -23,7 +22,7 @@ */ public class BiomeJson extends AbstractBiome { public BiomeJson() { - super(BiomeFlavor.BIOME); + super(); } @Override diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.java index e9f84d9edb..385dc3bb31 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.java @@ -15,7 +15,6 @@ */ package com.diffplug.spotless.maven.typescript; -import com.diffplug.spotless.biome.BiomeFlavor; import com.diffplug.spotless.maven.generic.AbstractBiome; /** @@ -23,7 +22,7 @@ */ public class BiomeTs extends AbstractBiome { public BiomeTs() { - super(BiomeFlavor.BIOME); + super(); } @Override diff --git a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java index 87c4d6e91f..462dbaed4f 100644 --- a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java @@ -53,7 +53,7 @@ class AutoDetectLanguage { */ @Test void testAutoDetectCjs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.cjs", "biome/js/fileAfter.cjs"); } @@ -64,7 +64,7 @@ void testAutoDetectCjs() { */ @Test void testAutoDetectCts() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.cts", "biome/ts/fileAfter.cts"); } @@ -76,7 +76,7 @@ void testAutoDetectCts() { @Test void testAutoDetectCssExperimental() { var path = createBiomeConfig("biome/config/css-enabled.json"); - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.8.3", downloadDir.toString()).withConfigPath(path).create(); + var step = BiomeStep.withExeDownload("1.8.3", downloadDir.toString()).withConfigPath(path).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -87,7 +87,7 @@ void testAutoDetectCssExperimental() { */ @Test void testAutoDetectCssStable() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.9.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.9.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -98,7 +98,7 @@ void testAutoDetectCssStable() { */ @Test void testAutoDetectJs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.js", "biome/js/fileAfter.js"); } @@ -109,7 +109,7 @@ void testAutoDetectJs() { */ @Test void testAutoDetectJson() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/json/fileBefore.json", "biome/json/fileAfter.json"); } @@ -120,7 +120,7 @@ void testAutoDetectJson() { */ @Test void testAutoDetectJsonc() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/jsonc/fileBefore.jsonc", "biome/jsonc/fileAfter.jsonc"); } @@ -131,7 +131,7 @@ void testAutoDetectJsonc() { */ @Test void testAutoDetectJsx() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.jsx", "biome/js/fileAfter.jsx"); } @@ -142,7 +142,7 @@ void testAutoDetectJsx() { */ @Test void testAutoDetectMjs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.mjs", "biome/js/fileAfter.mjs"); } @@ -153,7 +153,7 @@ void testAutoDetectMjs() { */ @Test void testAutoDetectMts() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.mts", "biome/ts/fileAfter.mts"); } @@ -164,7 +164,7 @@ void testAutoDetectMts() { */ @Test void testAutoDetectTs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.ts", "biome/ts/fileAfter.ts"); } @@ -175,7 +175,7 @@ void testAutoDetectTs() { */ @Test void testAutoDetectTsx() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.tsx", "biome/ts/fileAfter.tsx"); } @@ -188,7 +188,7 @@ void testAutoDetectTsx() { */ @Test void preservesIgnoredFiles() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.5.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.5.0", downloadDir.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/json/package.json", "biome/json/packageAfter.json"); } @@ -202,7 +202,7 @@ class ConfigFile { @Test void testLineWidth120() { var path = createBiomeConfig("biome/config/line-width-120.json"); - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withConfigPath(path).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withConfigPath(path).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/longLineBefore.js", "biome/js/longLineAfter120.js"); } @@ -213,7 +213,7 @@ void testLineWidth120() { @Test void testLineWidth80() { var path = createBiomeConfig("biome/config/line-width-80.json"); - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withConfigPath(path).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withConfigPath(path).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/longLineBefore.js", "biome/js/longLineAfter80.js"); } @@ -231,7 +231,7 @@ class ExplicitLanguage { */ @Test void testSetLanguageCjs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("js").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("js").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.cjs", "biome/js/fileAfter.cjs"); } @@ -243,7 +243,7 @@ void testSetLanguageCjs() { @Test void testSetLanguageCssExperimental() { var path = createBiomeConfig("biome/config/css-enabled.json"); - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.8.3", downloadDir.toString()).withConfigPath(path).withLanguage("css").create(); + var step = BiomeStep.withExeDownload("1.8.3", downloadDir.toString()).withConfigPath(path).withLanguage("css").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -254,7 +254,7 @@ void testSetLanguageCssExperimental() { */ @Test void testSetLanguageCssStable() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.9.0", downloadDir.toString()).withLanguage("css").create(); + var step = BiomeStep.withExeDownload("1.9.0", downloadDir.toString()).withLanguage("css").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -265,7 +265,7 @@ void testSetLanguageCssStable() { */ @Test void testSetLanguageCts() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("ts").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("ts").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.cts", "biome/ts/fileAfter.cts"); } @@ -276,7 +276,7 @@ void testSetLanguageCts() { */ @Test void testSetLanguageJs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("js").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("js").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.js", "biome/js/fileAfter.js"); } @@ -287,7 +287,7 @@ void testSetLanguageJs() { */ @Test void testSetLanguageJson() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("json").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("json").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/json/fileBefore.json", "biome/json/fileAfter.json"); } @@ -298,7 +298,7 @@ void testSetLanguageJson() { */ @Test void testSetLanguageJsonc() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("jsonc").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("jsonc").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/jsonc/fileBefore.jsonc", "biome/jsonc/fileAfter.jsonc"); } @@ -309,7 +309,7 @@ void testSetLanguageJsonc() { */ @Test void testSetLanguageJsx() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("jsx").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("jsx").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.jsx", "biome/js/fileAfter.jsx"); } @@ -320,7 +320,7 @@ void testSetLanguageJsx() { */ @Test void testSetLanguageMjs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("js").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("js").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.mjs", "biome/js/fileAfter.mjs"); } @@ -331,7 +331,7 @@ void testSetLanguageMjs() { */ @Test void testSetLanguageMts() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("ts").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("ts").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.mts", "biome/ts/fileAfter.mts"); } @@ -342,7 +342,7 @@ void testSetLanguageMts() { */ @Test void testSetLanguageTs() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("ts").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("ts").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.ts", "biome/ts/fileAfter.ts"); } @@ -353,7 +353,7 @@ void testSetLanguageTs() { */ @Test void testSetLanguageTsx() { - var step = BiomeStep.withExeDownload(BiomeFlavor.BIOME, "1.2.0", downloadDir.toString()).withLanguage("tsx").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("tsx").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.tsx", "biome/ts/fileAfter.tsx"); } From b5f1251e8f55d42fe2a81f01a7cf945293d16b2d Mon Sep 17 00:00:00 2001 From: Andre Wachsmuth Date: Tue, 1 Jul 2025 13:22:05 +0200 Subject: [PATCH 154/210] Ensure support for version 2.x of biome The download path changed slightly for version 2.x. Add tests for version 2.x. --- .../biome/BiomeExecutableDownloader.java | 4 +-- .../spotless/biome/BiomeSettings.java | 27 +++++++++++-------- .../gradle/spotless/BiomeIntegrationTest.java | 25 +++++++++++++++++ .../spotless/maven/biome/BiomeMavenTest.java | 13 +++++++++ .../spotless/biome/BiomeStepTest.java | 26 ++++++++++++++++++ 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java index 2bf02f3efb..3b1e6cec37 100644 --- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java +++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java @@ -278,7 +278,7 @@ private String getDownloadUrl(String version, Platform platform) throws IOExcept var architectureCodeName = getArchitectureCodeName(platform.getArchitecture()); var extension = getDownloadUrlExtension(platform.getOs()); var platformString = String.format(PLATFORM_PATTERN, osCodeName, architectureCodeName, extension); - return String.format(flavor.getUrlPattern(), version, platformString); + return String.format(BiomeSettings.getUrlPattern(version), version, platformString); } /** @@ -313,7 +313,7 @@ private String getDownloadUrlExtension(OS os) throws IOException { private Path getExecutablePath(String version, Platform platform) { var os = platform.getOs().name().toLowerCase(Locale.ROOT); var arch = platform.getArchitecture().name().toLowerCase(Locale.ROOT); - var fileName = String.format(flavor.getDownloadFilePattern(), os, arch, version); + var fileName = String.format(BiomeSettings.getDownloadFilePattern(), os, arch, version); return downloadDir.resolve(fileName); } diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java index c2f7028bc5..99f48730e1 100644 --- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java +++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java @@ -19,11 +19,12 @@ * Settings and constants for Biome to use. */ public final class BiomeSettings { - private final static String configName= "biome.json"; - private final static String defaultVersion = "1.2.0"; - private final static String downloadFilePattern = "biome-%s-%s-%s"; - private final static String shortName = "biome"; - private final static String urlPattern = "https://github.com/biomejs/biome/releases/download/cli%%2Fv%s/biome-%s"; + private final static String CONFIG_NAME = "biome.json"; + private final static String DEFAULT_VERSION = "1.2.0"; + private final static String DOWNLOAD_FILE_PATTERN = "biome-%s-%s-%s"; + private final static String SHORT_NAME = "biome"; + private final static String URL_PATTERN_1X = "https://github.com/biomejs/biome/releases/download/cli%%2Fv%s/biome-%s"; + private final static String URL_PATTERN_2X = "https://github.com/biomejs/biome/releases/download/%%40biomejs%%2Fbiome%%40%s/biome-%s"; private BiomeSettings() {} @@ -31,14 +32,14 @@ private BiomeSettings() {} * @return The name of the default config file. */ public static String configName() { - return configName; + return CONFIG_NAME; } /** * @return Default version to use when no version was set explicitly. */ public static String defaultVersion() { - return defaultVersion; + return DEFAULT_VERSION; } /** @@ -48,23 +49,27 @@ public static String defaultVersion() { * the second is the OS, the third is the architecture. */ public static String getDownloadFilePattern() { - return downloadFilePattern; + return DOWNLOAD_FILE_PATTERN; } /** + * @param version The biome version for which to get the URL pattern, e.g. 1.2.0 or 2.0.6. * @return The pattern for {@link String#format(String, Object...) * String.format()} for the URL where the executables can be downloaded. * The first parameter is the version, the second parameter is the OS / * platform. */ - public static String getUrlPattern() { - return urlPattern; + public static String getUrlPattern(String version) { + if (version != null && version.startsWith("1.")) { + return URL_PATTERN_1X; + } + return URL_PATTERN_2X; } /** * @return The short name of this flavor, e.g. biome. */ public static String shortName() { - return shortName; + return SHORT_NAME; } } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java index 0a8dfe7022..689a0cf40e 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java @@ -424,4 +424,29 @@ void preservesIgnoredFiles() throws Exception { assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); assertFile("package.json").sameAsResource("biome/json/packageAfter.json"); } + + /** + * Tests that the Gradle plugin works with version 2.x of biome. + * + * @throws Exception When a test failure occurs. + */ + @Test + void version2x() throws Exception { + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "spotless {", + " format 'mybiome', {", + " target '**/*.js'", + " biome('2.0.6')", + " }", + "}"); + setFile("biome_test.js").toResource("biome/js/fileBefore.js"); + + var spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertFile("biome_test.js").sameAsResource("biome/js/fileAfter.js"); + } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java index 5bb7424ef9..1c40393935 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java @@ -248,4 +248,17 @@ void preservesIgnoredFiles() throws Exception { mavenRunner().withArguments("spotless:apply").runNoError(); assertFile("package.json").sameAsResource("biome/json/packageAfter.json"); } + + /** + * Tests that the Maven plugin works with version 2.x of biome. + * + * @throws Exception When a test failure occurs. + */ + @Test + void version2X() throws Exception { + writePomWithBiomeSteps("**/*.js", "2.0.6"); + setFile("biome_test.js").toResource("biome/js/fileBefore.js"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile("biome_test.js").sameAsResource("biome/js/fileAfter.js"); + } } diff --git a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java index 462dbaed4f..6500906251 100644 --- a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java @@ -194,6 +194,32 @@ void preservesIgnoredFiles() { } } + /** + * Tests for the different biome versions. + */ + @Nested + class BiomeVersion { + /** + * Basic test that biome 1.x works. + */ + @Test + void test1x() { + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); + var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); + stepHarness.testResource("biome/js/fileBefore.cjs", "biome/js/fileAfter.cjs"); + } + + /** + * Basic test that biome 2.x works. + */ + @Test + void test2x() { + var step = BiomeStep.withExeDownload("2.0.6", downloadDir).create(); + var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); + stepHarness.testResource("biome/js/fileBefore.cjs", "biome/js/fileAfter.cjs"); + } + } + @Nested class ConfigFile { /** From a40ccc1790068e0b12b3132a6e443657031796fd Mon Sep 17 00:00:00 2001 From: Andre Wachsmuth Date: Tue, 1 Jul 2025 13:43:15 +0200 Subject: [PATCH 155/210] Run formatter --- .../biome/BiomeExecutableDownloader.java | 2 +- .../spotless/biome/BiomeSettings.java | 2 +- .../diffplug/spotless/biome/BiomeStep.java | 2 +- .../gradle/spotless/BiomeStepConfig.java | 16 +++++-------- .../gradle/spotless/CssExtension.java | 2 +- .../gradle/spotless/FormatExtension.java | 24 +++++++------------ .../gradle/spotless/JavascriptExtension.java | 8 +++---- .../gradle/spotless/JsonExtension.java | 2 +- .../gradle/spotless/TypescriptExtension.java | 11 ++++----- .../gradle/spotless/BiomeIntegrationTest.java | 2 +- .../diffplug/spotless/maven/css/BiomeCss.java | 2 +- .../spotless/maven/generic/AbstractBiome.java | 4 ++-- .../spotless/maven/generic/Biome.java | 2 +- .../spotless/maven/javascript/BiomeJs.java | 2 +- .../spotless/maven/json/BiomeJson.java | 2 +- .../spotless/maven/typescript/BiomeTs.java | 2 +- .../spotless/maven/biome/BiomeMavenTest.java | 2 +- .../spotless/biome/BiomeStepTest.java | 2 +- 18 files changed, 36 insertions(+), 53 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java index 3b1e6cec37..5512dd7c4c 100644 --- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.java +++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeExecutableDownloader.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. diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java index 99f48730e1..8bef764ba1 100644 --- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java +++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java b/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java index b95068de70..6993fcfaaf 100644 --- a/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.java +++ b/lib/src/main/java/com/diffplug/spotless/biome/BiomeStep.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. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java index 992b5b393f..49aeb28fc0 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,10 +23,10 @@ import javax.annotation.Nullable; -import com.diffplug.spotless.biome.BiomeSettings; import org.gradle.api.Project; import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.biome.BiomeSettings; import com.diffplug.spotless.biome.BiomeStep; public abstract class BiomeStepConfig> { @@ -36,8 +36,7 @@ public abstract class BiomeStepConfig> { * configuration is used. If this is a relative path, it is resolved against the * project's base directory. */ - @Nullable - private Object configPath; + @Nullable private Object configPath; /** * Optional directory where the downloaded Biome executable is placed. If this @@ -45,8 +44,7 @@ public abstract class BiomeStepConfig> { * Defaults to * ~/.m2/repository/com/diffplug/spotless/spotless-data/biome. */ - @Nullable - private Object downloadDir; + @Nullable private Object downloadDir; /** * Optional path to the Biome executable. Either a version or a @@ -63,8 +61,7 @@ public abstract class BiomeStepConfig> { * ./executable-name if you want to use an executable in the * project's base directory. */ - @Nullable - private Object pathToExe; + @Nullable private Object pathToExe; /** * A reference to the Gradle project for which spotless is executed. @@ -84,8 +81,7 @@ public abstract class BiomeStepConfig> { * version explicitly. This parameter is ignored when you specify a * pathToExe explicitly. */ - @Nullable - private String version; + @Nullable private String version; protected BiomeStepConfig(Project project, Consumer replaceStep, String version) { this.project = requireNonNull(project); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java index f1e844e153..2491faa04e 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 DiffPlug + * Copyright 2024-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. 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 d0ea378958..9e20364768 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 @@ -216,8 +216,7 @@ public void encoding(String charset) { protected FileCollection target, targetExclude; /** The value from which files will be excluded if their content contain it. */ - @Nullable - protected String targetExcludeContentPattern = null; + @Nullable protected String targetExcludeContentPattern = null; protected boolean isLicenseHeaderStep(FormatterStep formatterStep) { String formatterStepName = formatterStep.getName(); @@ -685,17 +684,13 @@ public abstract static class NpmStepConfig> { public static final String SPOTLESS_NPM_INSTALL_CACHE_DEFAULT_NAME = "spotless-npm-install-cache"; - @Nullable - protected Object npmFile; + @Nullable protected Object npmFile; - @Nullable - protected Object nodeFile; + @Nullable protected Object nodeFile; - @Nullable - protected Object npmInstallCache; + @Nullable protected Object npmInstallCache; - @Nullable - protected Object npmrcFile; + @Nullable protected Object npmrcFile; protected Project project; @@ -769,11 +764,9 @@ protected void replaceStep() { public class PrettierConfig extends NpmStepConfig { - @Nullable - Object prettierConfigFile; + @Nullable Object prettierConfigFile; - @Nullable - Map prettierConfig; + @Nullable Map prettierConfig; final Map devDependencies; @@ -813,8 +806,7 @@ protected FormatterStep createStep() { * format{ ... }. */ public class BiomeGeneric extends BiomeStepConfig { - @Nullable - String language; + @Nullable String language; /** * Creates a new Biome config that downloads the Biome executable for the given diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java index 6d329cfb51..043fd8237a 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.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. @@ -62,11 +62,9 @@ public static abstract class EslintBaseConfig> extends NpmStepConfig> { Map devDependencies = new LinkedHashMap<>(); - @Nullable - Object configFilePath = null; + @Nullable Object configFilePath = null; - @Nullable - String configJs = null; + @Nullable String configJs = null; public EslintBaseConfig(Project project, Consumer replaceStep, Map devDependencies) { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java index 063e1d8ae9..df0e5e6061 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.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. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java index e227cfb790..1e7c9efc24 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.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. @@ -72,11 +72,9 @@ public class TypescriptFormatExtension extends NpmStepConfig config = Collections.emptyMap(); - @Nullable - TsConfigFileType configFileType = null; + @Nullable TsConfigFileType configFileType = null; - @Nullable - Object configFilePath = null; + @Nullable Object configFilePath = null; private final Map devDependencies; @@ -197,8 +195,7 @@ public TypescriptEslintConfig eslint(Map devDependencies) { public class TypescriptEslintConfig extends EslintBaseConfig { - @Nullable - Object typescriptConfigFilePath = null; + @Nullable Object typescriptConfigFilePath = null; public TypescriptEslintConfig(Map devDependencies) { super(getProject(), TypescriptExtension.this::replaceStep, devDependencies); diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java index 689a0cf40e..8e4da27e95 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.java index dc45ecbead..77cfebffe2 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/css/BiomeCss.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. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java index 1ca39af989..465965f896 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.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. @@ -17,10 +17,10 @@ import java.nio.file.Paths; -import com.diffplug.spotless.biome.BiomeSettings; import org.apache.maven.plugins.annotations.Parameter; import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.biome.BiomeSettings; import com.diffplug.spotless.biome.BiomeStep; import com.diffplug.spotless.maven.FormatterStepConfig; import com.diffplug.spotless.maven.FormatterStepFactory; diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.java index 873dc1506a..439fe15ab9 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Biome.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. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.java index 82abf05592..a838bacd3e 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/javascript/BiomeJs.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. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.java index 046cc51e1d..67b9f8cd3a 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/json/BiomeJson.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. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.java index 385dc3bb31..2bbae1550a 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/typescript/BiomeTs.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. diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java index 1c40393935..1072a95da8 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java index 6500906251..db6c535835 100644 --- a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From e868b2643bbbdeb3077086deb3754b4be461d8ea Mon Sep 17 00:00:00 2001 From: Andre Wachsmuth Date: Tue, 1 Jul 2025 14:15:43 +0200 Subject: [PATCH 156/210] Add entry to changelog --- CHANGES.md | 3 +++ plugin-gradle/CHANGES.md | 3 +++ plugin-maven/CHANGES.md | 3 +++ 3 files changed, 9 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index ba1e66f1f7..3a6165e509 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Added * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +### Fixed +* Fix biome formatter for new major release 2.x of biome ([#2537](https://github.com/diffplug/spotless/pull/2537)) + ## [3.1.2] - 2025-05-27 ### Fixed * Fix `UnsupportedOperationException` in the Gradle plugin when using `targetExcludeContent[Pattern]` ([#2487](https://github.com/diffplug/spotless/pull/2487)) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index c7fc99944b..be15d11568 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -6,6 +6,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Added * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +### Fixed +* Fix biome formatter for new major release 2.x of biome ([#2537](https://github.com/diffplug/spotless/pull/2537)) + ## [7.0.4] - 2025-05-27 ### Fixed * Fix `UnsupportedOperationException` in the Gradle plugin when using `targetExcludeContent[Pattern]` ([#2487](https://github.com/diffplug/spotless/pull/2487)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 53c6f4b093..b58260e88c 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -6,6 +6,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Added * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +### Fixed +* Fix biome formatter for new major release 2.x of biome ([#2537](https://github.com/diffplug/spotless/pull/2537)) + ## [2.44.5] - 2025-05-27 ### Changed * Bump default `eclipse` version to latest `4.34` -> `4.35`. ([#2458](https://github.com/diffplug/spotless/pull/2458)) From afa0b220660057d52975667a1c3650bc33c45d48 Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 2 Jul 2025 17:06:04 +0800 Subject: [PATCH 157/210] Publish to Central Portal https://central.sonatype.org/news/20250326_ossrh_sunset/ https://github.com/gradle-nexus/publish-plugin?tab=readme-ov-file#publishing-to-maven-central-via-sonatype-central --- .github/workflows/deploy.yml | 8 ++++---- gradle/java-publish.gradle | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ffc164a461..4a4672be17 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,5 +1,5 @@ -# NEXUS_USER -# NEXUS_PASS64 (base64 NOTE: `base64` and `openssl base64` failed, had to use Java +# CENTRAL_PORTAL_USER +# CENTRAL_PORTAL_PASS64 (base64 NOTE: `base64` and `openssl base64` failed, had to use Java # byte[] data = "{{password}}".getBytes(StandardCharsets.UTF_8); # String encoded = new String(Base64.getEncoder().encode(data), StandardCharsets.UTF_8); # System.out.println(encoded); @@ -32,8 +32,8 @@ jobs: contents: write env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ORG_GRADLE_PROJECT_nexus_user: ${{ secrets.NEXUS_USER }} - ORG_GRADLE_PROJECT_nexus_pass64: ${{ secrets.NEXUS_PASS64 }} + ORG_GRADLE_PROJECT_central_portal_user: ${{ secrets.CENTRAL_PORTAL_USER }} + ORG_GRADLE_PROJECT_central_portal_pass64: ${{ secrets.CENTRAL_PORTAL_PASS64 }} ORG_GRADLE_PROJECT_gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }} ORG_GRADLE_PROJECT_gpg_key64: ${{ secrets.GPG_KEY64 }} steps: diff --git a/gradle/java-publish.gradle b/gradle/java-publish.gradle index baad061ea8..2c26a692f3 100644 --- a/gradle/java-publish.gradle +++ b/gradle/java-publish.gradle @@ -11,7 +11,7 @@ def decode64(String varName) { if (project.parent == null) { group = 'com.diffplug.spotless' - def pass = System.env['ORG_GRADLE_PROJECT_nexus_pass64'] + def pass = System.env['ORG_GRADLE_PROJECT_central_portal_pass64'] if (pass != null) { pass = pass.decodeBase64() } @@ -20,10 +20,10 @@ if (project.parent == null) { nexusPublishing { repositories { sonatype { - nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) - snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) - username = System.env['ORG_GRADLE_PROJECT_nexus_user'] - password = decode64('ORG_GRADLE_PROJECT_nexus_pass64') + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) + username = System.env['ORG_GRADLE_PROJECT_central_portal_user'] + password = decode64('ORG_GRADLE_PROJECT_central_portal_pass64') } } } From 2ebe138c9646c0d3f438bd5a1cc69ed0b0f47876 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Thu, 3 Jul 2025 10:16:24 +0200 Subject: [PATCH 158/210] Use palantir-java-format as default formatter in RemoveUnusedImportsStep --- CHANGES.md | 1 + .../java/RemoveUnusedImportsStep.java | 13 ++-- .../java/RemoveUnusedImportsStepTest.java | 73 +++++++++++++++++++ .../java/RemoveUnusedImportsStepTest.java | 33 --------- ...dImportsStep_withGoogleJavaFormatTest.java | 6 +- 5 files changed, 83 insertions(+), 43 deletions(-) create mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java delete mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java diff --git a/CHANGES.md b/CHANGES.md index ba1e66f1f7..8e855c5cbe 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +* Use `palantir-java-format` as default formatter in `RemoveUnusedImportsStep`. ([#2541](https://github.com/diffplug/spotless/pull/2541)) ## [3.1.2] - 2025-05-27 ### Fixed diff --git a/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java b/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java index 753678a86b..fcdb52503b 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.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. @@ -22,12 +22,12 @@ import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.Provisioner; -/** Uses google-java-format or cleanthat.UnnecessaryImport, but only to remove unused imports. */ +/** Uses palantir-java-format or cleanthat.UnnecessaryImport, but only to remove unused imports. */ public class RemoveUnusedImportsStep implements Serializable { private static final long serialVersionUID = 1L; static final String NAME = "removeUnusedImports"; - static final String GJF = "google-java-format"; + static final String DEFAULT_FORMATTER = "palantir-java-format"; static final String CLEANTHAT = "cleanthat-javaparser-unnecessaryimport"; // https://github.com/solven-eu/cleanthat/blob/master/java/src/main/java/eu/solven/cleanthat/engine/java/refactorer/mutators/UnnecessaryImport.java @@ -37,18 +37,17 @@ public class RemoveUnusedImportsStep implements Serializable { private RemoveUnusedImportsStep() {} public static String defaultFormatter() { - return GJF; + return DEFAULT_FORMATTER; } public static FormatterStep create(Provisioner provisioner) { - // The default importRemover is GJF - return create(GJF, provisioner); + return create(DEFAULT_FORMATTER, provisioner); } public static FormatterStep create(String unusedImportRemover, Provisioner provisioner) { Objects.requireNonNull(provisioner, "provisioner"); switch (unusedImportRemover) { - case GJF: + case DEFAULT_FORMATTER: return GoogleJavaFormatStep.createRemoveUnusedImportsOnly(provisioner); case CLEANTHAT: return CleanthatJavaStep.createWithStepName(NAME, CleanthatJavaStep.defaultGroupArtifact(), CleanthatJavaStep.defaultVersion(), "99.9", List.of(CLEANTHAT_MUTATOR), List.of(), false, provisioner); diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java new file mode 100644 index 0000000000..85713423cc --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java @@ -0,0 +1,73 @@ +/* + * 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. + * 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.java; + +import static com.diffplug.spotless.java.RemoveUnusedImportsStep.DEFAULT_FORMATTER; +import static com.diffplug.spotless.java.RemoveUnusedImportsStep.NAME; +import static com.diffplug.spotless.java.RemoveUnusedImportsStep.defaultFormatter; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.maven.MavenIntegrationHarness; + +class RemoveUnusedImportsStepTest extends MavenIntegrationHarness { + + @Test + void testRemoveUnusedImports() throws Exception { + writePomWithJavaSteps(""); + + String path = "src/main/java/test.java"; + setFile(path).toResource("java/removeunusedimports/JavaCodeWithPackageUnformatted.test"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile(path).sameAsResource("java/removeunusedimports/JavaCodeWithPackageFormatted.test"); + } + + @Test + void testDefaults() { + assertEquals("palantir-java-format", defaultFormatter()); + assertEquals("palantir-java-format", DEFAULT_FORMATTER); + assertEquals("removeUnusedImports", NAME); + } + + @Test + void testCreateWithDefaultFormatter() { + assertEquals(NAME, RemoveUnusedImportsStep.create((groupArtifact, version) -> Collections.emptySet()).getName()); + } + + @Test + void testCreateWithPalantirFormatter() { + assertEquals(NAME, RemoveUnusedImportsStep.create("palantir-java-format", (groupArtifact, version) -> Collections.emptySet()).getName()); + } + + @Test + void testCreateWithCleanthatFormatter() { + assertEquals(NAME, RemoveUnusedImportsStep.create("cleanthat-javaparser-unnecessaryimport", (groupArtifact, version) -> Collections.emptySet()).getName()); + } + + @Test + void testCreateWithInvalidFormatter() { + assertThrows(IllegalArgumentException.class, () -> RemoveUnusedImportsStep.create("invalid-formatter", (groupArtifact, version) -> Collections.emptySet())); + } + + @Test + void testCreateWithNullProvisioner() { + assertThrows(NullPointerException.class, () -> RemoveUnusedImportsStep.create("palantir-java-format", null)); + } +} diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java deleted file mode 100644 index 50853ba914..0000000000 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016-2021 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.maven.java; - -import org.junit.jupiter.api.Test; - -import com.diffplug.spotless.maven.MavenIntegrationHarness; - -class RemoveUnusedImportsStepTest extends MavenIntegrationHarness { - - @Test - void testRemoveUnusedInports() throws Exception { - writePomWithJavaSteps(""); - - String path = "src/main/java/test.java"; - setFile(path).toResource("java/removeunusedimports/JavaCodeWithPackageUnformatted.test"); - mavenRunner().withArguments("spotless:apply").runNoError(); - assertFile(path).sameAsResource("java/removeunusedimports/JavaCodeWithPackageFormatted.test"); - } -} diff --git a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java index 44699a8215..766816a659 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -25,7 +25,7 @@ class RemoveUnusedImportsStep_withGoogleJavaFormatTest { @Test void behavior() throws Exception { - FormatterStep step = RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.GJF, TestProvisioner.mavenCentral()); + FormatterStep step = RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.DEFAULT_FORMATTER, TestProvisioner.mavenCentral()); StepHarness.forStep(step) .testResource("java/removeunusedimports/JavaCodeUnformatted.test", "java/removeunusedimports/JavaCodeFormatted.test") .testResource("java/removeunusedimports/JavaCodeWithLicenseUnformatted.test", "java/removeunusedimports/JavaCodeWithLicenseFormatted.test") @@ -48,7 +48,7 @@ protected void setupTest(API api) { @Override protected FormatterStep create() { - return RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.GJF, TestProvisioner.mavenCentral()); + return RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.DEFAULT_FORMATTER, TestProvisioner.mavenCentral()); } }.testEquals(); } From 86c8ee02b6ef623656f49203b216de374829e9ef Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Thu, 3 Jul 2025 10:24:23 +0200 Subject: [PATCH 159/210] feat: Disable `expandEmptyElements`, to avoid empty body warnings --- CHANGES.md | 1 + .../com/diffplug/spotless/pom/SortPomCfg.java | 4 +- .../diffplug/spotless/pom/SortPomCfgTest.java | 177 ++++++++++++++++++ 3 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java diff --git a/CHANGES.md b/CHANGES.md index ba1e66f1f7..90eaa05320 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +* feat: Disable `expandEmptyElements`, to avoid empty body warnings. ([#2520](https://github.com/diffplug/spotless/pull/2520)) ## [3.1.2] - 2025-05-27 ### Fixed diff --git a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java index 08a0308178..db37ae25fd 100644 --- a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java +++ b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 DiffPlug + * Copyright 2021-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ public class SortPomCfg implements Serializable { public String lineSeparator = System.getProperty("line.separator"); - public boolean expandEmptyElements = true; + public boolean expandEmptyElements; public boolean spaceBeforeCloseEmptyElement = false; diff --git a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java new file mode 100644 index 0000000000..b0a336f189 --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java @@ -0,0 +1,177 @@ +/* + * 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.pom; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class SortPomCfgTest { + + @Test + void testDefaultValues() { + SortPomCfg cfg = new SortPomCfg(); + + // Test default values using AssertJ + assertThat(cfg.version).isEqualTo("4.0.0"); + assertThat(cfg.encoding).isEqualTo("UTF-8"); + assertThat(cfg.lineSeparator).isEqualTo(System.getProperty("line.separator")); + assertThat(cfg.expandEmptyElements).isFalse(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isFalse(); + assertThat(cfg.keepBlankLines).isTrue(); + assertThat(cfg.endWithNewline).isTrue(); + assertThat(cfg.nrOfIndentSpace).isEqualTo(2); + assertThat(cfg.indentBlankLines).isFalse(); + assertThat(cfg.indentSchemaLocation).isFalse(); + assertThat(cfg.indentAttribute).isNull(); + assertThat(cfg.predefinedSortOrder).isEqualTo("recommended_2008_06"); + assertThat(cfg.quiet).isFalse(); + assertThat(cfg.sortOrderFile).isNull(); + assertThat(cfg.sortDependencies).isNull(); + assertThat(cfg.sortDependencyManagement).isNull(); + assertThat(cfg.sortDependencyExclusions).isNull(); + assertThat(cfg.sortPlugins).isNull(); + assertThat(cfg.sortProperties).isFalse(); + assertThat(cfg.sortModules).isFalse(); + assertThat(cfg.sortExecutions).isFalse(); + } + + @Test + void testFieldSetters() { + SortPomCfg cfg = new SortPomCfg(); + + // Set all fields + cfg.version = "4.1.0"; + cfg.encoding = "ISO-8859-1"; + cfg.lineSeparator = "\n"; + cfg.expandEmptyElements = true; + cfg.spaceBeforeCloseEmptyElement = true; + cfg.keepBlankLines = false; + cfg.endWithNewline = false; + cfg.nrOfIndentSpace = 4; + cfg.indentBlankLines = true; + cfg.indentSchemaLocation = true; + cfg.indentAttribute = "attribute"; + cfg.predefinedSortOrder = "custom"; + cfg.quiet = true; + cfg.sortOrderFile = "sortOrder.xml"; + cfg.sortDependencies = "groupId,artifactId"; + cfg.sortDependencyManagement = "scope,groupId"; + cfg.sortDependencyExclusions = "artifactId"; + cfg.sortPlugins = "groupId"; + cfg.sortProperties = true; + cfg.sortModules = true; + cfg.sortExecutions = true; + + // Verify all set values with AssertJ + assertThat(cfg.version).isEqualTo("4.1.0"); + assertThat(cfg.encoding).isEqualTo("ISO-8859-1"); + assertThat(cfg.lineSeparator).isEqualTo("\n"); + assertThat(cfg.expandEmptyElements).isTrue(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); + assertThat(cfg.keepBlankLines).isFalse(); + assertThat(cfg.endWithNewline).isFalse(); + assertThat(cfg.nrOfIndentSpace).isEqualTo(4); + assertThat(cfg.indentBlankLines).isTrue(); + assertThat(cfg.indentSchemaLocation).isTrue(); + assertThat(cfg.indentAttribute).isEqualTo("attribute"); + assertThat(cfg.predefinedSortOrder).isEqualTo("custom"); + assertThat(cfg.quiet).isTrue(); + assertThat(cfg.sortOrderFile).isEqualTo("sortOrder.xml"); + assertThat(cfg.sortDependencies).isEqualTo("groupId,artifactId"); + assertThat(cfg.sortDependencyManagement).isEqualTo("scope,groupId"); + assertThat(cfg.sortDependencyExclusions).isEqualTo("artifactId"); + assertThat(cfg.sortPlugins).isEqualTo("groupId"); + assertThat(cfg.sortProperties).isTrue(); + assertThat(cfg.sortModules).isTrue(); + assertThat(cfg.sortExecutions).isTrue(); + } + + @Test + void testNullHandling() { + SortPomCfg cfg = new SortPomCfg(); + + // Set nullable fields to null + cfg.version = null; + cfg.encoding = null; + cfg.lineSeparator = null; + cfg.indentAttribute = null; + cfg.predefinedSortOrder = null; + cfg.sortOrderFile = null; + cfg.sortDependencies = null; + cfg.sortDependencyManagement = null; + cfg.sortDependencyExclusions = null; + cfg.sortPlugins = null; + + // Verify null values with AssertJ + assertThat(cfg.version).isNull(); + assertThat(cfg.encoding).isNull(); + assertThat(cfg.lineSeparator).isNull(); + assertThat(cfg.indentAttribute).isNull(); + assertThat(cfg.predefinedSortOrder).isNull(); + assertThat(cfg.sortOrderFile).isNull(); + assertThat(cfg.sortDependencies).isNull(); + assertThat(cfg.sortDependencyManagement).isNull(); + assertThat(cfg.sortDependencyExclusions).isNull(); + assertThat(cfg.sortPlugins).isNull(); + } + + @Test + void testBooleanFieldsEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Toggle all boolean fields + cfg.expandEmptyElements = !cfg.expandEmptyElements; + cfg.spaceBeforeCloseEmptyElement = !cfg.spaceBeforeCloseEmptyElement; + cfg.keepBlankLines = !cfg.keepBlankLines; + cfg.endWithNewline = !cfg.endWithNewline; + cfg.indentBlankLines = !cfg.indentBlankLines; + cfg.indentSchemaLocation = !cfg.indentSchemaLocation; + cfg.quiet = !cfg.quiet; + cfg.sortProperties = !cfg.sortProperties; + cfg.sortModules = !cfg.sortModules; + cfg.sortExecutions = !cfg.sortExecutions; + + // Verify all boolean fields are toggled + assertThat(cfg.expandEmptyElements).isTrue(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); + assertThat(cfg.keepBlankLines).isFalse(); + assertThat(cfg.endWithNewline).isFalse(); + assertThat(cfg.indentBlankLines).isTrue(); + assertThat(cfg.indentSchemaLocation).isTrue(); + assertThat(cfg.quiet).isTrue(); + assertThat(cfg.sortProperties).isTrue(); + assertThat(cfg.sortModules).isTrue(); + assertThat(cfg.sortExecutions).isTrue(); + } + + @Test + void testNumericFieldEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Test minimum value + cfg.nrOfIndentSpace = 0; + assertThat(cfg.nrOfIndentSpace).isZero(); + + // Test negative value + cfg.nrOfIndentSpace = -1; + assertThat(cfg.nrOfIndentSpace).isNegative(); + + // Test large value + cfg.nrOfIndentSpace = Integer.MAX_VALUE; + assertThat(cfg.nrOfIndentSpace).isEqualTo(Integer.MAX_VALUE); + } +} From f6ebe92ffe47ed2d7cfee4860f6cf282eda447c2 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 30 Jun 2025 07:58:44 +0200 Subject: [PATCH 160/210] chore: bump/replace server deps --- .../com/diffplug/spotless/npm/common-serve.js | 12 +++++++----- .../com/diffplug/spotless/npm/eslint-package.json | 6 +++--- .../com/diffplug/spotless/npm/prettier-package.json | 6 +++--- .../com/diffplug/spotless/npm/tsfmt-package.json | 6 +++--- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js b/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js index 5bfcb35612..291561eda4 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js +++ b/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js @@ -1,6 +1,6 @@ // this file will be glued to the top of the specific xy-serve.js file const debug_serve = false; // set to true for debug log output in node process -const GracefulShutdownManager = require("@moebius/http-graceful-shutdown").GracefulShutdownManager; +const gracefulShutdown = require("http-graceful-shutdown"); const express = require("express"); const app = express(); @@ -48,12 +48,14 @@ var listener = app.listen(0, "127.0.0.1", () => { } }); }); -const shutdownManager = new GracefulShutdownManager(listener); +const shutdown = gracefulShutdown(listener, { + forceExit: false, // let the event loop clear + finally: () => debugLog("graceful shutdown finished."), +}); app.post("/shutdown", (req, res) => { res.status(200).send("Shutting down"); - setTimeout(function () { - shutdownManager.terminate(() => debugLog("graceful shutdown finished.")); + setTimeout(async () => { + await shutdown() }, 200); }); - diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json b/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json index 0d7ce930f7..c6c33ee5a9 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json +++ b/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json @@ -9,11 +9,11 @@ }, "devDependencies": { ${devDependencies}, - "express": "4.18.2", - "@moebius/http-graceful-shutdown": "1.1.0" + "express": "5.1.0", + "http-graceful-shutdown": "3.1.14" }, "dependencies": {}, "engines": { - "node": ">=6" + "node": ">= 18" } } diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json b/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json index 395a05da67..0a7d522b80 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json +++ b/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json @@ -9,11 +9,11 @@ }, "devDependencies": { ${devDependencies}, - "express": "4.18.2", - "@moebius/http-graceful-shutdown": "1.1.0" + "express": "5.1.0", + "http-graceful-shutdown": "3.1.14" }, "dependencies": {}, "engines": { - "node": ">=6" + "node": ">= 18" } } diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json b/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json index 483dd0753d..f098b08edf 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json +++ b/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json @@ -9,11 +9,11 @@ }, "devDependencies": { ${devDependencies}, - "express": "4.18.2", - "@moebius/http-graceful-shutdown": "1.1.0" + "express": "5.1.0", + "http-graceful-shutdown": "3.1.14" }, "dependencies": {}, "engines": { - "node": ">= 4.2.0" + "node": ">= 18" } } From fea6e811bb9919b44f578e3436c06769fb5ded89 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 30 Jun 2025 07:59:05 +0200 Subject: [PATCH 161/210] fix: use correct variable name in error case --- lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-serve.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-serve.js b/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-serve.js index b9f20a1472..ffbb36c8a4 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-serve.js +++ b/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-serve.js @@ -19,7 +19,7 @@ app.post("/tsfmt/format", (req, res) => { */ // result contains 'message' (String), 'error' (boolean), 'dest' (String) => formatted if (resultMap.error !== undefined && resultMap.error) { - res.status(400).send(resultmap.message); + res.status(400).send(resultMap.message); return; } res.set("Content-Type", "text/plain"); From c93a15804338c9645bdf6e89fe3e713308d10942 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 30 Jun 2025 07:59:19 +0200 Subject: [PATCH 162/210] chore: bump internal version number(s) --- .../resources/com/diffplug/spotless/npm/eslint-package.json | 2 +- .../resources/com/diffplug/spotless/npm/prettier-package.json | 2 +- .../main/resources/com/diffplug/spotless/npm/tsfmt-package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json b/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json index c6c33ee5a9..c4bdba5209 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json +++ b/lib/src/main/resources/com/diffplug/spotless/npm/eslint-package.json @@ -1,6 +1,6 @@ { "name": "spotless-eslint", - "version": "2.0.0", + "version": "4.0.0", "description": "Spotless formatter step for running eslint as a rest service.", "repository": "https://github.com/diffplug/spotless", "license": "Apache-2.0", diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json b/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json index 0a7d522b80..a7c219625c 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json +++ b/lib/src/main/resources/com/diffplug/spotless/npm/prettier-package.json @@ -1,6 +1,6 @@ { "name": "spotless-prettier", - "version": "2.0.0", + "version": "4.0.0", "description": "Spotless formatter step for running prettier as a rest service.", "repository": "https://github.com/diffplug/spotless", "license": "Apache-2.0", diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json b/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json index f098b08edf..d6c9a8a656 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json +++ b/lib/src/main/resources/com/diffplug/spotless/npm/tsfmt-package.json @@ -1,6 +1,6 @@ { "name": "spotless-tsfmt", - "version": "2.0.0", + "version": "4.0.0", "description": "Spotless formatter step for running tsfmt as a rest service.", "repository": "https://github.com/diffplug/spotless", "license": "Apache-2.0", From 88153674bcb8b103d562e617321b7a91cc4da3dc Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 3 Jul 2025 20:17:55 +0200 Subject: [PATCH 163/210] chore: make sure to calculate different hashes if serve-files change this was a hidden update issue: if we change the serve-script content between two releases but the user keeps the package.json the same, the md5 hash used for the node-modules-dir stayed the same, resulting in us not using the latest version of the serve script but keep using the old one. That was especially harmful in the case where we changed the api of the serve-script to accept a uuid to allow multiple instances. The old script just ignored that resulting in a server-process that was never found due to wrong port-file-names written/waited for. --- lib/build.gradle | 1 + .../spotless/npm/NodeServerLayout.java | 10 ++--- .../npm/NpmFormatterStepStateBase.java | 2 +- .../spotless/npm/NpmResourceHelper.java | 13 +++++-- .../spotless/npm/NpmResourceHelperTest.java | 38 +++++++++++++++++++ 5 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 lib/src/test/java/com/diffplug/spotless/npm/NpmResourceHelperTest.java diff --git a/lib/build.gradle b/lib/build.gradle index fcf59cd414..4f4addc2d5 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -76,6 +76,7 @@ dependencies { testCommonImplementation "org.junit.jupiter:junit-jupiter:$VER_JUNIT" testCommonImplementation "org.assertj:assertj-core:$VER_ASSERTJ" testCommonImplementation "com.diffplug.durian:durian-testlib:$VER_DURIAN" + testCommonImplementation projects.testlib testCommonRuntimeOnly "org.junit.platform:junit-platform-launcher" // GLUE CODE (alphabetic order please) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/NodeServerLayout.java b/lib/src/main/java/com/diffplug/spotless/npm/NodeServerLayout.java index 850ea4eb6b..a6089c3972 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/NodeServerLayout.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/NodeServerLayout.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 DiffPlug + * Copyright 2020-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,16 +37,16 @@ class NodeServerLayout { private final File serveJsFile; private final File npmrcFile; - NodeServerLayout(File buildDir, String packageJsonContent) { - this.nodeModulesDir = new File(buildDir, nodeModulesDirName(packageJsonContent)); + NodeServerLayout(File buildDir, String packageJsonContent, String serveJsContent) { + this.nodeModulesDir = new File(buildDir, nodeModulesDirName(packageJsonContent, serveJsContent)); this.packageJsonFile = new File(nodeModulesDir, "package.json"); this.packageLockJsonFile = new File(nodeModulesDir, "package-lock.json"); this.serveJsFile = new File(nodeModulesDir, "serve.js"); this.npmrcFile = new File(nodeModulesDir, ".npmrc"); } - private static String nodeModulesDirName(String packageJsonContent) { - String md5Hash = NpmResourceHelper.md5(packageJsonContent); + private static String nodeModulesDirName(String packageJsonContent, String serveJsContent) { + String md5Hash = NpmResourceHelper.md5(packageJsonContent, serveJsContent); Matcher matcher = PACKAGE_JSON_NAME_PATTERN.matcher(packageJsonContent); if (!matcher.find()) { throw new IllegalArgumentException("package.json must contain a name property"); diff --git a/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java b/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java index 9b37533880..9f27942abc 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java @@ -71,7 +71,7 @@ public static class Runtime { Runtime(NpmFormatterStepStateBase parent) { this.parent = parent; - this.nodeServerLayout = new NodeServerLayout(parent.locations.buildDir(), parent.npmConfig.getPackageJsonContent()); + this.nodeServerLayout = new NodeServerLayout(parent.locations.buildDir(), parent.npmConfig.getPackageJsonContent(), parent.npmConfig.getServeScriptContent()); this.nodeServeApp = new NodeServeApp(nodeServerLayout, parent.npmConfig, parent.locations); } diff --git a/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java b/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java index 7a28685de0..94a7344980 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.diffplug.spotless.ThrowingEx; @@ -140,9 +141,15 @@ static String md5(File file) { return md5(readUtf8StringFromFile(file)); } - static String md5(String fileContent) { + static String md5(String fileContent, String... additionalFileContents) { + Objects.requireNonNull(fileContent, "fileContent must not be null"); + Stream additionalFilecontentStream = Stream.concat( + Stream.of(fileContent), + Stream.of(additionalFileContents)); MessageDigest md = ThrowingEx.get(() -> MessageDigest.getInstance("MD5")); - md.update(fileContent.getBytes(StandardCharsets.UTF_8)); + String stringToHash = additionalFilecontentStream.collect(Collectors.joining("@@@")); + md.update(stringToHash.getBytes(StandardCharsets.UTF_8)); + byte[] digest = md.digest(); // convert byte array digest to hex string StringBuilder sb = new StringBuilder(); diff --git a/lib/src/test/java/com/diffplug/spotless/npm/NpmResourceHelperTest.java b/lib/src/test/java/com/diffplug/spotless/npm/NpmResourceHelperTest.java new file mode 100644 index 0000000000..2fd969f864 --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/npm/NpmResourceHelperTest.java @@ -0,0 +1,38 @@ +/* + * 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.npm; + +import static com.diffplug.selfie.Selfie.expectSelfie; + +import org.junit.jupiter.api.Test; + +class NpmResourceHelperTest { + + @Test + void itCalculatesMd5ForSingleString() { + String input = "Hello, World!"; + + expectSelfie(NpmResourceHelper.md5(input)).toBe("65a8e27d8879283831b664bd8b7f0ad4"); + } + + @Test + void itCalculatesMd5ForMultipleStrings() { + String input1 = "Hello, World!"; + String input2 = "Hello, Spencer!"; + + expectSelfie(NpmResourceHelper.md5(input1, input2)).toBe("371ba0fbf3d73b33e71b4af8dc6afe00"); + } +} From 5f6880f73a7d7394ab7f2e0360ba2f88e457635b Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 3 Jul 2025 20:44:56 +0200 Subject: [PATCH 164/210] chore: assert new expected behaviour in test --- .../spotless/npm/NodeServerLayoutTest.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/src/test/java/com/diffplug/spotless/npm/NodeServerLayoutTest.java diff --git a/lib/src/test/java/com/diffplug/spotless/npm/NodeServerLayoutTest.java b/lib/src/test/java/com/diffplug/spotless/npm/NodeServerLayoutTest.java new file mode 100644 index 0000000000..f2cb55943d --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/npm/NodeServerLayoutTest.java @@ -0,0 +1,77 @@ +/* + * 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.npm; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.ResourceHarness; + +class NodeServerLayoutTest extends ResourceHarness { + + @Test + void itCalculatesSameNodeModulesDirForSameContent() throws IOException { + File testDir = newFolder("build"); + String packageJsonContent = prettierPackageJson(Collections.emptyMap()); + String serveJsContent = "fun main() { console.log('Hello, world!'); }"; + NodeServerLayout layout1 = new NodeServerLayout(testDir, packageJsonContent, serveJsContent); + NodeServerLayout layout2 = new NodeServerLayout(testDir, packageJsonContent, serveJsContent); + + assertThat(layout1.nodeModulesDir()).isEqualTo(layout2.nodeModulesDir()); + } + + @Test + void itCalculatesDifferentNodeModulesDirForDifferentPackageJson() throws IOException { + File testDir = newFolder("build"); + String packageJsonContent1 = prettierPackageJson(Collections.singletonMap("prettier-plugin-xy", "^2.0.0")); + String packageJsonContent2 = prettierPackageJson(Collections.singletonMap("prettier-plugin-xy", "^2.1.0")); + String serveJsContent = "fun main() { console.log('Hello, world!'); }"; + + NodeServerLayout layout1 = new NodeServerLayout(testDir, packageJsonContent1, serveJsContent); + NodeServerLayout layout2 = new NodeServerLayout(testDir, packageJsonContent2, serveJsContent); + + assertThat(layout1.nodeModulesDir()).isNotEqualTo(layout2.nodeModulesDir()); + } + + @Test + void itCalculatesDifferentNodeModulesDirForDifferentServeJs() throws IOException { + File testDir = newFolder("build"); + String packageJsonContent = prettierPackageJson(Collections.emptyMap()); + String serveJsContent1 = "fun main() { console.log('Hello, world!'); }"; + String serveJsContent2 = "fun main() { console.log('Goodbye, world!'); }"; + + NodeServerLayout layout1 = new NodeServerLayout(testDir, packageJsonContent, serveJsContent1); + NodeServerLayout layout2 = new NodeServerLayout(testDir, packageJsonContent, serveJsContent2); + + assertThat(layout1.nodeModulesDir()).isNotEqualTo(layout2.nodeModulesDir()); + } + + static String prettierPackageJson(Map dependencies) { + String templateContent = NpmResourceHelper.readUtf8StringFromClasspath(NodeServerLayoutTest.class, "/com/diffplug/spotless/npm/prettier-package.json"); + String dependenciesList = dependencies.entrySet().stream() + .map(entry -> String.format("\"%s\": \"%s\"", entry.getKey(), entry.getValue())) + .reduce((a, b) -> a + ",\n " + b) + .orElse(""); + + return templateContent.replace("${devDependencies}", dependenciesList); + } +} From 7572d5f42683149af00a51be69b29adc514e5653 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 3 Jul 2025 21:17:39 +0200 Subject: [PATCH 165/210] chore: implement PR feedback --- .../com/diffplug/spotless/npm/NpmResourceHelper.java | 7 +++++-- .../com/diffplug/spotless/npm/common-serve.js | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java b/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java index 94a7344980..3c146cd315 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/NpmResourceHelper.java @@ -32,6 +32,9 @@ import com.diffplug.spotless.ThrowingEx; final class NpmResourceHelper { + + public static final String MD5_STRING_DELIMITER = "@@@"; + private NpmResourceHelper() { // no instance required } @@ -143,11 +146,11 @@ static String md5(File file) { static String md5(String fileContent, String... additionalFileContents) { Objects.requireNonNull(fileContent, "fileContent must not be null"); - Stream additionalFilecontentStream = Stream.concat( + Stream additionalFileContentStream = Stream.concat( Stream.of(fileContent), Stream.of(additionalFileContents)); MessageDigest md = ThrowingEx.get(() -> MessageDigest.getInstance("MD5")); - String stringToHash = additionalFilecontentStream.collect(Collectors.joining("@@@")); + String stringToHash = additionalFileContentStream.collect(Collectors.joining(MD5_STRING_DELIMITER)); md.update(stringToHash.getBytes(StandardCharsets.UTF_8)); byte[] digest = md.digest(); diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js b/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js index 291561eda4..edce61465a 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js +++ b/lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js @@ -1,6 +1,6 @@ // this file will be glued to the top of the specific xy-serve.js file const debug_serve = false; // set to true for debug log output in node process -const gracefulShutdown = require("http-graceful-shutdown"); +const shutdownServer = require("http-graceful-shutdown"); const express = require("express"); const app = express(); @@ -48,7 +48,7 @@ var listener = app.listen(0, "127.0.0.1", () => { } }); }); -const shutdown = gracefulShutdown(listener, { +const shutdown = shutdownServer(listener, { forceExit: false, // let the event loop clear finally: () => debugLog("graceful shutdown finished."), }); @@ -56,6 +56,10 @@ const shutdown = gracefulShutdown(listener, { app.post("/shutdown", (req, res) => { res.status(200).send("Shutting down"); setTimeout(async () => { - await shutdown() + try { + await shutdown(); + } catch (err) { + console.error("Error during shutdown:", err); + } }, 200); }); From 3bfd0aebe1dab45221749632da93ea0839a4205a Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Thu, 3 Jul 2025 21:17:52 +0200 Subject: [PATCH 166/210] docs: note changes in changelog --- CHANGES.md | 6 ++++++ plugin-gradle/CHANGES.md | 6 ++++++ plugin-maven/CHANGES.md | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 938e3c385c..50b69be234 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,12 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +### Fixed +* Make sure npm-based formatters use the correct `node_modules` directory when running in parallel. ([#2542](https://github.com/diffplug/spotless/pull/2542)) + +### Changed +* Bump internal dependencies for npm-based formatters ([#2542](https://github.com/diffplug/spotless/pull/2542)) + ## [3.1.2] - 2025-05-27 ### Fixed * Fix `UnsupportedOperationException` in the Gradle plugin when using `targetExcludeContent[Pattern]` ([#2487](https://github.com/diffplug/spotless/pull/2487)) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 121d9d922c..f0e50b198b 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -7,6 +7,12 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +### Fixed +* Make sure npm-based formatters use the correct `node_modules` directory when running in parallel. ([#2542](https://github.com/diffplug/spotless/pull/2542)) + +### Changed +* Bump internal dependencies for npm-based formatters ([#2542](https://github.com/diffplug/spotless/pull/2542))\ + ## [7.0.4] - 2025-05-27 ### Fixed * Fix `UnsupportedOperationException` in the Gradle plugin when using `targetExcludeContent[Pattern]` ([#2487](https://github.com/diffplug/spotless/pull/2487)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index cab00b07af..ea9a32b918 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -7,6 +7,12 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) +### Fixed +* Make sure npm-based formatters use the correct `node_modules` directory when running in parallel. ([#2542](https://github.com/diffplug/spotless/pull/2542)) + +### Changed +* Bump internal dependencies for npm-based formatters ([#2542](https://github.com/diffplug/spotless/pull/2542)) + ## [2.44.5] - 2025-05-27 ### Changed * Bump default `eclipse` version to latest `4.34` -> `4.35`. ([#2458](https://github.com/diffplug/spotless/pull/2458)) From 427369317ceaaaed350f830a9fb487a677220eac Mon Sep 17 00:00:00 2001 From: Goooler Date: Fri, 4 Jul 2025 09:41:54 +0800 Subject: [PATCH 167/210] Link PRs in IDEA --- .idea/vcs.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..03539f0087 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file From 694eb3074407e7fd3999f52f826a48b18c533259 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Sun, 6 Jul 2025 22:54:21 -0700 Subject: [PATCH 168/210] Add the changes to the plugin-maven/CHANGES.md --- plugin-maven/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index aa150bf6cd..bf06a01e06 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -7,6 +7,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) ### Fixed +* `SortPom` disable expandEmptyElements, to avoid empty body warnings. ([#2520](https://github.com/diffplug/spotless/pull/2520)) * Fix biome formatter for new major release 2.x of biome ([#2537](https://github.com/diffplug/spotless/pull/2537)) * Make sure npm-based formatters use the correct `node_modules` directory when running in parallel. ([#2542](https://github.com/diffplug/spotless/pull/2542)) ### Changed From cb202b11ff3ac041fc188457e5420d87c119bec0 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Mon, 7 Jul 2025 17:06:51 +0200 Subject: [PATCH 169/210] Revert "Use palantir-java-format as default formatter in RemoveUnusedImportsStep" This reverts commit 2ebe138c --- CHANGES.md | 3 - .../java/RemoveUnusedImportsStep.java | 13 ++-- .../java/RemoveUnusedImportsStepTest.java | 73 ------------------- .../java/RemoveUnusedImportsStepTest.java | 33 +++++++++ ...dImportsStep_withGoogleJavaFormatTest.java | 6 +- 5 files changed, 43 insertions(+), 85 deletions(-) delete mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java create mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java diff --git a/CHANGES.md b/CHANGES.md index 2f9e031795..735eca7576 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,7 +13,6 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Added * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) -* Use `palantir-java-format` as default formatter in `RemoveUnusedImportsStep`. ([#2541](https://github.com/diffplug/spotless/pull/2541)) * scalafmt: enforce version consistency between the version configured in Spotless and the version declared in Scalafmt config file ([#2460](https://github.com/diffplug/spotless/issues/2460)) ### Fixed * `SortPom` disable expandEmptyElements, to avoid empty body warnings. ([#2520](https://github.com/diffplug/spotless/pull/2520)) @@ -418,8 +417,6 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [2.26.0] - 2022-06-05 ### Added * Support for `editorConfigOverride` in `ktlint`. ([#1218](https://github.com/diffplug/spotless/pull/1218) fixes [#1193](https://github.com/diffplug/spotless/issues/1193)) -### Fixed -* `google-java-format` and `RemoveUnusedImportsStep` works on JDK16+ without jvm args workaround. ([#1224](https://github.com/diffplug/spotless/pull/1224) fixes [#834](https://github.com/diffplug/spotless/issues/834)) ## [2.25.3] - 2022-05-10 ### Fixed diff --git a/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java b/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java index fcdb52503b..753678a86b 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 DiffPlug + * Copyright 2016-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,12 +22,12 @@ import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.Provisioner; -/** Uses palantir-java-format or cleanthat.UnnecessaryImport, but only to remove unused imports. */ +/** Uses google-java-format or cleanthat.UnnecessaryImport, but only to remove unused imports. */ public class RemoveUnusedImportsStep implements Serializable { private static final long serialVersionUID = 1L; static final String NAME = "removeUnusedImports"; - static final String DEFAULT_FORMATTER = "palantir-java-format"; + static final String GJF = "google-java-format"; static final String CLEANTHAT = "cleanthat-javaparser-unnecessaryimport"; // https://github.com/solven-eu/cleanthat/blob/master/java/src/main/java/eu/solven/cleanthat/engine/java/refactorer/mutators/UnnecessaryImport.java @@ -37,17 +37,18 @@ public class RemoveUnusedImportsStep implements Serializable { private RemoveUnusedImportsStep() {} public static String defaultFormatter() { - return DEFAULT_FORMATTER; + return GJF; } public static FormatterStep create(Provisioner provisioner) { - return create(DEFAULT_FORMATTER, provisioner); + // The default importRemover is GJF + return create(GJF, provisioner); } public static FormatterStep create(String unusedImportRemover, Provisioner provisioner) { Objects.requireNonNull(provisioner, "provisioner"); switch (unusedImportRemover) { - case DEFAULT_FORMATTER: + case GJF: return GoogleJavaFormatStep.createRemoveUnusedImportsOnly(provisioner); case CLEANTHAT: return CleanthatJavaStep.createWithStepName(NAME, CleanthatJavaStep.defaultGroupArtifact(), CleanthatJavaStep.defaultVersion(), "99.9", List.of(CLEANTHAT_MUTATOR), List.of(), false, provisioner); diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java deleted file mode 100644 index 85713423cc..0000000000 --- a/plugin-maven/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStepTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - * 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.java; - -import static com.diffplug.spotless.java.RemoveUnusedImportsStep.DEFAULT_FORMATTER; -import static com.diffplug.spotless.java.RemoveUnusedImportsStep.NAME; -import static com.diffplug.spotless.java.RemoveUnusedImportsStep.defaultFormatter; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.Collections; - -import org.junit.jupiter.api.Test; - -import com.diffplug.spotless.maven.MavenIntegrationHarness; - -class RemoveUnusedImportsStepTest extends MavenIntegrationHarness { - - @Test - void testRemoveUnusedImports() throws Exception { - writePomWithJavaSteps(""); - - String path = "src/main/java/test.java"; - setFile(path).toResource("java/removeunusedimports/JavaCodeWithPackageUnformatted.test"); - mavenRunner().withArguments("spotless:apply").runNoError(); - assertFile(path).sameAsResource("java/removeunusedimports/JavaCodeWithPackageFormatted.test"); - } - - @Test - void testDefaults() { - assertEquals("palantir-java-format", defaultFormatter()); - assertEquals("palantir-java-format", DEFAULT_FORMATTER); - assertEquals("removeUnusedImports", NAME); - } - - @Test - void testCreateWithDefaultFormatter() { - assertEquals(NAME, RemoveUnusedImportsStep.create((groupArtifact, version) -> Collections.emptySet()).getName()); - } - - @Test - void testCreateWithPalantirFormatter() { - assertEquals(NAME, RemoveUnusedImportsStep.create("palantir-java-format", (groupArtifact, version) -> Collections.emptySet()).getName()); - } - - @Test - void testCreateWithCleanthatFormatter() { - assertEquals(NAME, RemoveUnusedImportsStep.create("cleanthat-javaparser-unnecessaryimport", (groupArtifact, version) -> Collections.emptySet()).getName()); - } - - @Test - void testCreateWithInvalidFormatter() { - assertThrows(IllegalArgumentException.class, () -> RemoveUnusedImportsStep.create("invalid-formatter", (groupArtifact, version) -> Collections.emptySet())); - } - - @Test - void testCreateWithNullProvisioner() { - assertThrows(NullPointerException.class, () -> RemoveUnusedImportsStep.create("palantir-java-format", null)); - } -} diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java new file mode 100644 index 0000000000..3689fa8f98 --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/RemoveUnusedImportsStepTest.java @@ -0,0 +1,33 @@ +/* + * 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. + * 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.maven.java; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.maven.MavenIntegrationHarness; + +class RemoveUnusedImportsStepTest extends MavenIntegrationHarness { + + @Test + void testRemoveUnusedInports() throws Exception { + writePomWithJavaSteps(""); + + String path = "src/main/java/test.java"; + setFile(path).toResource("java/removeunusedimports/JavaCodeWithPackageUnformatted.test"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile(path).sameAsResource("java/removeunusedimports/JavaCodeWithPackageFormatted.test"); + } +} diff --git a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java index 766816a659..44699a8215 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ class RemoveUnusedImportsStep_withGoogleJavaFormatTest { @Test void behavior() throws Exception { - FormatterStep step = RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.DEFAULT_FORMATTER, TestProvisioner.mavenCentral()); + FormatterStep step = RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.GJF, TestProvisioner.mavenCentral()); StepHarness.forStep(step) .testResource("java/removeunusedimports/JavaCodeUnformatted.test", "java/removeunusedimports/JavaCodeFormatted.test") .testResource("java/removeunusedimports/JavaCodeWithLicenseUnformatted.test", "java/removeunusedimports/JavaCodeWithLicenseFormatted.test") @@ -48,7 +48,7 @@ protected void setupTest(API api) { @Override protected FormatterStep create() { - return RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.DEFAULT_FORMATTER, TestProvisioner.mavenCentral()); + return RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.GJF, TestProvisioner.mavenCentral()); } }.testEquals(); } From 62b12ca8fb2b17f04bf3028c97e73f99f682b5a9 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Mon, 7 Jul 2025 14:03:03 -0700 Subject: [PATCH 170/210] spotlessApply --- .../com/diffplug/spotless/java/RemoveUnusedImportsStep.java | 2 +- .../java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java b/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java index 753678a86b..71b6dc4281 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.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. diff --git a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java index 44699a8215..84ad3f1f61 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. From 10c60698327c0b7a4ecebd76c7638f695389d83b Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 7 Jul 2025 21:42:26 +0000 Subject: [PATCH 171/210] Published lib/3.2.0 --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 735eca7576..a4f4bf2e70 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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] + +## [3.2.0] - 2025-07-07 ### Added * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) From facaab50c74d0d4ce2f5afdd50a73907a3a1c875 Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 7 Jul 2025 21:43:29 +0000 Subject: [PATCH 172/210] Published gradle/7.1.0 --- plugin-gradle/CHANGES.md | 2 ++ plugin-gradle/README.md | 62 ++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 6dce00628c..c35554a6eb 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] + +## [7.1.0] - 2025-07-07 ### Added * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index f775bf58a8..b1ebab7878 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -14,9 +14,9 @@ output = [ ].join('\n'); --> [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.0.4-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.1.0-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -129,10 +129,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -174,7 +174,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -386,8 +386,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -446,8 +446,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle @@ -546,7 +546,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -578,7 +578,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -614,7 +614,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -650,7 +650,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -682,7 +682,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -703,7 +703,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -722,7 +722,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -747,7 +747,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -786,7 +786,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -835,7 +835,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -929,7 +929,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -992,7 +992,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1112,7 +1112,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1144,7 +1144,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1180,7 +1180,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1209,7 +1209,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1642,7 +1642,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1728,9 +1728,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1763,11 +1763,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.0.4/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From 9b004d2533309c879376f5e03d5edf2030ee35a2 Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 7 Jul 2025 21:44:59 +0000 Subject: [PATCH 173/210] Published maven/2.45.0 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index bf06a01e06..e8e69c82f8 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.45.0] - 2025-07-07 ### Added * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) * Add support for removing wildcard imports via `removeWildcardImports` step. ([#2517](https://github.com/diffplug/spotless/pull/2517)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 2e5839e819..f03a2273a0 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.44.5-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.44.5/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.45.0-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.45.0/index.html) // Relative paths are resolved against the project's base directory --> - biome('1.2.0').configPath('./config') + biome('2.1.0').configPath('./config') + } +} +``` + +__If spotless does not format any files__, this might be because you excluded those files in you biome.json +configuration file. If you are using biome 2.x, you can create a custom config file for spotless and inherit from +your main config file like this: + +```jsonc +// biome-spotless.json +{ + "extends": "./biome.json", + "include": ["**"] +} +``` + +Then simply specify the path to this file in your spotless configuration: + +```gradle +spotless { + format 'biome', { + biome('2.1.0').configPath('./config/biome-spotless.json') } } ``` diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java index 49aeb28fc0..4767e5112a 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BiomeStepConfig.java @@ -31,10 +31,9 @@ public abstract class BiomeStepConfig> { /** - * Optional path to the directory with configuration file for Biome. The file - * must be named {@code biome.json}. When none is given, the default - * configuration is used. If this is a relative path, it is resolved against the - * project's base directory. + * Optional path to the configuration file for Biome. Must be either a directory that contains a file named + * {@code biome.json}, or a file that contains the Biome config as JSON. When none is given, the default + * configuration is used. If this is a relative path, it is resolved against the project's base directory. */ @Nullable private Object configPath; diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java index 8e4da27e95..02ef09ec01 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java @@ -19,6 +19,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.File; + import org.junit.jupiter.api.Test; import org.owasp.encoder.Encode; @@ -230,6 +232,34 @@ void configPathAbsolute() throws Exception { assertFile("biome_test.js").sameAsResource("biome/js/longLineAfter120.js"); } + /** + * Tests that a path to a Biome config JSON file can be specified (requires biome 2.x). + * + * @throws Exception When a test failure occurs. + */ + @Test + void configPathFile() throws Exception { + var path = newFile("configs").getAbsolutePath(); + var file = new File(path, "biome.json").getAbsolutePath(); + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "spotless {", + " format 'mybiome', {", + " target '**/*.js'", + " biome('2.1.0').configPath('" + Encode.forJava(file) + "')", + " }", + "}"); + setFile("biome_test.js").toResource("biome/js/longLineBefore.js"); + setFile("configs/biome.json").toResource("biome/config/line-width-120.json"); + + var spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); + assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertFile("biome_test.js").sameAsResource("biome/js/longLineAfter120.js"); + } + /** * Tests that a path to the directory with the biome.json config file can be * specified. Uses a config file with a line width of 120. diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index e8e69c82f8..eb4695a891 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ## [2.45.0] - 2025-07-07 ### Added diff --git a/plugin-maven/README.md b/plugin-maven/README.md index f03a2273a0..f633ca5635 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -1530,9 +1530,9 @@ Note regarding CSS: Biome supports formatting CSS as of 1.8.0 (experimental, opt - 1.2.0 + 2.1.1 - + ${project.basedir}/path/to/config/dir @@ -1583,7 +1583,7 @@ To download the Biome binary from the network, just specify a version: ```xml - 1.2.0 + 2.1.0 ``` @@ -1594,7 +1594,7 @@ Biome binaries (defaults to `~/.m2/repository/com/diffplug/spotless/spotless-dat ```xml - 1.2.0 + 2.1.0 ${user.home}/biome @@ -1631,10 +1631,31 @@ Biome is used. To use a custom configuration: + ${project.basedir} ``` +__If spotless does not format any files__, this might be because you excluded those files in you biome.json +configuration file. If you are using biome 2.x, you can create a custom config file for spotless and inherit from +your main config file like this: + +```jsonc +// biome-spotless.json +{ + "extends": "./biome.json", + "include": ["**"] +} +``` + +Then simply specify the path to this file in your spotless configuration: + +```xml + + ${project.basedir}/biome-spotless.json + +``` + ### Biome input language By default, Biome detects the language / syntax of the files to format diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java index 465965f896..3d1cf82ca4 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/AbstractBiome.java @@ -37,10 +37,9 @@ public abstract class AbstractBiome implements FormatterStepFactory { protected AbstractBiome() {} /** - * Optional path to the directory with configuration file for Biome. The file - * must be named {@code biome.json}. When none is given, the default - * configuration is used. If this is a relative path, it is resolved against the - * project's base directory. + * Optional path to the configuration file for Biome. Must be either a directory that contains a file named + * {@code biome.json}, or a file that contains the Biome config as JSON. When none is given, the default + * configuration is used. If this is a relative path, it is resolved against the project's base directory. */ @Parameter private String configPath; diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java index 1072a95da8..4197b623dc 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/biome/BiomeMavenTest.java @@ -20,6 +20,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.owasp.encoder.Encode.forXml; +import java.io.File; + import org.junit.jupiter.api.Test; import com.diffplug.spotless.maven.MavenIntegrationHarness; @@ -139,6 +141,23 @@ void configPathAbsolute() throws Exception { assertFile("biome_test.js").sameAsResource("biome/js/longLineAfter120.js"); } + /** + * Tests that a path to a Biome config JSON file can be specified (requires biome 2.x). + * + * @throws Exception When a test failure occurs. + */ + @Test + void configPathFile() throws Exception { + var path = newFile("configs").getAbsolutePath(); + var file = new File(path, "biome.json").getAbsolutePath(); + writePomWithBiomeSteps("**/*.js", + "2.1.1" + forXml(file) + ""); + setFile("biome_test.js").toResource("biome/js/longLineBefore.js"); + setFile("configs/biome.json").toResource("biome/config/line-width-120.json"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile("biome_test.js").sameAsResource("biome/js/longLineAfter120.js"); + } + /** * Tests that a path to the directory with the biome.json config file can be * specified. Uses a config file with a line width of 120. diff --git a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java index db6c535835..090c898df8 100644 --- a/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/biome/BiomeStepTest.java @@ -15,8 +15,11 @@ */ package com.diffplug.spotless.biome; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import org.junit.jupiter.api.BeforeAll; @@ -53,7 +56,7 @@ class AutoDetectLanguage { */ @Test void testAutoDetectCjs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.cjs", "biome/js/fileAfter.cjs"); } @@ -64,7 +67,7 @@ void testAutoDetectCjs() { */ @Test void testAutoDetectCts() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.cts", "biome/ts/fileAfter.cts"); } @@ -76,7 +79,7 @@ void testAutoDetectCts() { @Test void testAutoDetectCssExperimental() { var path = createBiomeConfig("biome/config/css-enabled.json"); - var step = BiomeStep.withExeDownload("1.8.3", downloadDir.toString()).withConfigPath(path).create(); + var step = BiomeStep.withExeDownload("1.8.3", downloadDir).withConfigPath(path.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -87,7 +90,7 @@ void testAutoDetectCssExperimental() { */ @Test void testAutoDetectCssStable() { - var step = BiomeStep.withExeDownload("1.9.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.9.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -98,7 +101,7 @@ void testAutoDetectCssStable() { */ @Test void testAutoDetectJs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.js", "biome/js/fileAfter.js"); } @@ -109,7 +112,7 @@ void testAutoDetectJs() { */ @Test void testAutoDetectJson() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/json/fileBefore.json", "biome/json/fileAfter.json"); } @@ -120,7 +123,7 @@ void testAutoDetectJson() { */ @Test void testAutoDetectJsonc() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/jsonc/fileBefore.jsonc", "biome/jsonc/fileAfter.jsonc"); } @@ -131,7 +134,7 @@ void testAutoDetectJsonc() { */ @Test void testAutoDetectJsx() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.jsx", "biome/js/fileAfter.jsx"); } @@ -142,7 +145,7 @@ void testAutoDetectJsx() { */ @Test void testAutoDetectMjs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.mjs", "biome/js/fileAfter.mjs"); } @@ -153,7 +156,7 @@ void testAutoDetectMjs() { */ @Test void testAutoDetectMts() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.mts", "biome/ts/fileAfter.mts"); } @@ -164,7 +167,7 @@ void testAutoDetectMts() { */ @Test void testAutoDetectTs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.ts", "biome/ts/fileAfter.ts"); } @@ -175,7 +178,7 @@ void testAutoDetectTs() { */ @Test void testAutoDetectTsx() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.tsx", "biome/ts/fileAfter.tsx"); } @@ -188,7 +191,7 @@ void testAutoDetectTsx() { */ @Test void preservesIgnoredFiles() { - var step = BiomeStep.withExeDownload("1.5.0", downloadDir.toString()).create(); + var step = BiomeStep.withExeDownload("1.5.0", downloadDir).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/json/package.json", "biome/json/packageAfter.json"); } @@ -228,7 +231,7 @@ class ConfigFile { @Test void testLineWidth120() { var path = createBiomeConfig("biome/config/line-width-120.json"); - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withConfigPath(path).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withConfigPath(path.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/longLineBefore.js", "biome/js/longLineAfter120.js"); } @@ -239,11 +242,36 @@ void testLineWidth120() { @Test void testLineWidth80() { var path = createBiomeConfig("biome/config/line-width-80.json"); - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withConfigPath(path).create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withConfigPath(path.toString()).create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/longLineBefore.js", "biome/js/longLineAfter80.js"); } + /** + * Test the path to the JSON config file can be specified directly (requires biome 2.x). + */ + @Test + void testPathToFile() { + var path = createBiomeConfig("biome/config/line-width-80.json").resolve("biome.json"); + assertTrue(Files.isRegularFile(path)); + assertTrue(Files.exists(path)); + var step = BiomeStep.withExeDownload("2.1.1", downloadDir).withConfigPath(path.toString()).create(); + var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); + stepHarness.testResource("biome/js/longLineBefore.js", "biome/js/longLineAfter80.js"); + } + + /** + * Test the path to the folder with the biome.json config file can be specified. + */ + @Test + void testPathToDirectory() { + var path = createBiomeConfig("biome/config/line-width-80.json"); + assertTrue(Files.isDirectory(path)); + assertTrue(Files.exists(path)); + var step = BiomeStep.withExeDownload("2.1.1", downloadDir).withConfigPath(path.toString()).create(); + var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); + stepHarness.testResource("biome/js/longLineBefore.js", "biome/js/longLineAfter80.js"); + } } /** @@ -257,7 +285,7 @@ class ExplicitLanguage { */ @Test void testSetLanguageCjs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("js").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("js").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.cjs", "biome/js/fileAfter.cjs"); } @@ -269,7 +297,7 @@ void testSetLanguageCjs() { @Test void testSetLanguageCssExperimental() { var path = createBiomeConfig("biome/config/css-enabled.json"); - var step = BiomeStep.withExeDownload("1.8.3", downloadDir.toString()).withConfigPath(path).withLanguage("css").create(); + var step = BiomeStep.withExeDownload("1.8.3", downloadDir).withConfigPath(path.toString()).withLanguage("css").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -280,7 +308,7 @@ void testSetLanguageCssExperimental() { */ @Test void testSetLanguageCssStable() { - var step = BiomeStep.withExeDownload("1.9.0", downloadDir.toString()).withLanguage("css").create(); + var step = BiomeStep.withExeDownload("1.9.0", downloadDir).withLanguage("css").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/css/fileBefore.css", "biome/css/fileAfter.css"); } @@ -291,7 +319,7 @@ void testSetLanguageCssStable() { */ @Test void testSetLanguageCts() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("ts").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("ts").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.cts", "biome/ts/fileAfter.cts"); } @@ -302,7 +330,7 @@ void testSetLanguageCts() { */ @Test void testSetLanguageJs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("js").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("js").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.js", "biome/js/fileAfter.js"); } @@ -313,7 +341,7 @@ void testSetLanguageJs() { */ @Test void testSetLanguageJson() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("json").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("json").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/json/fileBefore.json", "biome/json/fileAfter.json"); } @@ -324,7 +352,7 @@ void testSetLanguageJson() { */ @Test void testSetLanguageJsonc() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("jsonc").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("jsonc").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/jsonc/fileBefore.jsonc", "biome/jsonc/fileAfter.jsonc"); } @@ -335,7 +363,7 @@ void testSetLanguageJsonc() { */ @Test void testSetLanguageJsx() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("jsx").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("jsx").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.jsx", "biome/js/fileAfter.jsx"); } @@ -346,7 +374,7 @@ void testSetLanguageJsx() { */ @Test void testSetLanguageMjs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("js").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("js").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/js/fileBefore.mjs", "biome/js/fileAfter.mjs"); } @@ -357,7 +385,7 @@ void testSetLanguageMjs() { */ @Test void testSetLanguageMts() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("ts").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("ts").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.mts", "biome/ts/fileAfter.mts"); } @@ -368,7 +396,7 @@ void testSetLanguageMts() { */ @Test void testSetLanguageTs() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("ts").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("ts").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.ts", "biome/ts/fileAfter.ts"); } @@ -379,17 +407,17 @@ void testSetLanguageTs() { */ @Test void testSetLanguageTsx() { - var step = BiomeStep.withExeDownload("1.2.0", downloadDir.toString()).withLanguage("tsx").create(); + var step = BiomeStep.withExeDownload("1.2.0", downloadDir).withLanguage("tsx").create(); var stepHarness = StepHarnessWithFile.forStep(BiomeStepTest.this, step); stepHarness.testResource("biome/ts/fileBefore.tsx", "biome/ts/fileAfter.tsx"); } } - private String createBiomeConfig(String name) { + private Path createBiomeConfig(String name) { var config = createTestFile(name).toPath(); var dir = config.getParent(); - var rome = dir.resolve("biome.json"); - ThrowingEx.run(() -> Files.copy(config, rome)); - return dir.toString(); + var biomeConfig = dir.resolve("biome.json"); + ThrowingEx.run(() -> Files.copy(config, biomeConfig)); + return dir; } } From b79b2d37c8078cc29e57f7866f583c46ae099ebb Mon Sep 17 00:00:00 2001 From: Andre Wachsmuth Date: Wed, 9 Jul 2025 19:10:56 +0200 Subject: [PATCH 176/210] Add link to PR to CHANGES.md --- CHANGES.md | 2 +- plugin-gradle/CHANGES.md | 2 +- plugin-maven/CHANGES.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0ec752f8cb..65635901eb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. +* Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) ## [3.2.0] - 2025-07-07 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index d31dfa4ae3..80b05e796f 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. +* Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) ## [7.1.0] - 2025-07-07 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index eb4695a891..2c801e3c2c 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. +* Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) ## [2.45.0] - 2025-07-07 ### Added From f65f0bf2864ad9aeec861b17dea48a531f58e00d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 05:18:50 +0000 Subject: [PATCH 177/210] fix(deps): update dependency com.google.code.gson:gson to v2.13.1 (#2414) * fix(deps): update dependency com.google.code.gson:gson to v2.13.1 * Updates --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler --- CHANGES.md | 3 +++ lib/build.gradle | 2 +- .../main/java/com/diffplug/spotless/json/gson/GsonStep.java | 4 ++-- plugin-gradle/CHANGES.md | 3 +++ plugin-maven/CHANGES.md | 3 +++ 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a4f4bf2e70..4229bc511b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +## Changed +* Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) + ## [3.2.0] - 2025-07-07 ### Added * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) diff --git a/lib/build.gradle b/lib/build.gradle index 4f4addc2d5..115e5be32a 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -96,7 +96,7 @@ dependencies { // googleJavaFormat googleJavaFormatCompileOnly 'com.google.googlejavaformat:google-java-format:1.24.0' // gson - gsonCompileOnly 'com.google.code.gson:gson:2.11.0' + gsonCompileOnly 'com.google.code.gson:gson:2.13.1' // jackson String VER_JACKSON='2.18.1' jacksonCompileOnly "com.fasterxml.jackson.core:jackson-databind:$VER_JACKSON" diff --git a/lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.java b/lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.java index a690b02b95..31634afa88 100644 --- a/lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.java +++ b/lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.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. @@ -30,7 +30,7 @@ public class GsonStep implements Serializable { private static final String MAVEN_COORDINATES = "com.google.code.gson:gson"; private static final String INCOMPATIBLE_ERROR_MESSAGE = "There was a problem interacting with Gson; maybe you set an incompatible version?"; public static final String NAME = "gson"; - public static final String DEFAULT_VERSION = "2.11.0"; + public static final String DEFAULT_VERSION = "2.13.1"; private final JarState.Promised jarState; private final GsonConfig gsonConfig; diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index c35554a6eb..d2a80d31fd 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,6 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +## Changed +* Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) + ## [7.1.0] - 2025-07-07 ### Added * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index e8e69c82f8..5fd50571d4 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,6 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +## Changed +* Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) + ## [2.45.0] - 2025-07-07 ### Added * Support for `idea` ([#2020](https://github.com/diffplug/spotless/pull/2020), [#2535](https://github.com/diffplug/spotless/pull/2535)) From a73d5b9e7144438541bc817e34ce8de85929cb6e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 14:02:58 +0800 Subject: [PATCH 178/210] chore(deps): update dependency gradle to v8.14.3 (#2549) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68d70..d4081da476 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From f5639f1b3ef27d9e9b2173e40d61917c11e9a2cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 06:17:38 +0000 Subject: [PATCH 179/210] fix(deps): update jackson monorepo to v2.19.1 (#2352) * fix(deps): update jackson monorepo to v2.19.1 * Updates --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler --- CHANGES.md | 1 + lib/build.gradle | 2 +- .../main/java/com/diffplug/spotless/json/JacksonJsonStep.java | 4 ++-- plugin-gradle/CHANGES.md | 1 + plugin-maven/CHANGES.md | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4229bc511b..ded3ad58c8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) +* Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) ## [3.2.0] - 2025-07-07 ### Added diff --git a/lib/build.gradle b/lib/build.gradle index 115e5be32a..47ff1ca1a3 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -98,7 +98,7 @@ dependencies { // gson gsonCompileOnly 'com.google.code.gson:gson:2.13.1' // jackson - String VER_JACKSON='2.18.1' + String VER_JACKSON='2.19.1' jacksonCompileOnly "com.fasterxml.jackson.core:jackson-databind:$VER_JACKSON" jacksonCompileOnly "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$VER_JACKSON" // ktfmt diff --git a/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java b/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java index a4d264b4f0..d8f395129e 100644 --- a/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java +++ b/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 DiffPlug + * Copyright 2021-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ public class JacksonJsonStep implements Serializable { private static final long serialVersionUID = 1L; private static final String MAVEN_COORDINATE = "com.fasterxml.jackson.core:jackson-databind:"; - private static final String DEFAULT_VERSION = "2.18.1"; + private static final String DEFAULT_VERSION = "2.19.1"; public static final String NAME = "jacksonJson"; private final JarState.Promised jarState; diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index d2a80d31fd..5394d24832 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -6,6 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) +* Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) ## [7.1.0] - 2025-07-07 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 5fd50571d4..1c7d2e2b0c 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -6,6 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) +* Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) ## [2.45.0] - 2025-07-07 ### Added From b08ccfcb162b53df7ea1c784ef9a6f787bad428c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 06:32:23 +0000 Subject: [PATCH 180/210] fix(deps): update dependency io.cucumber:gherkin-utils to v9.2.0 (#2408) * fix(deps): update dependency io.cucumber:gherkin-utils to v9.2.0 * Updates --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler --- CHANGES.md | 1 + lib/build.gradle | 2 +- .../java/com/diffplug/spotless/gherkin/GherkinUtilsStep.java | 4 ++-- plugin-gradle/CHANGES.md | 1 + plugin-maven/CHANGES.md | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ded3ad58c8..301bb5da0e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) +* Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) ## [3.2.0] - 2025-07-07 ### Added diff --git a/lib/build.gradle b/lib/build.gradle index 47ff1ca1a3..f44d92e645 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -91,7 +91,7 @@ dependencies { // flexmark flexmarkCompileOnly 'com.vladsch.flexmark:flexmark-all:0.64.8' // gherkin - gherkinCompileOnly 'io.cucumber:gherkin-utils:9.0.0' + gherkinCompileOnly 'io.cucumber:gherkin-utils:9.2.0' gherkinCompileOnly 'org.slf4j:slf4j-api:2.0.17' // googleJavaFormat googleJavaFormatCompileOnly 'com.google.googlejavaformat:google-java-format:1.24.0' diff --git a/lib/src/main/java/com/diffplug/spotless/gherkin/GherkinUtilsStep.java b/lib/src/main/java/com/diffplug/spotless/gherkin/GherkinUtilsStep.java index 63cdd7a786..4f606332d0 100644 --- a/lib/src/main/java/com/diffplug/spotless/gherkin/GherkinUtilsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/gherkin/GherkinUtilsStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 DiffPlug + * Copyright 2021-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,7 +28,7 @@ public class GherkinUtilsStep implements Serializable { private static final long serialVersionUID = 1L; private static final String MAVEN_COORDINATE = "io.cucumber:gherkin-utils:"; - private static final String DEFAULT_VERSION = "9.0.0"; + private static final String DEFAULT_VERSION = "9.2.0"; public static final String NAME = "gherkinUtils"; private final JarState.Promised jarState; diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 5394d24832..5ab73ecbd2 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -7,6 +7,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) +* Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) ## [7.1.0] - 2025-07-07 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 1c7d2e2b0c..f361e062de 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -7,6 +7,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) +* Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) ## [2.45.0] - 2025-07-07 ### Added From 6404c075d526a81c1f3a91987f8e26f060416f00 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 06:33:52 +0000 Subject: [PATCH 181/210] fix(deps): update dependency org.junit.jupiter:junit-jupiter to v5.13.3 (#2551) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1ef2017082..fa9e23c117 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,7 +29,7 @@ VER_SLF4J=[1.6,2.0[ # Used in multiple places VER_DURIAN=1.2.0 VER_JGIT=6.10.1.202505221210-r -VER_JUNIT=5.13.1 +VER_JUNIT=5.13.3 VER_ASSERTJ=3.27.3 VER_MOCKITO=5.18.0 VER_SELFIE=2.5.3 \ No newline at end of file From 3aef1b411e7afd2a8c28d17ab2f483985e06c9a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 06:47:07 +0000 Subject: [PATCH 182/210] chore(deps): update plugin com.diffplug.spotless to v7.1.0 (#2552) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index c6831e1b4d..8c67f9681e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ pluginManagement { } plugins { - id 'com.diffplug.spotless' version '7.0.4' apply false + id 'com.diffplug.spotless' version '7.1.0' apply false // https://plugins.gradle.org/plugin/com.gradle.plugin-publish id 'com.gradle.plugin-publish' version '1.3.1' apply false // https://github.com/gradle-nexus/publish-plugin/releases From 433c58006df7bd0f2393cc89f09ce497ab2c11a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:28:00 +0800 Subject: [PATCH 183/210] fix(deps): update dependency org.eclipse.platform:org.eclipse.osgi to v3.23.100 (#2550) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- lib-extra/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib-extra/build.gradle b/lib-extra/build.gradle index 880830740b..0b727ef8e2 100644 --- a/lib-extra/build.gradle +++ b/lib-extra/build.gradle @@ -21,7 +21,7 @@ dependencies { // the osgi dep is included in solstice, but it has some CVE's against it. // 3.18.500 is the oldest, most-compatible version with no CVE's // https://central.sonatype.com/artifact/org.eclipse.platform/org.eclipse.osgi/versions - implementation "org.eclipse.platform:org.eclipse.osgi:3.23.0" + implementation "org.eclipse.platform:org.eclipse.osgi:3.23.100" // testing testImplementation projects.testlib From 7fbb6c840c560e8c44dfcb26f46eb0f385dabc26 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 08:25:36 +0000 Subject: [PATCH 184/210] chore(deps): update plugin com.github.spotbugs to v6.2.2 (#2509) * chore(deps): update plugin com.github.spotbugs to v6.2.2 * Configure spotbugs-exclude.xml to exclude `THROWS_METHOD_THROWS_RUNTIMEEXCEPTION` * Remove extra SuppressFBWarnings * Suppress THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION * Suppress things for lib-extra as well * Remove extra SuppressFBWarnings in lib-extra --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler --- lib-extra/build.gradle | 1 + lib-extra/spotbugs-exclude.xml | 8 ++++++++ .../diffplug/spotless/extra/GitAttributesLineEndings.java | 1 - lib/build.gradle | 1 + lib/spotbugs-exclude.xml | 8 ++++++++ .../com/diffplug/spotless/ConfigurationCacheHackList.java | 3 --- .../main/java/com/diffplug/spotless/ProcessRunner.java | 5 +---- .../main/java/com/diffplug/spotless/SpotlessCache.java | 6 +----- .../java/com/diffplug/spotless/generic/FenceStep.java | 3 --- .../java/com/diffplug/spotless/java/ImportOrderStep.java | 5 +---- settings.gradle | 2 +- 11 files changed, 22 insertions(+), 21 deletions(-) create mode 100644 lib-extra/spotbugs-exclude.xml create mode 100644 lib/spotbugs-exclude.xml diff --git a/lib-extra/build.gradle b/lib-extra/build.gradle index 0b727ef8e2..a4749cc859 100644 --- a/lib-extra/build.gradle +++ b/lib-extra/build.gradle @@ -102,4 +102,5 @@ p2deps { spotbugs { // LOW|MEDIUM|DEFAULT|HIGH (low = sensitive to even minor mistakes). reportLevel = com.github.spotbugs.snom.Confidence.valueOf('LOW') + excludeFilter = file("spotbugs-exclude.xml") } diff --git a/lib-extra/spotbugs-exclude.xml b/lib-extra/spotbugs-exclude.xml new file mode 100644 index 0000000000..fd9367044a --- /dev/null +++ b/lib-extra/spotbugs-exclude.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib-extra/src/main/java/com/diffplug/spotless/extra/GitAttributesLineEndings.java b/lib-extra/src/main/java/com/diffplug/spotless/extra/GitAttributesLineEndings.java index 0e058566f2..85d8416c0b 100644 --- a/lib-extra/src/main/java/com/diffplug/spotless/extra/GitAttributesLineEndings.java +++ b/lib-extra/src/main/java/com/diffplug/spotless/extra/GitAttributesLineEndings.java @@ -188,7 +188,6 @@ static class RuntimeInit { /** git worktree root, might not exist if we're not in a git repo. */ final @Nullable File workTree; - @SuppressFBWarnings("SIC_INNER_SHOULD_BE_STATIC_ANON") RuntimeInit(File projectDir) { ///////////////////////////////// // USER AND SYSTEM-WIDE VALUES // diff --git a/lib/build.gradle b/lib/build.gradle index f44d92e645..11b959b6c6 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -139,6 +139,7 @@ dependencies { spotbugs { // LOW|MEDIUM|DEFAULT|HIGH (low = sensitive to even minor mistakes). reportLevel = com.github.spotbugs.snom.Confidence.valueOf('LOW') + excludeFilter = file("spotbugs-exclude.xml") } apply from: rootProject.file('gradle/special-tests.gradle') diff --git a/lib/spotbugs-exclude.xml b/lib/spotbugs-exclude.xml new file mode 100644 index 0000000000..fd9367044a --- /dev/null +++ b/lib/spotbugs-exclude.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib/src/main/java/com/diffplug/spotless/ConfigurationCacheHackList.java b/lib/src/main/java/com/diffplug/spotless/ConfigurationCacheHackList.java index 39be0d9559..58794fd588 100644 --- a/lib/src/main/java/com/diffplug/spotless/ConfigurationCacheHackList.java +++ b/lib/src/main/java/com/diffplug/spotless/ConfigurationCacheHackList.java @@ -24,8 +24,6 @@ import com.diffplug.spotless.yaml.SerializeToByteArrayHack; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - /** * Gradle requires three things: * - Gradle defines cache equality based on your serialized representation @@ -78,7 +76,6 @@ private void writeObject(java.io.ObjectOutputStream out) throws IOException { } } - @SuppressFBWarnings("MC_OVERRIDABLE_METHOD_CALL_IN_READ_OBJECT") private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { boolean serializeToByteArrayFirst = in.readBoolean(); optimizeForEquality = in.readBoolean(); diff --git a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java index e7755f75bd..c6dd44ca7b 100644 --- a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java +++ b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2024 DiffPlug + * Copyright 2020-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,8 +37,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - /** * Shelling out to a process is harder than it ought to be in Java. * If you don't read stdout and stderr on their own threads, you risk @@ -195,7 +193,6 @@ private void checkState() { } } - @SuppressFBWarnings({"EI_EXPOSE_REP", "EI_EXPOSE_REP2"}) public static class Result { private final List args; private final int exitCode; diff --git a/lib/src/main/java/com/diffplug/spotless/SpotlessCache.java b/lib/src/main/java/com/diffplug/spotless/SpotlessCache.java index 237e326482..9828b7d748 100644 --- a/lib/src/main/java/com/diffplug/spotless/SpotlessCache.java +++ b/lib/src/main/java/com/diffplug/spotless/SpotlessCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 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. @@ -30,8 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - /** * Spotless' global cache. {@link SpotlessCache#clear()} should be called * when Spotless is no longer in use to release any resources it has grabbed. @@ -64,12 +62,10 @@ public final int hashCode() { final Map cache = new HashMap<>(); - @SuppressFBWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") synchronized ClassLoader classloader(JarState state) { return classloader(state, state); } - @SuppressFBWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") synchronized ClassLoader classloader(Serializable key, JarState state) { SerializedKey serializedKey = new SerializedKey(key); return cache diff --git a/lib/src/main/java/com/diffplug/spotless/generic/FenceStep.java b/lib/src/main/java/com/diffplug/spotless/generic/FenceStep.java index 7d98219231..7cda2e4905 100644 --- a/lib/src/main/java/com/diffplug/spotless/generic/FenceStep.java +++ b/lib/src/main/java/com/diffplug/spotless/generic/FenceStep.java @@ -31,8 +31,6 @@ import com.diffplug.spotless.LineEnding; import com.diffplug.spotless.Lint; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - public class FenceStep { /** Declares the name of the step. */ public static FenceStep named(String name) { @@ -135,7 +133,6 @@ public BaseFormatter toFormatterFunc() { } } - @SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED") private static class BaseFormatter implements FormatterFunc.NeedsFile, FormatterFunc.Closeable { final Kind kind; final Pattern regex; diff --git a/lib/src/main/java/com/diffplug/spotless/java/ImportOrderStep.java b/lib/src/main/java/com/diffplug/spotless/java/ImportOrderStep.java index 1e2c8a81c8..7f2aa7ec4d 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/ImportOrderStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/ImportOrderStep.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. @@ -40,8 +40,6 @@ import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.SerializedFunction; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - public final class ImportOrderStep implements Serializable { private static final long serialVersionUID = 1L; private static final boolean WILDCARDS_LAST_DEFAULT = false; @@ -94,7 +92,6 @@ private FormatterStep createFrom(boolean wildcardsLast, boolean semanticSort, Se State::toFormatter); } - @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE") // workaround https://github.com/spotbugs/spotbugs/issues/756 private static List getImportOrder(File importsFile) { try (Stream lines = Files.lines(importsFile.toPath())) { return lines.filter(line -> !line.startsWith("#")) diff --git a/settings.gradle b/settings.gradle index 8c67f9681e..c0b1b241b0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,7 +12,7 @@ plugins { // https://github.com/gradle-nexus/publish-plugin/releases id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' apply false // https://github.com/spotbugs/spotbugs-gradle-plugin/releases - id 'com.github.spotbugs' version '6.1.13' apply false + id 'com.github.spotbugs' version '6.2.2' apply false // https://github.com/diffplug/spotless-changelog/blob/main/CHANGELOG.md id 'com.diffplug.spotless-changelog' version '3.1.2' apply false // https://github.com/radarsh/gradle-test-logger-plugin/blob/develop/CHANGELOG.md From 03a4cd248346a5a34dba7e726b08c2f5347cddbc Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Mon, 14 Jul 2025 14:29:10 +0800 Subject: [PATCH 185/210] Test on Java 24 (#2473) * Add Java 24 into test matrix * Fix `ErrorShouldRethrowTest` by disabling some ones running on Java 24 --- .github/workflows/ci.yml | 2 +- .../diffplug/gradle/spotless/ErrorShouldRethrowTest.java | 7 ++++++- .../diffplug/gradle/spotless/GradleIntegrationHarness.java | 7 +++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 051f9802c5..dba0ec1d89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: matrix: kind: [maven, gradle] # Test on the latest Java version once Gradle & Maven support it. - jre: [11, 17, 21, 23] + jre: [11, 17, 21, 24] os: [ubuntu-latest] include: # test windows at the diagonals of the above matrix diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ErrorShouldRethrowTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ErrorShouldRethrowTest.java index e083161a09..ebd4bcbbf2 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ErrorShouldRethrowTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ErrorShouldRethrowTest.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.gradle.spotless; +import static org.junit.jupiter.api.condition.JRE.JAVA_23; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -22,6 +24,7 @@ import org.gradle.testkit.runner.BuildResult; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; import com.diffplug.selfie.Selfie; import com.diffplug.selfie.StringSelfie; @@ -57,6 +60,7 @@ void passesIfNoException() throws Exception { } @Test + @EnabledForJreRange(max = JAVA_23) // `[Incubating] Problems report is available at` presents in the output from Java 24 or above. void anyExceptionShouldFail() throws Exception { writeBuild( " } // format", @@ -105,6 +109,7 @@ void unlessExemptedByPath() throws Exception { } @Test + @EnabledForJreRange(max = JAVA_23) // `[Incubating] Problems report is available at` presents in the output from Java 24 or above. void failsIfNeitherStepNorFileExempted() throws Exception { writeBuild( " ignoreErrorForStep 'nope'", diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/GradleIntegrationHarness.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/GradleIntegrationHarness.java index 100bdefc50..21fef4bc27 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/GradleIntegrationHarness.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/GradleIntegrationHarness.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. @@ -54,8 +54,11 @@ public enum GradleVersionSupport { GradleVersionSupport(String version) { String minVersionForRunningJRE; switch (Jvm.version()) { - case 24: + case 25: // TODO: https://docs.gradle.org/current/userguide/compatibility.html + case 24: + minVersionForRunningJRE = "8.14"; + break; case 23: minVersionForRunningJRE = "8.10"; break; From 3893580f4100f66123f0f5f9a45162fab7022324 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Mon, 14 Jul 2025 17:28:13 +0800 Subject: [PATCH 186/210] TODO Gradle issue 22600 (#2554) --- plugin-gradle/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin-gradle/build.gradle b/plugin-gradle/build.gradle index 5211428f8b..5c16c64422 100644 --- a/plugin-gradle/build.gradle +++ b/plugin-gradle/build.gradle @@ -34,6 +34,7 @@ tasks.withType(Test).configureEach { testLogging.showStandardStreams = true } tasks.validatePlugins { + // TODO: https://github.com/gradle/gradle/issues/22600 enableStricterValidation = true } From 7203e24a4574927aaaa9e146a59d59f62e78ba35 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 12:48:42 +0800 Subject: [PATCH 187/210] fix(deps): update dependency io.github.solven-eu.cleanthat:java to v2.23 (#2556) * fix(deps): update dependency io.github.solven-eu.cleanthat:java to v2.23 * Updates --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler --- CHANGES.md | 1 + lib/build.gradle | 2 +- .../java/com/diffplug/spotless/java/CleanthatJavaStep.java | 4 ++-- plugin-gradle/CHANGES.md | 1 + plugin-maven/CHANGES.md | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 301bb5da0e..164ba9a6c6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) * Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) +* Bump default `cleanthat` version to latest `2.22` -> `2.23`. ([#2556](https://github.com/diffplug/spotless/pull/2556)) ## [3.2.0] - 2025-07-07 ### Added diff --git a/lib/build.gradle b/lib/build.gradle index 11b959b6c6..16477b066c 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -81,7 +81,7 @@ dependencies { // GLUE CODE (alphabetic order please) // cleanthat - String VER_CLEANTHAT='2.22' + String VER_CLEANTHAT='2.23' cleanthatCompileOnly "io.github.solven-eu.cleanthat:java:$VER_CLEANTHAT" compatCleanthat2Dot1CompileAndTestOnly "io.github.solven-eu.cleanthat:java:$VER_CLEANTHAT" // diktat old supported version 1.x diff --git a/lib/src/main/java/com/diffplug/spotless/java/CleanthatJavaStep.java b/lib/src/main/java/com/diffplug/spotless/java/CleanthatJavaStep.java index 2762bbeaf9..7790c8b06a 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/CleanthatJavaStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/CleanthatJavaStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 DiffPlug + * Copyright 2023-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ public final class CleanthatJavaStep implements Serializable { /** * CleanThat changelog is available at here. */ - private static final Jvm.Support JVM_SUPPORT = Jvm. support(NAME).add(11, "2.22"); + private static final Jvm.Support JVM_SUPPORT = Jvm. support(NAME).add(11, "2.23"); private final JarState.Promised jarState; private final String version; diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 5ab73ecbd2..d202ad6443 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -8,6 +8,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) * Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) +* Bump default `cleanthat` version to latest `2.22` -> `2.23`. ([#2556](https://github.com/diffplug/spotless/pull/2556)) ## [7.1.0] - 2025-07-07 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index f361e062de..22ae1e293d 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -8,6 +8,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) * Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) +* Bump default `cleanthat` version to latest `2.22` -> `2.23`. ([#2556](https://github.com/diffplug/spotless/pull/2556)) ## [2.45.0] - 2025-07-07 ### Added From e6e9a075b8cf97f871254da5f12adc922e331b2b Mon Sep 17 00:00:00 2001 From: Alex Danylenko Date: Fri, 11 Jul 2025 23:17:35 -0700 Subject: [PATCH 188/210] add git pre push hook --- CHANGES.md | 1 + .../spotless/GitPrePushHookInstaller.java | 169 ++++++++++++++++++ .../GitPrePushHookInstallerGradle.java | 42 +++++ .../GitPrePushHookInstallerMaven.java | 32 ++++ plugin-gradle/CHANGES.md | 3 + .../gradle/spotless/SpotlessExtension.java | 3 + .../spotless/SpotlessExtensionImpl.java | 6 +- .../SpotlessInstallPrePushHookTask.java | 46 +++++ .../SpotlessInstallPrePushHookTaskTest.java | 70 ++++++++ plugin-maven/CHANGES.md | 3 + .../spotless/maven/AbstractSpotlessMojo.java | 1 + .../maven/SpotlessInstallPrePushHookMojo.java | 63 +++++++ .../SpotlessInstallPrePushHookMojoTest.java | 69 +++++++ .../resources/git_pre_hook/pre-push.created | 12 ++ .../resources/git_pre_hook/pre-push.existing | 51 ++++++ .../git_pre_hook/pre-push.existing-added | 62 +++++++ .../spotless/GitPrePushHookInstallerTest.java | 148 +++++++++++++++ 17 files changed, 780 insertions(+), 1 deletion(-) create mode 100644 lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java create mode 100644 lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java create mode 100644 lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java create mode 100644 plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java create mode 100644 plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java create mode 100644 plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java create mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java create mode 100644 testlib/src/main/resources/git_pre_hook/pre-push.created create mode 100644 testlib/src/main/resources/git_pre_hook/pre-push.existing create mode 100644 testlib/src/main/resources/git_pre_hook/pre-push.existing-added create mode 100644 testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java diff --git a/CHANGES.md b/CHANGES.md index e98e32f712..a57d1c1e2c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) +- `GitPrePushHookInstaller`, a reusable library component for installing a Git `pre-push` hook that runs formatter checks. ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java new file mode 100644 index 0000000000..a317689b35 --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java @@ -0,0 +1,169 @@ +package com.diffplug.spotless; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; + +/** + * Abstract class responsible for installing a Git pre-push hook in a repository. + * This class ensures that specific checks and logic are run before a push operation in Git. + * + * Subclasses should define specific behavior for hook installation by implementing the required abstract methods. + */ +public abstract class GitPrePushHookInstaller { + + /** + * Logger for recording informational and error messages during the installation process. + */ + protected final GitPreHookLogger logger; + + /** + * The root directory of the Git repository where the hook will be installed. + */ + protected final File root; + + /** + * Constructor to initialize the GitPrePushHookInstaller with a logger and repository root path. + * + * @param logger The logger for recording messages. + * @param root The root directory of the Git repository. + */ + public GitPrePushHookInstaller(GitPreHookLogger logger, File root) { + this.logger = logger; + this.root = root; + } + + /** + * Installs the Git pre-push hook into the repository. + * + *

    This method checks for the following: + *

      + *
    • Ensures Git is installed and the `.git/config` file exists.
    • + *
    • Checks if an executor required by the hook is available.
    • + *
    • Creates and writes the pre-push hook file if it does not exist.
    • + *
    • Skips installation if the hook is already installed.
    • + *
    + * If an issue occurs during installation, error messages are logged. + * + * @throws Exception if any error occurs during installation. + */ + public void install() throws Exception { + logger.info("Installing git pre-push hook"); + + if (!isGitInstalled()) { + logger.error("Git not found in root directory"); + return; + } + + if (!isExecutorInstalled()) { + return; + } + + var hookContent = ""; + final var gitHookFile = root.toPath().resolve(".git/hooks/pre-push").toFile(); + if (!gitHookFile.exists()) { + logger.info("Git pre-push hook not found, creating it"); + gitHookFile.getParentFile().mkdirs(); + if (!gitHookFile.createNewFile()) { + logger.error("Failed to create pre-push hook file"); + return; + } + + if (!gitHookFile.setExecutable(true, false)) { + logger.error("Can not make file executable"); + return; + } + + hookContent += "#!/bin/sh\n"; + } + + if (isGitHookInstalled(gitHookFile)) { + logger.info("Skipping, git pre-push hook already installed %s", gitHookFile.getAbsolutePath()); + return; + } + + hookContent += preHookContent(); + writeFile(gitHookFile, hookContent); + + logger.info("Git pre-push hook installed successfully to the file %s", gitHookFile.getAbsolutePath()); + } + + /** + * Checks if the required executor for performing the desired pre-push actions is installed. + * + * @return {@code true} if the executor is installed, {@code false} otherwise. + */ + protected abstract boolean isExecutorInstalled(); + + /** + * Provides the content of the hook that should be inserted into the pre-push script. + * + * @return A string representing the content to include in the pre-push script. + */ + protected abstract String preHookContent(); + + /** + * Checks if Git is installed by validating the existence of `.git/config` in the repository root. + * + * @return {@code true} if Git is installed, {@code false} otherwise. + */ + private boolean isGitInstalled() { + return root.toPath().resolve(".git/config").toFile().exists(); + } + + /** + * Verifies if the pre-push hook file already contains the custom Spotless hook content. + * + * @param gitHookFile The file representing the Git hook. + * @return {@code true} if the hook is already installed, {@code false} otherwise. + * @throws Exception if an error occurs when reading the file. + */ + private boolean isGitHookInstalled(File gitHookFile) throws Exception { + final var hook = Files.readString(gitHookFile.toPath(), UTF_8); + return hook.contains("##### SPOTLESS HOOK START #####"); + } + + /** + * Writes the specified content into a file. + * + * @param file The file to which the content should be written. + * @param content The content to write into the file. + * @throws IOException if an error occurs while writing to the file. + */ + private void writeFile(File file, String content) throws IOException { + try (final var writer = new FileWriter(file, UTF_8, true)) { + writer.write(content); + } + } + + /** + * Generates a pre-push template script that defines the commands to check and apply changes + * using an executor and Spotless. + * + * @param executor The tool to execute the check and apply commands. + * @param commandCheck The command to check for issues. + * @param commandApply The command to apply corrections. + * @return A string template representing the Spotless Git pre-push hook content. + */ + protected String preHookTemplate(String executor, String commandCheck, String commandApply) { + var spotlessHook = "\n"; + spotlessHook += "\n##### SPOTLESS HOOK START #####"; + spotlessHook += "\nSPOTLESS_EXECUTOR=" + executor; + spotlessHook += "\nif ! $SPOTLESS_EXECUTOR " + commandCheck + " ; then"; + spotlessHook += "\n echo 1>&2 \"spotless found problems, running " + commandApply + "; commit the result and re-push\""; + spotlessHook += "\n $SPOTLESS_EXECUTOR " + commandApply; + spotlessHook += "\n exit 1"; + spotlessHook += "\nfi"; + spotlessHook += "\n##### SPOTLESS HOOK END #####"; + spotlessHook += "\n\n"; + return spotlessHook; + } + + public interface GitPreHookLogger { + void info(String format, Object... arguments); + void error(String format, Object... arguments); + } +} diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java new file mode 100644 index 0000000000..8c4817c54c --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java @@ -0,0 +1,42 @@ +package com.diffplug.spotless; + +import java.io.File; + +/** + * Implementation of {@link GitPrePushHookInstaller} specifically for Gradle-based projects. + * This class installs a Git pre-push hook that uses Gradle's `gradlew` executable to check and apply Spotless formatting. + */ +public class GitPrePushHookInstallerGradle extends GitPrePushHookInstaller { + + /** + * The Gradle wrapper file (`gradlew`) located in the root directory of the project. + */ + private final File gradlew; + + public GitPrePushHookInstallerGradle(GitPreHookLogger logger, File root) { + super(logger, root); + this.gradlew = root.toPath().resolve("gradlew").toFile(); + } + + /** + * Checks if the Gradle wrapper (`gradlew`) is present in the root directory. + * This ensures that the executor used for formatting (`spotlessCheck` and `spotlessApply`) is available. + * + * @return {@code true} if the Gradle wrapper is found, {@code false} otherwise. + * An error is logged if the wrapper is not found. + */ + @Override + protected boolean isExecutorInstalled() { + if (gradlew.exists()) { + return true; + } + + logger.error("Failed to find gradlew in root directory"); + return false; + } + + @Override + protected String preHookContent() { + return preHookTemplate(gradlew.getAbsolutePath(), "spotlessCheck", "spotlessApply"); + } +} diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java new file mode 100644 index 0000000000..c54b2e4d02 --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java @@ -0,0 +1,32 @@ +package com.diffplug.spotless; + +import java.io.File; + +/** + * Implementation of {@link GitPrePushHookInstaller} specifically for Maven-based projects. + * This class installs a Git pre-push hook that uses Maven to check and apply Spotless formatting. + */ +public class GitPrePushHookInstallerMaven extends GitPrePushHookInstaller { + + public GitPrePushHookInstallerMaven(GitPreHookLogger logger, File root) { + super(logger, root); + } + + /** + * Confirms that Maven is installed and available for use. + * + *

    This method assumes that if this code is running, then Maven is already properly installed and configured, + * so it always returns {@code true}. + * + * @return {@code true}, indicating that Maven is available. + */ + @Override + protected boolean isExecutorInstalled() { + return true; + } + + @Override + protected String preHookContent() { + return preHookTemplate("mvn", "spotless:check", "spotless:apply"); + } +} diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index dd1e9c425f..b318ae421f 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -5,6 +5,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) +- `spotlessInstallGitPrePushHook` task, which installs a Git `pre-push` hook to run `spotlessCheck` and `spotlessApply`. + Uses shared implementation from `GitPrePushHookInstaller`. + [#2553](https://github.com/diffplug/spotless/pull/2553) ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java index e883953eaa..885d697688 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java @@ -38,14 +38,17 @@ public abstract class SpotlessExtension { private final RegisterDependenciesTask registerDependenciesTask; protected static final String TASK_GROUP = LifecycleBasePlugin.VERIFICATION_GROUP; + protected static final String BUILD_SETUP_TASK_GROUP = "build setup"; protected static final String CHECK_DESCRIPTION = "Checks that sourcecode satisfies formatting steps."; protected static final String APPLY_DESCRIPTION = "Applies code formatting steps to sourcecode in-place."; + protected static final String INSTALL_GIT_PRE_PUSH_HOOK_DESCRIPTION = "Installs Spotless Git pre-push hook."; static final String EXTENSION = "spotless"; static final String EXTENSION_PREDECLARE = "spotlessPredeclare"; static final String CHECK = "Check"; static final String APPLY = "Apply"; static final String DIAGNOSE = "Diagnose"; + static final String INSTALL_GIT_PRE_PUSH_HOOK = "InstallGitPrePushHook"; protected SpotlessExtension(Project project) { this.project = requireNonNull(project); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.java index 75168f690a..45d7ffade7 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.java @@ -23,7 +23,7 @@ import org.gradle.api.tasks.TaskProvider; public class SpotlessExtensionImpl extends SpotlessExtension { - final TaskProvider rootCheckTask, rootApplyTask, rootDiagnoseTask; + final TaskProvider rootCheckTask, rootApplyTask, rootDiagnoseTask, rootInstallPreHook; public SpotlessExtensionImpl(Project project) { super(project); @@ -38,6 +38,10 @@ public SpotlessExtensionImpl(Project project) { rootDiagnoseTask = project.getTasks().register(EXTENSION + DIAGNOSE, task -> { task.setGroup(TASK_GROUP); // no description on purpose }); + rootInstallPreHook = project.getTasks().register(EXTENSION + INSTALL_GIT_PRE_PUSH_HOOK, SpotlessInstallPrePushHookTask.class, task -> { + task.setGroup(BUILD_SETUP_TASK_GROUP); + task.setDescription(INSTALL_GIT_PRE_PUSH_HOOK_DESCRIPTION); + }); project.afterEvaluate(unused -> { if (enforceCheck) { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java new file mode 100644 index 0000000000..df6b9bfc8e --- /dev/null +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java @@ -0,0 +1,46 @@ +package com.diffplug.gradle.spotless; + +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.TaskAction; +import org.gradle.work.DisableCachingByDefault; + +import com.diffplug.spotless.GitPrePushHookInstaller.GitPreHookLogger; +import com.diffplug.spotless.GitPrePushHookInstallerGradle; + +/** + * A Gradle task responsible for installing a Git pre-push hook for the Spotless plugin. + * This hook ensures that Spotless formatting rules are automatically checked and applied + * before performing a Git push operation. + * + *

    The task leverages {@link GitPrePushHookInstallerGradle} to implement the installation process. + */ +@DisableCachingByDefault(because = "not worth caching") +public class SpotlessInstallPrePushHookTask extends DefaultTask { + + /** + * Executes the task to install the Git pre-push hook. + * + *

    This method creates an instance of {@link GitPrePushHookInstallerGradle}, + * providing a logger to record informational and error messages during the installation process. + * The installer then installs the hook in the root directory of the Gradle project. + * + * @throws Exception if an error occurs during the hook installation process. + */ + @TaskAction + public void performAction() throws Exception { + final var logger = new GitPreHookLogger() { + @Override + public void info(String format, Object... arguments) { + getLogger().lifecycle(String.format(format, arguments)); + } + + @Override + public void error(String format, Object... arguments) { + getLogger().error(String.format(format, arguments)); + } + }; + + final var installer = new GitPrePushHookInstallerGradle(logger, getProject().getRootDir()); + installer.install(); + } +} diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java new file mode 100644 index 0000000000..1f74e14fc3 --- /dev/null +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java @@ -0,0 +1,70 @@ +package com.diffplug.gradle.spotless; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class SpotlessInstallPrePushHookTaskTest extends GradleIntegrationHarness { + + @Test + public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws Exception { + // given + final var gradlew = setFile("gradlew").toContent(""); + setFile(".git/config").toContent(""); + setFile("build.gradle").toLines( + "plugins {", + " id 'java'", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }" + ); + + // when + var output = gradleRunner() + .withArguments("spotlessInstallGitPrePushHook") + .build() + .getOutput(); + + // then + assertThat(output).contains("Installing git pre-push hook"); + assertThat(output).contains("Git pre-push hook not found, creating it"); + assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); + + final var content = getTestResource("git_pre_hook/pre-push.created") + .replace("${executor}", gradlew.getAbsolutePath()) + .replace("${checkCommand}", "spotlessCheck") + .replace("${applyCommand}", "spotlessApply"); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + @Test + public void should_append_to_existing_pre_hook_file_when_hook_file_exists() throws Exception { + // given + final var gradlew = setFile("gradlew").toContent(""); + setFile(".git/config").toContent(""); + setFile("build.gradle").toLines( + "plugins {", + " id 'java'", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }" + ); + setFile(".git/hooks/pre-push").toResource("git_pre_hook/pre-push.existing"); + + // when + final var output = gradleRunner() + .withArguments("spotlessInstallGitPrePushHook") + .build() + .getOutput(); + + // then + assertThat(output).contains("Installing git pre-push hook"); + assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); + + final var content = getTestResource("git_pre_hook/pre-push.existing-added") + .replace("${executor}", gradlew.getAbsolutePath()) + .replace("${checkCommand}", "spotlessCheck") + .replace("${applyCommand}", "spotlessApply"); + assertFile(".git/hooks/pre-push").hasContent(content); + } +} diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 6829753b2e..f44ad846d4 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -5,6 +5,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) +- `spotless:install-git-pre-push-hook` goal, which installs a Git `pre-push` hook to run `spotless:check` and `spotless:apply`. + Uses shared implementation from `GitPrePushHookInstaller`. + [#2553](https://github.com/diffplug/spotless/pull/2553) ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java index d21a1b8113..5a21a7258a 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java @@ -91,6 +91,7 @@ public abstract class AbstractSpotlessMojo extends AbstractMojo { static final String GOAL_CHECK = "check"; static final String GOAL_APPLY = "apply"; + static final String GOAL_PRE_PUSH_HOOK = "install-git-pre-push-hook"; @Component private RepositorySystem repositorySystem; diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java new file mode 100644 index 0000000000..356a52e913 --- /dev/null +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java @@ -0,0 +1,63 @@ +package com.diffplug.spotless.maven; + +import java.io.File; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; + +import com.diffplug.spotless.GitPrePushHookInstaller.GitPreHookLogger; +import com.diffplug.spotless.GitPrePushHookInstallerMaven; + +/** + * A Maven Mojo responsible for installing a Git pre-push hook for the Spotless plugin. + * This hook ensures that Spotless formatting rules are automatically checked and applied + * before performing a Git push operation. + * + *

    The class leverages {@link GitPrePushHookInstallerMaven} to perform the installation process + * and uses a Maven logger to log installation events and errors to the console. + */ +@Mojo(name = AbstractSpotlessMojo.GOAL_PRE_PUSH_HOOK, threadSafe = true) +public class SpotlessInstallPrePushHookMojo extends AbstractMojo { + + /** + * The base directory of the Maven project where the Git pre-push hook will be installed. + * This parameter is automatically set to the root directory of the current project. + */ + @Parameter(defaultValue = "${project.basedir}", readonly = true, required = true) + private File baseDir; + + /** + * Executes the Mojo, installing the Git pre-push hook for the Spotless plugin. + * + *

    This method creates an instance of {@link GitPrePushHookInstallerMaven}, + * providing a logger for logging the process of hook installation and any potential errors. + * The installation process runs in the root directory of the current Maven project. + * + * @throws MojoExecutionException if an error occurs during the installation process. + * @throws MojoFailureException if the hook fails to install for any reason. + */ + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + final var logger = new GitPreHookLogger() { + @Override + public void info(String format, Object... arguments) { + getLog().info(String.format(format, arguments)); + } + + @Override + public void error(String format, Object... arguments) { + getLog().error(String.format(format, arguments)); + } + }; + + try { + final var installer = new GitPrePushHookInstallerMaven(logger, baseDir); + installer.install(); + } catch (Exception e) { + throw new MojoExecutionException("Unable to install pre-push hook", e); + } + } +} diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java new file mode 100644 index 0000000000..ad6faf823b --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java @@ -0,0 +1,69 @@ +package com.diffplug.spotless.maven; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class SpotlessInstallPrePushHookMojoTest extends MavenIntegrationHarness { + + @Test + public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws Exception { + // given + setFile(".git/config").toContent(""); + setFile("license.txt").toResource("license/TestLicense"); + writePomWithJavaLicenseHeaderStep(); + + // when + final var output = mavenRunner() + .withArguments("spotless:install-git-pre-push-hook") + .runNoError() + .stdOutUtf8(); + + // then + assertThat(output).contains("Installing git pre-push hook"); + assertThat(output).contains("Git pre-push hook not found, creating it"); + assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); + + + final var content = getTestResource("git_pre_hook/pre-push.created") + .replace("${executor}", "mvn") + .replace("${checkCommand}", "spotless:check") + .replace("${applyCommand}", "spotless:apply"); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + @Test + public void should_append_to_existing_pre_hook_file_when_hook_file_exists() throws Exception { + // given + setFile(".git/config").toContent(""); + setFile("license.txt").toResource("license/TestLicense"); + setFile(".git/hooks/pre-push").toResource("git_pre_hook/pre-push.existing"); + + writePomWithJavaLicenseHeaderStep(); + + // when + final var output = mavenRunner() + .withArguments("spotless:install-git-pre-push-hook") + .runNoError() + .stdOutUtf8(); + + // then + assertThat(output).contains("Installing git pre-push hook"); + assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); + + final var content = getTestResource("git_pre_hook/pre-push.existing-added") + .replace("${executor}", "mvn") + .replace("${checkCommand}", "spotless:check") + .replace("${applyCommand}", "spotless:apply"); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + private void writePomWithJavaLicenseHeaderStep() throws IOException { + writePomWithJavaSteps( + "", + " ${basedir}/license.txt", + ""); + } +} diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.created b/testlib/src/main/resources/git_pre_hook/pre-push.created new file mode 100644 index 0000000000..376598c605 --- /dev/null +++ b/testlib/src/main/resources/git_pre_hook/pre-push.created @@ -0,0 +1,12 @@ +#!/bin/sh + + +##### SPOTLESS HOOK START ##### +SPOTLESS_EXECUTOR=${executor} +if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then + echo 1>&2 "spotless found problems, running ${applyCommand}; commit the result and re-push" + $SPOTLESS_EXECUTOR ${applyCommand} + exit 1 +fi +##### SPOTLESS HOOK END ##### + diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.existing b/testlib/src/main/resources/git_pre_hook/pre-push.existing new file mode 100644 index 0000000000..a46210c6c1 --- /dev/null +++ b/testlib/src/main/resources/git_pre_hook/pre-push.existing @@ -0,0 +1,51 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.existing-added b/testlib/src/main/resources/git_pre_hook/pre-push.existing-added new file mode 100644 index 0000000000..fd107efaec --- /dev/null +++ b/testlib/src/main/resources/git_pre_hook/pre-push.existing-added @@ -0,0 +1,62 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + + +##### SPOTLESS HOOK START ##### +SPOTLESS_EXECUTOR=${executor} +if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then + echo 1>&2 "spotless found problems, running ${applyCommand}; commit the result and re-push" + $SPOTLESS_EXECUTOR ${applyCommand} + exit 1 +fi +##### SPOTLESS HOOK END ##### + diff --git a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java new file mode 100644 index 0000000000..78ed927ed0 --- /dev/null +++ b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java @@ -0,0 +1,148 @@ +package com.diffplug.spotless; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.GitPrePushHookInstaller.GitPreHookLogger; + +class GitPrePushHookInstallerTest extends ResourceHarness { + private final List logs = new ArrayList<>(); + private final GitPreHookLogger logger = new GitPreHookLogger() { + @Override + public void info(String format, Object... arguments) { + logs.add(String.format(format, arguments)); + } + + @Override + public void error(String format, Object... arguments) { + logs.add(String.format(format, arguments)); + } + }; + + @Test + public void should_not_create_pre_hook_file_when_git_is_not_installed() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(2); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Git not found in root directory"); + assertThat(newFile(".git/hooks/pre-push")).doesNotExist(); + } + + @Test + public void should_not_create_pre_hook_file_when_gradlew_is_not_installed() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); + setFile(".git/config").toContent(""); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(2); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Failed to find gradlew in root directory"); + assertThat(newFile(".git/hooks/pre-push")).doesNotExist(); + } + + @Test + public void should_not_create_pre_hook_file_when_hook_already_installed() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); + final var hookFile = setFile(".git/hooks/pre-push").toResource("git_pre_hook/pre-push.existing-added"); + + setFile("gradlew").toContent(""); + setFile(".git/config").toContent(""); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(2); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Skipping, git pre-push hook already installed " + hookFile.getAbsolutePath()); + assertThat(hookFile).content().isEqualTo(getTestResource("git_pre_hook/pre-push.existing-added")); + } + + @Test + public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); + final var gradlew = setFile("gradlew").toContent(""); + setFile(".git/config").toContent(""); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(3); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); + assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); + + final var content = gradleHookContent("git_pre_hook/pre-push.created"); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + @Test + public void should_append_to_existing_pre_hook_file_when_hook_file_exists() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); + final var gradlew = setFile("gradlew").toContent(""); + setFile(".git/config").toContent(""); + setFile(".git/hooks/pre-push").toResource("git_pre_hook/pre-push.existing"); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(2); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); + + final var content = gradleHookContent("git_pre_hook/pre-push.existing-added"); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + @Test + public void should_create_pre_hook_file_for_maven_when_hook_file_does_not_exists() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder()); + setFile(".git/config").toContent(""); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(3); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); + assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); + + final var content = mavenHookContent("git_pre_hook/pre-push.created"); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + private String gradleHookContent(String resourcePath) { + return getTestResource(resourcePath) + .replace("${executor}", setFile("gradlew").toContent("").getAbsolutePath()) + .replace("${checkCommand}", "spotlessCheck") + .replace("${applyCommand}", "spotlessApply"); + } + + private String mavenHookContent(String resourcePath) { + return getTestResource(resourcePath) + .replace("${executor}", "mvn") + .replace("${checkCommand}", "spotless:check") + .replace("${applyCommand}", "spotless:apply"); + } +} From 6528b0bbba29d130fcdcd1432eeb6b1f928b6493 Mon Sep 17 00:00:00 2001 From: Alex Danylenko Date: Fri, 11 Jul 2025 23:56:21 -0700 Subject: [PATCH 189/210] spotlessApply --- .../spotless/GitPrePushHookInstaller.java | 22 ++++++- .../GitPrePushHookInstallerGradle.java | 15 +++++ .../GitPrePushHookInstallerMaven.java | 15 +++++ .../gradle/spotless/SpotlessExtension.java | 2 +- .../spotless/SpotlessExtensionImpl.java | 2 +- .../SpotlessInstallPrePushHookTask.java | 15 +++++ .../SpotlessInstallPrePushHookTaskTest.java | 62 ++++++++++++------- .../spotless/maven/AbstractSpotlessMojo.java | 2 +- .../maven/SpotlessInstallPrePushHookMojo.java | 15 +++++ .../SpotlessInstallPrePushHookMojoTest.java | 50 +++++++++------ .../spotless/GitPrePushHookInstallerTest.java | 33 +++++++--- 11 files changed, 178 insertions(+), 55 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java index a317689b35..f8f6a19a88 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java @@ -1,3 +1,18 @@ +/* + * 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; import static java.nio.charset.StandardCharsets.UTF_8; @@ -66,7 +81,11 @@ public void install() throws Exception { final var gitHookFile = root.toPath().resolve(".git/hooks/pre-push").toFile(); if (!gitHookFile.exists()) { logger.info("Git pre-push hook not found, creating it"); - gitHookFile.getParentFile().mkdirs(); + if (!gitHookFile.getParentFile().exists() && !gitHookFile.getParentFile().mkdirs()) { + logger.error("Failed to create pre-push hook directory"); + return; + } + if (!gitHookFile.createNewFile()) { logger.error("Failed to create pre-push hook file"); return; @@ -164,6 +183,7 @@ protected String preHookTemplate(String executor, String commandCheck, String co public interface GitPreHookLogger { void info(String format, Object... arguments); + void error(String format, Object... arguments); } } diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java index 8c4817c54c..26ba4b5442 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java @@ -1,3 +1,18 @@ +/* + * 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; import java.io.File; diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java index c54b2e4d02..1148c07267 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java @@ -1,3 +1,18 @@ +/* + * 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; import java.io.File; diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java index 885d697688..92079d67c4 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.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. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.java index 45d7ffade7..53b7b011a1 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionImpl.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. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java index df6b9bfc8e..2b8d19264b 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java @@ -1,3 +1,18 @@ +/* + * 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.gradle.spotless; import org.gradle.api.DefaultTask; diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java index 1f74e14fc3..9146a773a2 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java @@ -1,3 +1,18 @@ +/* + * 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.gradle.spotless; import static org.assertj.core.api.Assertions.assertThat; @@ -11,19 +26,19 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws // given final var gradlew = setFile("gradlew").toContent(""); setFile(".git/config").toContent(""); + newFile(".git/hooks").mkdirs(); setFile("build.gradle").toLines( - "plugins {", - " id 'java'", - " id 'com.diffplug.spotless'", - "}", - "repositories { mavenCentral() }" - ); + "plugins {", + " id 'java'", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }"); // when var output = gradleRunner() - .withArguments("spotlessInstallGitPrePushHook") - .build() - .getOutput(); + .withArguments("spotlessInstallGitPrePushHook") + .build() + .getOutput(); // then assertThat(output).contains("Installing git pre-push hook"); @@ -31,9 +46,9 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); final var content = getTestResource("git_pre_hook/pre-push.created") - .replace("${executor}", gradlew.getAbsolutePath()) - .replace("${checkCommand}", "spotlessCheck") - .replace("${applyCommand}", "spotlessApply"); + .replace("${executor}", gradlew.getAbsolutePath()) + .replace("${checkCommand}", "spotlessCheck") + .replace("${applyCommand}", "spotlessApply"); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -43,28 +58,27 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro final var gradlew = setFile("gradlew").toContent(""); setFile(".git/config").toContent(""); setFile("build.gradle").toLines( - "plugins {", - " id 'java'", - " id 'com.diffplug.spotless'", - "}", - "repositories { mavenCentral() }" - ); + "plugins {", + " id 'java'", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }"); setFile(".git/hooks/pre-push").toResource("git_pre_hook/pre-push.existing"); // when final var output = gradleRunner() - .withArguments("spotlessInstallGitPrePushHook") - .build() - .getOutput(); + .withArguments("spotlessInstallGitPrePushHook") + .build() + .getOutput(); // then assertThat(output).contains("Installing git pre-push hook"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); final var content = getTestResource("git_pre_hook/pre-push.existing-added") - .replace("${executor}", gradlew.getAbsolutePath()) - .replace("${checkCommand}", "spotlessCheck") - .replace("${applyCommand}", "spotlessApply"); + .replace("${executor}", gradlew.getAbsolutePath()) + .replace("${checkCommand}", "spotlessCheck") + .replace("${applyCommand}", "spotlessApply"); assertFile(".git/hooks/pre-push").hasContent(content); } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java index 5a21a7258a..e5a8004f97 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.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. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java index 356a52e913..691ddd4969 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java @@ -1,3 +1,18 @@ +/* + * 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.maven; import java.io.File; diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java index ad6faf823b..b9d5d6a343 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java @@ -1,11 +1,26 @@ +/* + * 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.maven; +import static org.assertj.core.api.Assertions.assertThat; + import java.io.IOException; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; - class SpotlessInstallPrePushHookMojoTest extends MavenIntegrationHarness { @Test @@ -17,20 +32,19 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws // when final var output = mavenRunner() - .withArguments("spotless:install-git-pre-push-hook") - .runNoError() - .stdOutUtf8(); + .withArguments("spotless:install-git-pre-push-hook") + .runNoError() + .stdOutUtf8(); // then assertThat(output).contains("Installing git pre-push hook"); assertThat(output).contains("Git pre-push hook not found, creating it"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); - final var content = getTestResource("git_pre_hook/pre-push.created") - .replace("${executor}", "mvn") - .replace("${checkCommand}", "spotless:check") - .replace("${applyCommand}", "spotless:apply"); + .replace("${executor}", "mvn") + .replace("${checkCommand}", "spotless:check") + .replace("${applyCommand}", "spotless:apply"); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -45,25 +59,25 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro // when final var output = mavenRunner() - .withArguments("spotless:install-git-pre-push-hook") - .runNoError() - .stdOutUtf8(); + .withArguments("spotless:install-git-pre-push-hook") + .runNoError() + .stdOutUtf8(); // then assertThat(output).contains("Installing git pre-push hook"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); final var content = getTestResource("git_pre_hook/pre-push.existing-added") - .replace("${executor}", "mvn") - .replace("${checkCommand}", "spotless:check") - .replace("${applyCommand}", "spotless:apply"); + .replace("${executor}", "mvn") + .replace("${checkCommand}", "spotless:check") + .replace("${applyCommand}", "spotless:apply"); assertFile(".git/hooks/pre-push").hasContent(content); } private void writePomWithJavaLicenseHeaderStep() throws IOException { writePomWithJavaSteps( - "", - " ${basedir}/license.txt", - ""); + "", + " ${basedir}/license.txt", + ""); } } diff --git a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java index 78ed927ed0..4fd9eed749 100644 --- a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java @@ -1,3 +1,18 @@ +/* + * 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; import static org.assertj.core.api.Assertions.assertThat; @@ -25,13 +40,13 @@ public void error(String format, Object... arguments) { @Test public void should_not_create_pre_hook_file_when_git_is_not_installed() throws Exception { - // given + // given final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); - // when + // when gradle.install(); - // then + // then assertThat(logs).hasSize(2); assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); assertThat(logs).element(1).isEqualTo("Git not found in root directory"); @@ -134,15 +149,15 @@ public void should_create_pre_hook_file_for_maven_when_hook_file_does_not_exists private String gradleHookContent(String resourcePath) { return getTestResource(resourcePath) - .replace("${executor}", setFile("gradlew").toContent("").getAbsolutePath()) - .replace("${checkCommand}", "spotlessCheck") - .replace("${applyCommand}", "spotlessApply"); + .replace("${executor}", setFile("gradlew").toContent("").getAbsolutePath()) + .replace("${checkCommand}", "spotlessCheck") + .replace("${applyCommand}", "spotlessApply"); } private String mavenHookContent(String resourcePath) { return getTestResource(resourcePath) - .replace("${executor}", "mvn") - .replace("${checkCommand}", "spotless:check") - .replace("${applyCommand}", "spotless:apply"); + .replace("${executor}", "mvn") + .replace("${checkCommand}", "spotless:check") + .replace("${applyCommand}", "spotless:apply"); } } From b9f488017e4902cf98f37d074f9380fac54df807 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 17 Jul 2025 09:53:18 -0700 Subject: [PATCH 190/210] Placeholders for docs. --- plugin-gradle/README.md | 5 +++++ plugin-maven/README.md | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 1fa7519a8c..6e6e648ed6 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -53,6 +53,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui - [**Quickstart**](#quickstart) - [Requirements](#requirements) + - [Git hook](#git-hook) - [Linting](#linting) - **Languages** - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea)) @@ -141,6 +142,10 @@ Spotless requires JRE 11+ and Gradle 6.1.1 or newer. - If you're stuck on JRE 8, use [`id 'com.diffplug.spotless' version '6.13.0'` or older](https://github.com/diffplug/spotless/blob/main/plugin-gradle/CHANGES.md#6130---2023-01-14). - If you're stuck on an older version of Gradle, [`id 'com.diffplug.gradle.spotless' version '4.5.1'` supports all the way back to Gradle 2.x](https://github.com/diffplug/spotless/blob/main/plugin-gradle/CHANGES.md#451---2020-07-04). +### Git hook + +TODO + ### Linting Starting in version `7.0.0`, Spotless now supports linting in addition to formatting. To Spotless, all lints are errors which must be either fixed or suppressed. Lints show up like this: diff --git a/plugin-maven/README.md b/plugin-maven/README.md index f633ca5635..8cd01731ba 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -37,6 +37,7 @@ user@machine repo % mvn spotless:check - [**Quickstart**](#quickstart) - [Requirements](#requirements) + - [Git hook](#git-hook) - [Binding to maven phase](#binding-to-maven-phase) - **Languages** - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea)) @@ -145,7 +146,10 @@ Spotless consists of a list of formats (in the example above, `misc` and `java`) Spotless requires Maven to be running on JRE 11+. To use JRE 8, go back to [`2.30.0` or older](https://github.com/diffplug/spotless/blob/main/plugin-maven/CHANGES.md#2300---2023-01-13). - + +### Git hook + +TODO ### Binding to maven phase @@ -176,6 +180,8 @@ any other maven phase (i.e. compile) then it can be configured as below; ``` + + ## Java [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java). [available steps](https://github.com/diffplug/spotless/tree/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java). From a790659b8936a782ca5eae3fe2b7ea721e9f4764 Mon Sep 17 00:00:00 2001 From: Alex Danylenko Date: Thu, 17 Jul 2025 21:45:19 -0700 Subject: [PATCH 191/210] maven wrapper support --- .../spotless/GitPrePushHookInstaller.java | 29 ++++------ .../GitPrePushHookInstallerGradle.java | 24 ++++---- .../GitPrePushHookInstallerMaven.java | 24 ++++---- .../SpotlessInstallPrePushHookTask.java | 5 ++ .../SpotlessInstallPrePushHookTaskTest.java | 6 +- .../maven/SpotlessInstallPrePushHookMojo.java | 5 ++ .../spotless/GitPrePushHookInstallerTest.java | 56 ++++++++++++++----- 7 files changed, 89 insertions(+), 60 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java index f8f6a19a88..9c317d94ab 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java @@ -16,6 +16,7 @@ package com.diffplug.spotless; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Objects.requireNonNull; import java.io.File; import java.io.FileWriter; @@ -30,6 +31,9 @@ */ public abstract class GitPrePushHookInstaller { + private static final String HOOK_HEADLINE = "##### SPOTLESS HOOK START #####"; + private static final String HOOK_FOOTER = "##### SPOTLESS HOOK END #####"; + /** * Logger for recording informational and error messages during the installation process. */ @@ -47,8 +51,8 @@ public abstract class GitPrePushHookInstaller { * @param root The root directory of the Git repository. */ public GitPrePushHookInstaller(GitPreHookLogger logger, File root) { - this.logger = logger; - this.root = root; + this.logger = requireNonNull(logger, "logger can not be null"); + this.root = requireNonNull(root, "root file can not be null"); } /** @@ -73,10 +77,6 @@ public void install() throws Exception { return; } - if (!isExecutorInstalled()) { - return; - } - var hookContent = ""; final var gitHookFile = root.toPath().resolve(".git/hooks/pre-push").toFile(); if (!gitHookFile.exists()) { @@ -100,7 +100,7 @@ public void install() throws Exception { } if (isGitHookInstalled(gitHookFile)) { - logger.info("Skipping, git pre-push hook already installed %s", gitHookFile.getAbsolutePath()); + logger.warn("Skipping, git pre-push hook already installed %s", gitHookFile.getAbsolutePath()); return; } @@ -110,13 +110,6 @@ public void install() throws Exception { logger.info("Git pre-push hook installed successfully to the file %s", gitHookFile.getAbsolutePath()); } - /** - * Checks if the required executor for performing the desired pre-push actions is installed. - * - * @return {@code true} if the executor is installed, {@code false} otherwise. - */ - protected abstract boolean isExecutorInstalled(); - /** * Provides the content of the hook that should be inserted into the pre-push script. * @@ -142,7 +135,7 @@ private boolean isGitInstalled() { */ private boolean isGitHookInstalled(File gitHookFile) throws Exception { final var hook = Files.readString(gitHookFile.toPath(), UTF_8); - return hook.contains("##### SPOTLESS HOOK START #####"); + return hook.contains(HOOK_HEADLINE); } /** @@ -169,21 +162,21 @@ private void writeFile(File file, String content) throws IOException { */ protected String preHookTemplate(String executor, String commandCheck, String commandApply) { var spotlessHook = "\n"; - spotlessHook += "\n##### SPOTLESS HOOK START #####"; + spotlessHook += "\n" + HOOK_HEADLINE; spotlessHook += "\nSPOTLESS_EXECUTOR=" + executor; spotlessHook += "\nif ! $SPOTLESS_EXECUTOR " + commandCheck + " ; then"; spotlessHook += "\n echo 1>&2 \"spotless found problems, running " + commandApply + "; commit the result and re-push\""; spotlessHook += "\n $SPOTLESS_EXECUTOR " + commandApply; spotlessHook += "\n exit 1"; spotlessHook += "\nfi"; - spotlessHook += "\n##### SPOTLESS HOOK END #####"; + spotlessHook += "\n" + HOOK_FOOTER; spotlessHook += "\n\n"; return spotlessHook; } public interface GitPreHookLogger { void info(String format, Object... arguments); - + void warn(String format, Object... arguments); void error(String format, Object... arguments); } } diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java index 26ba4b5442..8ae6e6cb94 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java @@ -33,25 +33,21 @@ public GitPrePushHookInstallerGradle(GitPreHookLogger logger, File root) { this.gradlew = root.toPath().resolve("gradlew").toFile(); } + /** - * Checks if the Gradle wrapper (`gradlew`) is present in the root directory. - * This ensures that the executor used for formatting (`spotlessCheck` and `spotlessApply`) is available. - * - * @return {@code true} if the Gradle wrapper is found, {@code false} otherwise. - * An error is logged if the wrapper is not found. + * {@inheritDoc} */ @Override - protected boolean isExecutorInstalled() { + protected String preHookContent() { + return preHookTemplate(executor(), "spotlessCheck", "spotlessApply"); + } + + private String executor() { if (gradlew.exists()) { - return true; + return gradlew.getAbsolutePath(); } - logger.error("Failed to find gradlew in root directory"); - return false; - } - - @Override - protected String preHookContent() { - return preHookTemplate(gradlew.getAbsolutePath(), "spotlessCheck", "spotlessApply"); + logger.info("Gradle wrapper is not installed, using global gradle"); + return "gradle"; } } diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java index 1148c07267..7f84d85429 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java @@ -23,25 +23,27 @@ */ public class GitPrePushHookInstallerMaven extends GitPrePushHookInstaller { + private final File mvnw; + public GitPrePushHookInstallerMaven(GitPreHookLogger logger, File root) { super(logger, root); + this.mvnw = root.toPath().resolve("mvnw").toFile(); } /** - * Confirms that Maven is installed and available for use. - * - *

    This method assumes that if this code is running, then Maven is already properly installed and configured, - * so it always returns {@code true}. - * - * @return {@code true}, indicating that Maven is available. + * {@inheritDoc} */ @Override - protected boolean isExecutorInstalled() { - return true; + protected String preHookContent() { + return preHookTemplate(executor(), "spotless:check", "spotless:apply"); } - @Override - protected String preHookContent() { - return preHookTemplate("mvn", "spotless:check", "spotless:apply"); + private String executor() { + if (mvnw.exists()) { + return mvnw.getAbsolutePath(); + } + + logger.info("Maven wrapper is not installed, using global maven"); + return "mvn"; } } diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java index 2b8d19264b..3e59e94b0a 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTask.java @@ -49,6 +49,11 @@ public void info(String format, Object... arguments) { getLogger().lifecycle(String.format(format, arguments)); } + @Override + public void warn(String format, Object... arguments) { + getLogger().warn(String.format(format, arguments)); + } + @Override public void error(String format, Object... arguments) { getLogger().error(String.format(format, arguments)); diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java index 9146a773a2..140bb8a755 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java @@ -24,7 +24,6 @@ class SpotlessInstallPrePushHookTaskTest extends GradleIntegrationHarness { @Test public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws Exception { // given - final var gradlew = setFile("gradlew").toContent(""); setFile(".git/config").toContent(""); newFile(".git/hooks").mkdirs(); setFile("build.gradle").toLines( @@ -46,7 +45,7 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); final var content = getTestResource("git_pre_hook/pre-push.created") - .replace("${executor}", gradlew.getAbsolutePath()) + .replace("${executor}", "gradle") .replace("${checkCommand}", "spotlessCheck") .replace("${applyCommand}", "spotlessApply"); assertFile(".git/hooks/pre-push").hasContent(content); @@ -55,7 +54,6 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws @Test public void should_append_to_existing_pre_hook_file_when_hook_file_exists() throws Exception { // given - final var gradlew = setFile("gradlew").toContent(""); setFile(".git/config").toContent(""); setFile("build.gradle").toLines( "plugins {", @@ -76,7 +74,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); final var content = getTestResource("git_pre_hook/pre-push.existing-added") - .replace("${executor}", gradlew.getAbsolutePath()) + .replace("${executor}", "gradle") .replace("${checkCommand}", "spotlessCheck") .replace("${applyCommand}", "spotlessApply"); assertFile(".git/hooks/pre-push").hasContent(content); diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java index 691ddd4969..984724a688 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojo.java @@ -62,6 +62,11 @@ public void info(String format, Object... arguments) { getLog().info(String.format(format, arguments)); } + @Override + public void warn(String format, Object... arguments) { + getLog().warn(String.format(format, arguments)); + } + @Override public void error(String format, Object... arguments) { getLog().error(String.format(format, arguments)); diff --git a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java index 4fd9eed749..b6fbcd26e8 100644 --- a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java @@ -32,6 +32,11 @@ public void info(String format, Object... arguments) { logs.add(String.format(format, arguments)); } + @Override + public void warn(String format, Object... arguments) { + logs.add(String.format(format, arguments)); + } + @Override public void error(String format, Object... arguments) { logs.add(String.format(format, arguments)); @@ -54,7 +59,7 @@ public void should_not_create_pre_hook_file_when_git_is_not_installed() throws E } @Test - public void should_not_create_pre_hook_file_when_gradlew_is_not_installed() throws Exception { + public void should_use_global_gradle_when_gradlew_is_not_installed() throws Exception { // given final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); setFile(".git/config").toContent(""); @@ -63,10 +68,14 @@ public void should_not_create_pre_hook_file_when_gradlew_is_not_installed() thro gradle.install(); // then - assertThat(logs).hasSize(2); + assertThat(logs).hasSize(4); assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); - assertThat(logs).element(1).isEqualTo("Failed to find gradlew in root directory"); - assertThat(newFile(".git/hooks/pre-push")).doesNotExist(); + assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); + assertThat(logs).element(2).isEqualTo("Gradle wrapper is not installed, using global gradle"); + assertThat(logs).element(3).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); + + final var content = gradleHookContent("git_pre_hook/pre-push.created", false); + assertFile(".git/hooks/pre-push").hasContent(content); } @Test @@ -92,7 +101,7 @@ public void should_not_create_pre_hook_file_when_hook_already_installed() throws public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws Exception { // given final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); - final var gradlew = setFile("gradlew").toContent(""); + setFile("gradlew").toContent(""); setFile(".git/config").toContent(""); // when @@ -104,7 +113,7 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = gradleHookContent("git_pre_hook/pre-push.created"); + final var content = gradleHookContent("git_pre_hook/pre-push.created", true); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -112,7 +121,7 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws public void should_append_to_existing_pre_hook_file_when_hook_file_exists() throws Exception { // given final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); - final var gradlew = setFile("gradlew").toContent(""); + setFile("gradlew").toContent(""); setFile(".git/config").toContent(""); setFile(".git/hooks/pre-push").toResource("git_pre_hook/pre-push.existing"); @@ -124,7 +133,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); assertThat(logs).element(1).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = gradleHookContent("git_pre_hook/pre-push.existing-added"); + final var content = gradleHookContent("git_pre_hook/pre-push.existing-added", true); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -132,6 +141,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro public void should_create_pre_hook_file_for_maven_when_hook_file_does_not_exists() throws Exception { // given final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder()); + setFile("mvnw").toContent(""); setFile(".git/config").toContent(""); // when @@ -143,20 +153,40 @@ public void should_create_pre_hook_file_for_maven_when_hook_file_does_not_exists assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = mavenHookContent("git_pre_hook/pre-push.created"); + final var content = mavenHookContent("git_pre_hook/pre-push.created", true); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + @Test + public void should_use_global_maven_when_maven_wrapper_is_not_installed() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder()); + setFile(".git/config").toContent(""); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(4); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); + assertThat(logs).element(2).isEqualTo("Maven wrapper is not installed, using global maven"); + assertThat(logs).element(3).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); + + final var content = mavenHookContent("git_pre_hook/pre-push.created", false); assertFile(".git/hooks/pre-push").hasContent(content); } - private String gradleHookContent(String resourcePath) { + private String gradleHookContent(String resourcePath, boolean isWrapper) { return getTestResource(resourcePath) - .replace("${executor}", setFile("gradlew").toContent("").getAbsolutePath()) + .replace("${executor}", isWrapper ? newFile("gradlew").getAbsolutePath() : "gradle") .replace("${checkCommand}", "spotlessCheck") .replace("${applyCommand}", "spotlessApply"); } - private String mavenHookContent(String resourcePath) { + private String mavenHookContent(String resourcePath, boolean isWrapper) { return getTestResource(resourcePath) - .replace("${executor}", "mvn") + .replace("${executor}", isWrapper ? newFile("mvnw").getAbsolutePath() : "mvn") .replace("${checkCommand}", "spotless:check") .replace("${applyCommand}", "spotless:apply"); } From 525e70eb8751e432e527cc23434f0c009fa4ae90 Mon Sep 17 00:00:00 2001 From: Alex Danylenko Date: Thu, 17 Jul 2025 22:44:46 -0700 Subject: [PATCH 192/210] reinstall support --- .../spotless/GitPrePushHookInstaller.java | 86 +++++++++++++------ .../GitPrePushHookInstallerGradle.java | 1 - plugin-gradle/README.md | 31 ++++++- .../SpotlessInstallPrePushHookTaskTest.java | 4 +- plugin-maven/README.md | 31 ++++++- .../SpotlessInstallPrePushHookMojoTest.java | 8 +- ...{pre-push.created => pre-push.created-tpl} | 1 - ...ting-added => pre-push.existing-added-tpl} | 1 - .../git_pre_hook/pre-push.reinstalled-tpl | 64 ++++++++++++++ .../spotless/GitPrePushHookInstallerTest.java | 36 +++++--- 10 files changed, 206 insertions(+), 57 deletions(-) rename testlib/src/main/resources/git_pre_hook/{pre-push.created => pre-push.created-tpl} (99%) rename testlib/src/main/resources/git_pre_hook/{pre-push.existing-added => pre-push.existing-added-tpl} (99%) create mode 100644 testlib/src/main/resources/git_pre_hook/pre-push.reinstalled-tpl diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java index 9c317d94ab..b5070a003b 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java @@ -100,16 +100,44 @@ public void install() throws Exception { } if (isGitHookInstalled(gitHookFile)) { - logger.warn("Skipping, git pre-push hook already installed %s", gitHookFile.getAbsolutePath()); - return; + logger.info("Git pre-push hook already installed, reinstalling it"); + uninstall(gitHookFile); } hookContent += preHookContent(); - writeFile(gitHookFile, hookContent); + writeFile(gitHookFile, hookContent, true); logger.info("Git pre-push hook installed successfully to the file %s", gitHookFile.getAbsolutePath()); } + /** + * Uninstalls the Spotless Git pre-push hook from the specified hook file by removing + * the custom hook content between the defined hook markers. + * + *

    This method: + *

      + *
    • Reads the entire content of the pre-push hook file
    • + *
    • Identifies the Spotless hook section using predefined markers
    • + *
    • Removes the Spotless hook content while preserving other hook content
    • + *
    • Writes the modified content back to the hook file
    • + *
    + * + * @param gitHookFile The Git pre-push hook file from which to remove the Spotless hook + * @throws Exception if any error occurs during the uninstallation process, + * such as file reading or writing errors + */ + private void uninstall(File gitHookFile) throws Exception { + final var hook = Files.readString(gitHookFile.toPath(), UTF_8); + final var hookStart = hook.indexOf(HOOK_HEADLINE); + final var hookEnd = hook.indexOf(HOOK_FOOTER) + HOOK_FOOTER.length(); + + final var hookScript = hook.substring(hookStart, hookEnd); + + final var uninstalledHook = hook.replace(hookScript, ""); + + writeFile(gitHookFile, uninstalledHook, false); + } + /** * Provides the content of the hook that should be inserted into the pre-push script. * @@ -117,6 +145,29 @@ public void install() throws Exception { */ protected abstract String preHookContent(); + /** + * Generates a pre-push template script that defines the commands to check and apply changes + * using an executor and Spotless. + * + * @param executor The tool to execute the check and apply commands. + * @param commandCheck The command to check for issues. + * @param commandApply The command to apply corrections. + * @return A string template representing the Spotless Git pre-push hook content. + */ + protected String preHookTemplate(String executor, String commandCheck, String commandApply) { + var spotlessHook = "\n"; + spotlessHook += "\n" + HOOK_HEADLINE; + spotlessHook += "\nSPOTLESS_EXECUTOR=" + executor; + spotlessHook += "\nif ! $SPOTLESS_EXECUTOR " + commandCheck + " ; then"; + spotlessHook += "\n echo 1>&2 \"spotless found problems, running " + commandApply + "; commit the result and re-push\""; + spotlessHook += "\n $SPOTLESS_EXECUTOR " + commandApply; + spotlessHook += "\n exit 1"; + spotlessHook += "\nfi"; + spotlessHook += "\n" + HOOK_FOOTER; + spotlessHook += "\n"; + return spotlessHook; + } + /** * Checks if Git is installed by validating the existence of `.git/config` in the repository root. * @@ -145,38 +196,17 @@ private boolean isGitHookInstalled(File gitHookFile) throws Exception { * @param content The content to write into the file. * @throws IOException if an error occurs while writing to the file. */ - private void writeFile(File file, String content) throws IOException { - try (final var writer = new FileWriter(file, UTF_8, true)) { + private void writeFile(File file, String content, boolean append) throws IOException { + try (final var writer = new FileWriter(file, UTF_8, append)) { writer.write(content); } } - /** - * Generates a pre-push template script that defines the commands to check and apply changes - * using an executor and Spotless. - * - * @param executor The tool to execute the check and apply commands. - * @param commandCheck The command to check for issues. - * @param commandApply The command to apply corrections. - * @return A string template representing the Spotless Git pre-push hook content. - */ - protected String preHookTemplate(String executor, String commandCheck, String commandApply) { - var spotlessHook = "\n"; - spotlessHook += "\n" + HOOK_HEADLINE; - spotlessHook += "\nSPOTLESS_EXECUTOR=" + executor; - spotlessHook += "\nif ! $SPOTLESS_EXECUTOR " + commandCheck + " ; then"; - spotlessHook += "\n echo 1>&2 \"spotless found problems, running " + commandApply + "; commit the result and re-push\""; - spotlessHook += "\n $SPOTLESS_EXECUTOR " + commandApply; - spotlessHook += "\n exit 1"; - spotlessHook += "\nfi"; - spotlessHook += "\n" + HOOK_FOOTER; - spotlessHook += "\n\n"; - return spotlessHook; - } - public interface GitPreHookLogger { void info(String format, Object... arguments); + void warn(String format, Object... arguments); + void error(String format, Object... arguments); } } diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java index 8ae6e6cb94..cfed7cdd58 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java @@ -33,7 +33,6 @@ public GitPrePushHookInstallerGradle(GitPreHookLogger logger, File root) { this.gradlew = root.toPath().resolve("gradlew").toFile(); } - /** * {@inheritDoc} */ diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 6e6e648ed6..75c7c885c9 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -53,7 +53,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui - [**Quickstart**](#quickstart) - [Requirements](#requirements) - - [Git hook](#git-hook) + - [Git pre-push hook](#git-pre-push-hook) - [Linting](#linting) - **Languages** - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea)) @@ -142,9 +142,34 @@ Spotless requires JRE 11+ and Gradle 6.1.1 or newer. - If you're stuck on JRE 8, use [`id 'com.diffplug.spotless' version '6.13.0'` or older](https://github.com/diffplug/spotless/blob/main/plugin-gradle/CHANGES.md#6130---2023-01-14). - If you're stuck on an older version of Gradle, [`id 'com.diffplug.gradle.spotless' version '4.5.1'` supports all the way back to Gradle 2.x](https://github.com/diffplug/spotless/blob/main/plugin-gradle/CHANGES.md#451---2020-07-04). -### Git hook +### Git pre-push hook -TODO +You can install a Git pre-push hook that ensures code is properly formatted before being pushed to a remote repository. +This helps catch formatting issues early — before CI fails — and is especially useful for teams not using IDE integrations or pre-commit tools. + +#### What the hook does + +When installed, the Git `pre-push` hook will: + +1. Run `spotlessCheck` +2. If formatting issues are found: + - It automatically runs `spotlessApply` to fix them + - Aborts the push with a message + - You can then commit the changes and push again + +This ensures your code is always clean before it leaves your machine. + +#### Installation + +Run the following task once in your project: +```console +gradle spotlessInstallGitPrePushHook +``` + +This installs a `.git/hooks/pre-push` script that runs `spotlessCheck`, and runs `spotlessApply` if needed. + +> [!WARNING] +> The hook will not install automatically — you must run the install command manually. ### Linting diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java index 140bb8a755..2d6046d6fe 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java @@ -44,7 +44,7 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws assertThat(output).contains("Git pre-push hook not found, creating it"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); - final var content = getTestResource("git_pre_hook/pre-push.created") + final var content = getTestResource("git_pre_hook/pre-push.created-tpl") .replace("${executor}", "gradle") .replace("${checkCommand}", "spotlessCheck") .replace("${applyCommand}", "spotlessApply"); @@ -73,7 +73,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(output).contains("Installing git pre-push hook"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); - final var content = getTestResource("git_pre_hook/pre-push.existing-added") + final var content = getTestResource("git_pre_hook/pre-push.existing-added-tpl") .replace("${executor}", "gradle") .replace("${checkCommand}", "spotlessCheck") .replace("${applyCommand}", "spotlessApply"); diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 8cd01731ba..ade17248be 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -37,7 +37,7 @@ user@machine repo % mvn spotless:check - [**Quickstart**](#quickstart) - [Requirements](#requirements) - - [Git hook](#git-hook) + - [Git pre-push hook](#git-pre-push-hook) - [Binding to maven phase](#binding-to-maven-phase) - **Languages** - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea)) @@ -147,9 +147,34 @@ Spotless consists of a list of formats (in the example above, `misc` and `java`) Spotless requires Maven to be running on JRE 11+. To use JRE 8, go back to [`2.30.0` or older](https://github.com/diffplug/spotless/blob/main/plugin-maven/CHANGES.md#2300---2023-01-13). -### Git hook +### Git pre-push hook -TODO +You can install a Git pre-push hook that ensures code is properly formatted before being pushed to a remote repository. +This helps catch formatting issues early — before CI fails — and is especially useful for teams not using IDE integrations or pre-commit tools. + +#### What the hook does + +When installed, the Git `pre-push` hook will: + +1. Run `spotless:check` +2. If formatting issues are found: + - It automatically runs `spotless:apply` to fix them + - Aborts the push with a message + - You can then commit the changes and push again + +This ensures your code is always clean before it leaves your machine. + +#### Installation + +Run the following task once in your project: +```console +mvn spotless:install-git-pre-push-hook +``` + +This installs a `.git/hooks/pre-push` script that runs `spotless:check`, and runs `spotless:apply` if needed. + +> [!WARNING] +> The hook will not install automatically — you must run the install command manually. ### Binding to maven phase diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java index b9d5d6a343..dd11e10c36 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java @@ -41,8 +41,8 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws assertThat(output).contains("Git pre-push hook not found, creating it"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); - final var content = getTestResource("git_pre_hook/pre-push.created") - .replace("${executor}", "mvn") + final var content = getTestResource("git_pre_hook/pre-push.created-tpl") + .replace("${executor}", newFile("mvnw").getAbsolutePath()) .replace("${checkCommand}", "spotless:check") .replace("${applyCommand}", "spotless:apply"); assertFile(".git/hooks/pre-push").hasContent(content); @@ -67,8 +67,8 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(output).contains("Installing git pre-push hook"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); - final var content = getTestResource("git_pre_hook/pre-push.existing-added") - .replace("${executor}", "mvn") + final var content = getTestResource("git_pre_hook/pre-push.existing-added-tpl") + .replace("${executor}", newFile("mvnw").getAbsolutePath()) .replace("${checkCommand}", "spotless:check") .replace("${applyCommand}", "spotless:apply"); assertFile(".git/hooks/pre-push").hasContent(content); diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.created b/testlib/src/main/resources/git_pre_hook/pre-push.created-tpl similarity index 99% rename from testlib/src/main/resources/git_pre_hook/pre-push.created rename to testlib/src/main/resources/git_pre_hook/pre-push.created-tpl index 376598c605..8edbebebf6 100644 --- a/testlib/src/main/resources/git_pre_hook/pre-push.created +++ b/testlib/src/main/resources/git_pre_hook/pre-push.created-tpl @@ -9,4 +9,3 @@ if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then exit 1 fi ##### SPOTLESS HOOK END ##### - diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.existing-added b/testlib/src/main/resources/git_pre_hook/pre-push.existing-added-tpl similarity index 99% rename from testlib/src/main/resources/git_pre_hook/pre-push.existing-added rename to testlib/src/main/resources/git_pre_hook/pre-push.existing-added-tpl index fd107efaec..48330e5842 100644 --- a/testlib/src/main/resources/git_pre_hook/pre-push.existing-added +++ b/testlib/src/main/resources/git_pre_hook/pre-push.existing-added-tpl @@ -59,4 +59,3 @@ if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then exit 1 fi ##### SPOTLESS HOOK END ##### - diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.reinstalled-tpl b/testlib/src/main/resources/git_pre_hook/pre-push.reinstalled-tpl new file mode 100644 index 0000000000..ef970ea413 --- /dev/null +++ b/testlib/src/main/resources/git_pre_hook/pre-push.reinstalled-tpl @@ -0,0 +1,64 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + + + + + +##### SPOTLESS HOOK START ##### +SPOTLESS_EXECUTOR=${executor} +if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then + echo 1>&2 "spotless found problems, running ${applyCommand}; commit the result and re-push" + $SPOTLESS_EXECUTOR ${applyCommand} + exit 1 +fi +##### SPOTLESS HOOK END ##### diff --git a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java index b6fbcd26e8..4cd10ce8b8 100644 --- a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java @@ -74,15 +74,16 @@ public void should_use_global_gradle_when_gradlew_is_not_installed() throws Exce assertThat(logs).element(2).isEqualTo("Gradle wrapper is not installed, using global gradle"); assertThat(logs).element(3).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = gradleHookContent("git_pre_hook/pre-push.created", false); + final var content = gradleHookContent("git_pre_hook/pre-push.created-tpl", ExecutorType.GLOBAL); assertFile(".git/hooks/pre-push").hasContent(content); } @Test - public void should_not_create_pre_hook_file_when_hook_already_installed() throws Exception { + public void should_reinstall_pre_hook_file_when_hook_already_installed() throws Exception { // given final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); - final var hookFile = setFile(".git/hooks/pre-push").toResource("git_pre_hook/pre-push.existing-added"); + final var installedGlobally = gradleHookContent("git_pre_hook/pre-push.existing-added-tpl", ExecutorType.GLOBAL); + final var hookFile = setFile(".git/hooks/pre-push").toContent(installedGlobally); setFile("gradlew").toContent(""); setFile(".git/config").toContent(""); @@ -91,10 +92,13 @@ public void should_not_create_pre_hook_file_when_hook_already_installed() throws gradle.install(); // then - assertThat(logs).hasSize(2); + assertThat(logs).hasSize(3); assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); - assertThat(logs).element(1).isEqualTo("Skipping, git pre-push hook already installed " + hookFile.getAbsolutePath()); - assertThat(hookFile).content().isEqualTo(getTestResource("git_pre_hook/pre-push.existing-added")); + assertThat(logs).element(1).isEqualTo("Git pre-push hook already installed, reinstalling it"); + assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + hookFile.getAbsolutePath()); + + final var content = gradleHookContent("git_pre_hook/pre-push.reinstalled-tpl", ExecutorType.WRAPPER); + assertFile(".git/hooks/pre-push").hasContent(content); } @Test @@ -113,7 +117,7 @@ public void should_create_pre_hook_file_when_hook_file_does_not_exists() throws assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = gradleHookContent("git_pre_hook/pre-push.created", true); + final var content = gradleHookContent("git_pre_hook/pre-push.created-tpl", ExecutorType.WRAPPER); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -133,7 +137,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); assertThat(logs).element(1).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = gradleHookContent("git_pre_hook/pre-push.existing-added", true); + final var content = gradleHookContent("git_pre_hook/pre-push.existing-added-tpl", ExecutorType.WRAPPER); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -153,7 +157,7 @@ public void should_create_pre_hook_file_for_maven_when_hook_file_does_not_exists assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it"); assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = mavenHookContent("git_pre_hook/pre-push.created", true); + final var content = mavenHookContent("git_pre_hook/pre-push.created-tpl", ExecutorType.WRAPPER); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -173,21 +177,25 @@ public void should_use_global_maven_when_maven_wrapper_is_not_installed() throws assertThat(logs).element(2).isEqualTo("Maven wrapper is not installed, using global maven"); assertThat(logs).element(3).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = mavenHookContent("git_pre_hook/pre-push.created", false); + final var content = mavenHookContent("git_pre_hook/pre-push.created-tpl", ExecutorType.GLOBAL); assertFile(".git/hooks/pre-push").hasContent(content); } - private String gradleHookContent(String resourcePath, boolean isWrapper) { + private String gradleHookContent(String resourcePath, ExecutorType executorType) { return getTestResource(resourcePath) - .replace("${executor}", isWrapper ? newFile("gradlew").getAbsolutePath() : "gradle") + .replace("${executor}", executorType == ExecutorType.WRAPPER ? newFile("gradlew").getAbsolutePath() : "gradle") .replace("${checkCommand}", "spotlessCheck") .replace("${applyCommand}", "spotlessApply"); } - private String mavenHookContent(String resourcePath, boolean isWrapper) { + private String mavenHookContent(String resourcePath, ExecutorType executorType) { return getTestResource(resourcePath) - .replace("${executor}", isWrapper ? newFile("mvnw").getAbsolutePath() : "mvn") + .replace("${executor}", executorType == ExecutorType.WRAPPER ? newFile("mvnw").getAbsolutePath() : "mvn") .replace("${checkCommand}", "spotless:check") .replace("${applyCommand}", "spotless:apply"); } + + private enum ExecutorType { + WRAPPER, GLOBAL + } } From 259ec38f714178310e8625945ed74b83cb9a99ea Mon Sep 17 00:00:00 2001 From: ntwigg Date: Fri, 18 Jul 2025 12:53:35 -0700 Subject: [PATCH 193/210] Modify git-hook docs, with an eye towards a future where there is both a pre-push hook or a pre-commit hook, depending on what the user prefers. --- plugin-gradle/README.md | 25 +++++-------------------- plugin-maven/README.md | 31 ++++++++----------------------- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 75c7c885c9..05a99350fd 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -53,7 +53,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui - [**Quickstart**](#quickstart) - [Requirements](#requirements) - - [Git pre-push hook](#git-pre-push-hook) + - [Git hook (optional)](#git-hook) - [Linting](#linting) - **Languages** - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea)) @@ -142,16 +142,11 @@ Spotless requires JRE 11+ and Gradle 6.1.1 or newer. - If you're stuck on JRE 8, use [`id 'com.diffplug.spotless' version '6.13.0'` or older](https://github.com/diffplug/spotless/blob/main/plugin-gradle/CHANGES.md#6130---2023-01-14). - If you're stuck on an older version of Gradle, [`id 'com.diffplug.gradle.spotless' version '4.5.1'` supports all the way back to Gradle 2.x](https://github.com/diffplug/spotless/blob/main/plugin-gradle/CHANGES.md#451---2020-07-04). -### Git pre-push hook +### Git hook -You can install a Git pre-push hook that ensures code is properly formatted before being pushed to a remote repository. -This helps catch formatting issues early — before CI fails — and is especially useful for teams not using IDE integrations or pre-commit tools. +If you want, you can run `./gradlew spotlessInstallGitPrePushHook` and it will install a hook such that -#### What the hook does - -When installed, the Git `pre-push` hook will: - -1. Run `spotlessCheck` +1. When you push, it runs `spotlessCheck` 2. If formatting issues are found: - It automatically runs `spotlessApply` to fix them - Aborts the push with a message @@ -159,17 +154,7 @@ When installed, the Git `pre-push` hook will: This ensures your code is always clean before it leaves your machine. -#### Installation - -Run the following task once in your project: -```console -gradle spotlessInstallGitPrePushHook -``` - -This installs a `.git/hooks/pre-push` script that runs `spotlessCheck`, and runs `spotlessApply` if needed. - -> [!WARNING] -> The hook will not install automatically — you must run the install command manually. +If you prefer instead to have a "pre-commit" hook so that every single commit is clean, see [#623](https://github.com/diffplug/spotless/issues/623) for a workaround or to contribute a permanent fix. ### Linting diff --git a/plugin-maven/README.md b/plugin-maven/README.md index ade17248be..50b90ada1f 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -37,7 +37,7 @@ user@machine repo % mvn spotless:check - [**Quickstart**](#quickstart) - [Requirements](#requirements) - - [Git pre-push hook](#git-pre-push-hook) + - [Git hook (optional)](#git-hook) - [Binding to maven phase](#binding-to-maven-phase) - **Languages** - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [IntelliJ IDEA](#intellij-idea)) @@ -147,34 +147,19 @@ Spotless consists of a list of formats (in the example above, `misc` and `java`) Spotless requires Maven to be running on JRE 11+. To use JRE 8, go back to [`2.30.0` or older](https://github.com/diffplug/spotless/blob/main/plugin-maven/CHANGES.md#2300---2023-01-13). -### Git pre-push hook +### Git hook -You can install a Git pre-push hook that ensures code is properly formatted before being pushed to a remote repository. -This helps catch formatting issues early — before CI fails — and is especially useful for teams not using IDE integrations or pre-commit tools. +If you want, you can run `mvn spotless:install-git-pre-push-hook` and it will install a hook such that -#### What the hook does - -When installed, the Git `pre-push` hook will: - -1. Run `spotless:check` +1. When you push, it runs `spotless:check` 2. If formatting issues are found: - - It automatically runs `spotless:apply` to fix them - - Aborts the push with a message - - You can then commit the changes and push again + - It automatically runs `spotless:apply` to fix them + - Aborts the push with a message + - You can then commit the changes and push again This ensures your code is always clean before it leaves your machine. -#### Installation - -Run the following task once in your project: -```console -mvn spotless:install-git-pre-push-hook -``` - -This installs a `.git/hooks/pre-push` script that runs `spotless:check`, and runs `spotless:apply` if needed. - -> [!WARNING] -> The hook will not install automatically — you must run the install command manually. +If you prefer instead to have a "pre-commit" hook so that every single commit is clean, see [#623](https://github.com/diffplug/spotless/issues/623) for a workaround or to contribute a permanent fix. ### Binding to maven phase From 2dadeb609c02b26930a30086a277a14d0d0466b7 Mon Sep 17 00:00:00 2001 From: Alex Danylenko Date: Fri, 18 Jul 2025 20:09:10 -0700 Subject: [PATCH 194/210] uninstall fix --- .../spotless/GitPrePushHookInstaller.java | 55 +++++++++-- .../GitPrePushHookInstallerGradle.java | 4 +- .../GitPrePushHookInstallerMaven.java | 4 +- .../SpotlessInstallPrePushHookTaskTest.java | 2 +- .../SpotlessInstallPrePushHookMojoTest.java | 2 +- ...pl => pre-push.existing-installed-end-tpl} | 0 ...=> pre-push.existing-installed-middle-tpl} | 36 ++++++- .../pre-push.existing-reinstalled-middle-tpl | 94 +++++++++++++++++++ .../spotless/GitPrePushHookInstallerTest.java | 49 +++++++++- 9 files changed, 227 insertions(+), 19 deletions(-) rename testlib/src/main/resources/git_pre_hook/{pre-push.existing-added-tpl => pre-push.existing-installed-end-tpl} (100%) rename testlib/src/main/resources/git_pre_hook/{pre-push.reinstalled-tpl => pre-push.existing-installed-middle-tpl} (67%) create mode 100644 testlib/src/main/resources/git_pre_hook/pre-push.existing-reinstalled-middle-tpl diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java index b5070a003b..167e089b7d 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java @@ -31,7 +31,7 @@ */ public abstract class GitPrePushHookInstaller { - private static final String HOOK_HEADLINE = "##### SPOTLESS HOOK START #####"; + private static final String HOOK_HEADER = "##### SPOTLESS HOOK START #####"; private static final String HOOK_FOOTER = "##### SPOTLESS HOOK END #####"; /** @@ -128,10 +128,48 @@ public void install() throws Exception { */ private void uninstall(File gitHookFile) throws Exception { final var hook = Files.readString(gitHookFile.toPath(), UTF_8); - final var hookStart = hook.indexOf(HOOK_HEADLINE); - final var hookEnd = hook.indexOf(HOOK_FOOTER) + HOOK_FOOTER.length(); + final int hookStart = hook.indexOf(HOOK_HEADER); + final int hookEnd = hook.indexOf(HOOK_FOOTER) + HOOK_FOOTER.length(); // hookEnd exclusive, so must be last symbol \n + + /* Detailed explanation: + * 1. hook.indexOf(HOOK_FOOTER) - finds the starting position of footer "##### SPOTLESS HOOK END #####" + * 2. + HOOK_FOOTER.length() is needed because String.substring(startIndex, endIndex) treats endIndex as exclusive + * + * For example, if file content is: + * #!/bin/sh + * ##### SPOTLESS HOOK START ##### + * ... hook code ... + * ##### SPOTLESS HOOK END ##### + * other content + * + * When we later use this in: hook.substring(hookStart, hookEnd) + * - Since substring's endIndex is exclusive (it stops BEFORE that index) + * - We need hookEnd to point to the position AFTER the last '#' + * - This ensures the entire footer "##### SPOTLESS HOOK END #####" is included in the substring + * + * This exclusive behavior is why in the subsequent code: + * if (hook.charAt(hookEnd) == '\n') { + * hookScript += "\n"; + * } + * + * We can directly use hookEnd to check the next character after the footer + * - Since hookEnd is already pointing to the position AFTER the footer + * - No need for hookEnd + 1 in charAt() + * - This makes the code more consistent with the substring's exclusive nature + */ + + var hookScript = hook.substring(hookStart, hookEnd); + if (hookStart >= 1 && hook.charAt(hookStart - 1) == '\n') { + hookScript = "\n" + hookScript; + } + + if (hookStart >= 2 && hook.charAt(hookStart - 2) == '\n') { + hookScript = "\n" + hookScript; + } - final var hookScript = hook.substring(hookStart, hookEnd); + if (hook.charAt(hookEnd) == '\n') { + hookScript += "\n"; + } final var uninstalledHook = hook.replace(hookScript, ""); @@ -155,8 +193,10 @@ private void uninstall(File gitHookFile) throws Exception { * @return A string template representing the Spotless Git pre-push hook content. */ protected String preHookTemplate(String executor, String commandCheck, String commandApply) { - var spotlessHook = "\n"; - spotlessHook += "\n" + HOOK_HEADLINE; + var spotlessHook = ""; + + spotlessHook += "\n"; + spotlessHook += "\n" + HOOK_HEADER; spotlessHook += "\nSPOTLESS_EXECUTOR=" + executor; spotlessHook += "\nif ! $SPOTLESS_EXECUTOR " + commandCheck + " ; then"; spotlessHook += "\n echo 1>&2 \"spotless found problems, running " + commandApply + "; commit the result and re-push\""; @@ -165,6 +205,7 @@ protected String preHookTemplate(String executor, String commandCheck, String co spotlessHook += "\nfi"; spotlessHook += "\n" + HOOK_FOOTER; spotlessHook += "\n"; + return spotlessHook; } @@ -186,7 +227,7 @@ private boolean isGitInstalled() { */ private boolean isGitHookInstalled(File gitHookFile) throws Exception { final var hook = Files.readString(gitHookFile.toPath(), UTF_8); - return hook.contains(HOOK_HEADLINE); + return hook.contains(HOOK_HEADER) && hook.contains(HOOK_FOOTER); } /** diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java index cfed7cdd58..0b11db5cab 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java @@ -38,10 +38,10 @@ public GitPrePushHookInstallerGradle(GitPreHookLogger logger, File root) { */ @Override protected String preHookContent() { - return preHookTemplate(executor(), "spotlessCheck", "spotlessApply"); + return preHookTemplate(executorPath(), "spotlessCheck", "spotlessApply"); } - private String executor() { + private String executorPath() { if (gradlew.exists()) { return gradlew.getAbsolutePath(); } diff --git a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java index 7f84d85429..138d27f9a3 100644 --- a/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java +++ b/lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java @@ -35,10 +35,10 @@ public GitPrePushHookInstallerMaven(GitPreHookLogger logger, File root) { */ @Override protected String preHookContent() { - return preHookTemplate(executor(), "spotless:check", "spotless:apply"); + return preHookTemplate(executorPath(), "spotless:check", "spotless:apply"); } - private String executor() { + private String executorPath() { if (mvnw.exists()) { return mvnw.getAbsolutePath(); } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java index 2d6046d6fe..d5ff385b82 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpotlessInstallPrePushHookTaskTest.java @@ -73,7 +73,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(output).contains("Installing git pre-push hook"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); - final var content = getTestResource("git_pre_hook/pre-push.existing-added-tpl") + final var content = getTestResource("git_pre_hook/pre-push.existing-installed-end-tpl") .replace("${executor}", "gradle") .replace("${checkCommand}", "spotlessCheck") .replace("${applyCommand}", "spotlessApply"); diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java index dd11e10c36..ebfc13d982 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessInstallPrePushHookMojoTest.java @@ -67,7 +67,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(output).contains("Installing git pre-push hook"); assertThat(output).contains("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push")); - final var content = getTestResource("git_pre_hook/pre-push.existing-added-tpl") + final var content = getTestResource("git_pre_hook/pre-push.existing-installed-end-tpl") .replace("${executor}", newFile("mvnw").getAbsolutePath()) .replace("${checkCommand}", "spotless:check") .replace("${applyCommand}", "spotless:apply"); diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.existing-added-tpl b/testlib/src/main/resources/git_pre_hook/pre-push.existing-installed-end-tpl similarity index 100% rename from testlib/src/main/resources/git_pre_hook/pre-push.existing-added-tpl rename to testlib/src/main/resources/git_pre_hook/pre-push.existing-installed-end-tpl diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.reinstalled-tpl b/testlib/src/main/resources/git_pre_hook/pre-push.existing-installed-middle-tpl similarity index 67% rename from testlib/src/main/resources/git_pre_hook/pre-push.reinstalled-tpl rename to testlib/src/main/resources/git_pre_hook/pre-push.existing-installed-middle-tpl index ef970ea413..63f7da0a0b 100644 --- a/testlib/src/main/resources/git_pre_hook/pre-push.reinstalled-tpl +++ b/testlib/src/main/resources/git_pre_hook/pre-push.existing-installed-middle-tpl @@ -51,9 +51,6 @@ do done - - - ##### SPOTLESS HOOK START ##### SPOTLESS_EXECUTOR=${executor} if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then @@ -62,3 +59,36 @@ if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then exit 1 fi ##### SPOTLESS HOOK END ##### + + +# some additional pre-push code +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done diff --git a/testlib/src/main/resources/git_pre_hook/pre-push.existing-reinstalled-middle-tpl b/testlib/src/main/resources/git_pre_hook/pre-push.existing-reinstalled-middle-tpl new file mode 100644 index 0000000000..7265927c13 --- /dev/null +++ b/testlib/src/main/resources/git_pre_hook/pre-push.existing-reinstalled-middle-tpl @@ -0,0 +1,94 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + + +# some additional pre-push code +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + + +##### SPOTLESS HOOK START ##### +SPOTLESS_EXECUTOR=${executor} +if ! $SPOTLESS_EXECUTOR ${checkCommand} ; then + echo 1>&2 "spotless found problems, running ${applyCommand}; commit the result and re-push" + $SPOTLESS_EXECUTOR ${applyCommand} + exit 1 +fi +##### SPOTLESS HOOK END ##### diff --git a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java index 4cd10ce8b8..6167e26b8c 100644 --- a/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java @@ -82,7 +82,7 @@ public void should_use_global_gradle_when_gradlew_is_not_installed() throws Exce public void should_reinstall_pre_hook_file_when_hook_already_installed() throws Exception { // given final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); - final var installedGlobally = gradleHookContent("git_pre_hook/pre-push.existing-added-tpl", ExecutorType.GLOBAL); + final var installedGlobally = gradleHookContent("git_pre_hook/pre-push.existing-installed-end-tpl", ExecutorType.GLOBAL); final var hookFile = setFile(".git/hooks/pre-push").toContent(installedGlobally); setFile("gradlew").toContent(""); @@ -97,7 +97,50 @@ public void should_reinstall_pre_hook_file_when_hook_already_installed() throws assertThat(logs).element(1).isEqualTo("Git pre-push hook already installed, reinstalling it"); assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + hookFile.getAbsolutePath()); - final var content = gradleHookContent("git_pre_hook/pre-push.reinstalled-tpl", ExecutorType.WRAPPER); + final var content = gradleHookContent("git_pre_hook/pre-push.existing-installed-end-tpl", ExecutorType.WRAPPER); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + @Test + public void should_reinstall_pre_hook_file_when_hook_already_installed_in_the_middle_of_file() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); + final var installedGlobally = gradleHookContent("git_pre_hook/pre-push.existing-installed-middle-tpl", ExecutorType.GLOBAL); + final var hookFile = setFile(".git/hooks/pre-push").toContent(installedGlobally); + + setFile("gradlew").toContent(""); + setFile(".git/config").toContent(""); + + // when + gradle.install(); + + // then + assertThat(logs).hasSize(3); + assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); + assertThat(logs).element(1).isEqualTo("Git pre-push hook already installed, reinstalling it"); + assertThat(logs).element(2).isEqualTo("Git pre-push hook installed successfully to the file " + hookFile.getAbsolutePath()); + + final var content = gradleHookContent("git_pre_hook/pre-push.existing-reinstalled-middle-tpl", ExecutorType.WRAPPER); + assertFile(".git/hooks/pre-push").hasContent(content); + } + + @Test + public void should_reinstall_a_few_times_pre_hook_file_when_hook_already_installed_in_the_middle_of_file() throws Exception { + // given + final var gradle = new GitPrePushHookInstallerGradle(logger, rootFolder()); + final var installedGlobally = gradleHookContent("git_pre_hook/pre-push.existing-installed-middle-tpl", ExecutorType.GLOBAL); + setFile(".git/hooks/pre-push").toContent(installedGlobally); + + setFile("gradlew").toContent(""); + setFile(".git/config").toContent(""); + + // when + gradle.install(); + gradle.install(); + gradle.install(); + + // then + final var content = gradleHookContent("git_pre_hook/pre-push.existing-reinstalled-middle-tpl", ExecutorType.WRAPPER); assertFile(".git/hooks/pre-push").hasContent(content); } @@ -137,7 +180,7 @@ public void should_append_to_existing_pre_hook_file_when_hook_file_exists() thro assertThat(logs).element(0).isEqualTo("Installing git pre-push hook"); assertThat(logs).element(1).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath()); - final var content = gradleHookContent("git_pre_hook/pre-push.existing-added-tpl", ExecutorType.WRAPPER); + final var content = gradleHookContent("git_pre_hook/pre-push.existing-installed-end-tpl", ExecutorType.WRAPPER); assertFile(".git/hooks/pre-push").hasContent(content); } From cee700945d4c5aa50af52d5739fb68de53f7753f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Jul 2025 06:12:35 +0000 Subject: [PATCH 195/210] fix(deps): update jackson monorepo to v2.19.2 (#2558) * fix(deps): update jackson monorepo to v2.19.2 * Updates --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler --- CHANGES.md | 2 +- lib/build.gradle | 2 +- .../main/java/com/diffplug/spotless/json/JacksonJsonStep.java | 2 +- plugin-gradle/CHANGES.md | 2 +- plugin-maven/CHANGES.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e98e32f712..53bdbdfaf7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,7 +15,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) -* Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) +* Bump default `jackson` version to latest `2.18.1` -> `2.19.2`. ([#2558](https://github.com/diffplug/spotless/pull/2558)) * Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) * Bump default `cleanthat` version to latest `2.22` -> `2.23`. ([#2556](https://github.com/diffplug/spotless/pull/2556)) diff --git a/lib/build.gradle b/lib/build.gradle index 16477b066c..134f3285b5 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -98,7 +98,7 @@ dependencies { // gson gsonCompileOnly 'com.google.code.gson:gson:2.13.1' // jackson - String VER_JACKSON='2.19.1' + String VER_JACKSON='2.19.2' jacksonCompileOnly "com.fasterxml.jackson.core:jackson-databind:$VER_JACKSON" jacksonCompileOnly "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$VER_JACKSON" // ktfmt diff --git a/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java b/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java index d8f395129e..fe4bf36b30 100644 --- a/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java +++ b/lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java @@ -32,7 +32,7 @@ public class JacksonJsonStep implements Serializable { private static final long serialVersionUID = 1L; private static final String MAVEN_COORDINATE = "com.fasterxml.jackson.core:jackson-databind:"; - private static final String DEFAULT_VERSION = "2.19.1"; + private static final String DEFAULT_VERSION = "2.19.2"; public static final String NAME = "jacksonJson"; private final JarState.Promised jarState; diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index dd1e9c425f..d08e2c2755 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -8,7 +8,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) -* Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) +* Bump default `jackson` version to latest `2.18.1` -> `2.19.2`. ([#2558](https://github.com/diffplug/spotless/pull/2558)) * Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) * Bump default `cleanthat` version to latest `2.22` -> `2.23`. ([#2556](https://github.com/diffplug/spotless/pull/2556)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 6829753b2e..72308379e6 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -8,7 +8,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) -* Bump default `jackson` version to latest `2.18.1` -> `2.19.1`. ([#2352](https://github.com/diffplug/spotless/pull/2352)) +* Bump default `jackson` version to latest `2.18.1` -> `2.19.2`. ([#2558](https://github.com/diffplug/spotless/pull/2558)) * Bump default `gherkin-utils` version to latest `9.0.0` -> `9.2.0`. ([#2408](https://github.com/diffplug/spotless/pull/2408)) * Bump default `cleanthat` version to latest `2.22` -> `2.23`. ([#2556](https://github.com/diffplug/spotless/pull/2556)) From b26c800afef0fb61561f85f6ff27b33705004953 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Sun, 20 Jul 2025 09:53:09 -0700 Subject: [PATCH 196/210] Update changelogs. --- CHANGES.md | 5 ++--- plugin-gradle/CHANGES.md | 4 ++-- plugin-maven/CHANGES.md | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6184c9c851..7a68a5d044 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,8 +12,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) -- `GitPrePushHookInstaller`, a reusable library component for installing a Git `pre-push` hook that runs formatter checks. - +* `GitPrePushHookInstaller`, a reusable library component for installing a Git `pre-push` hook that runs formatter checks. +* Allow setting Eclipse XML config from a string, not only from files ([#2361](https://github.com/diffplug/spotless/pull/2361)) ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.2`. ([#2558](https://github.com/diffplug/spotless/pull/2558)) @@ -42,7 +42,6 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [3.1.1] - 2025-04-07 ### Changed -* Allow setting Eclipse XML config from a string, not only from files ([#2361](https://github.com/diffplug/spotless/pull/2361)) * Use palantir-java-format 2.57.0 on Java 21. ([#2447](https://github.com/diffplug/spotless/pull/2447)) * Re-try `npm install` with `--prefer-online` after `ERESOLVE` error. ([#2448](https://github.com/diffplug/spotless/pull/2448)) * Allow multiple npm-based formatters having the same module dependencies, to share a `node_modules` dir without race conditions. [#2462](https://github.com/diffplug/spotless/pull/2462)) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index c13377f49b..6e33cab329 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -5,10 +5,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) -- `spotlessInstallGitPrePushHook` task, which installs a Git `pre-push` hook to run `spotlessCheck` and `spotlessApply`. +* `spotlessInstallGitPrePushHook` task, which installs a Git `pre-push` hook to run `spotlessCheck` and `spotlessApply`. Uses shared implementation from `GitPrePushHookInstaller`. [#2553](https://github.com/diffplug/spotless/pull/2553) - +* Allow setting Eclipse XML config from a string, not only from files ([#2361](https://github.com/diffplug/spotless/pull/2361)) ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.2`. ([#2558](https://github.com/diffplug/spotless/pull/2558)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index d7b900689e..c7a2caba7d 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -5,10 +5,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) -- `spotless:install-git-pre-push-hook` goal, which installs a Git `pre-push` hook to run `spotless:check` and `spotless:apply`. +*`spotless:install-git-pre-push-hook` goal, which installs a Git `pre-push` hook to run `spotless:check` and `spotless:apply`. Uses shared implementation from `GitPrePushHookInstaller`. [#2553](https://github.com/diffplug/spotless/pull/2553) - ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.2`. ([#2558](https://github.com/diffplug/spotless/pull/2558)) From b12ff7c47f7afb65217f5b1d917c10e221b61f58 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Sun, 20 Jul 2025 10:00:43 -0700 Subject: [PATCH 197/210] More changelog fixup. --- CHANGES.md | 2 +- plugin-gradle/CHANGES.md | 4 +--- plugin-maven/CHANGES.md | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7a68a5d044..92525bbfdc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) -* `GitPrePushHookInstaller`, a reusable library component for installing a Git `pre-push` hook that runs formatter checks. +* `GitPrePushHookInstaller`, a reusable library component for installing a Git `pre-push` hook that runs formatter checks. ([#2553](https://github.com/diffplug/spotless/pull/2553)) * Allow setting Eclipse XML config from a string, not only from files ([#2361](https://github.com/diffplug/spotless/pull/2361)) ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 6e33cab329..9e3d18ffa6 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -5,9 +5,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) -* `spotlessInstallGitPrePushHook` task, which installs a Git `pre-push` hook to run `spotlessCheck` and `spotlessApply`. - Uses shared implementation from `GitPrePushHookInstaller`. - [#2553](https://github.com/diffplug/spotless/pull/2553) +* `spotlessInstallGitPrePushHook` task, which installs a Git `pre-push` hook to run `spotlessCheck` and `spotlessApply`. ([#2553](https://github.com/diffplug/spotless/pull/2553)) * Allow setting Eclipse XML config from a string, not only from files ([#2361](https://github.com/diffplug/spotless/pull/2361)) ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index c7a2caba7d..b2de9d10ca 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -5,9 +5,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) -*`spotless:install-git-pre-push-hook` goal, which installs a Git `pre-push` hook to run `spotless:check` and `spotless:apply`. - Uses shared implementation from `GitPrePushHookInstaller`. - [#2553](https://github.com/diffplug/spotless/pull/2553) +* `spotless:install-git-pre-push-hook` goal, which installs a Git `pre-push` hook to run `spotless:check` and `spotless:apply`. ([#2553](https://github.com/diffplug/spotless/pull/2553)) ## Changed * Bump default `gson` version to latest `2.11.0` -> `2.13.1`. ([#2414](https://github.com/diffplug/spotless/pull/2414)) * Bump default `jackson` version to latest `2.18.1` -> `2.19.2`. ([#2558](https://github.com/diffplug/spotless/pull/2558)) From 0d0192d39933831eb799e5bf830acc92caf86425 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Sun, 20 Jul 2025 10:31:48 -0700 Subject: [PATCH 198/210] Use try-with-resources to make sure we don't have dangling streams. --- .../diffplug/spotless/FormatterProperties.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java b/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java index ad180ab77a..499314ee3d 100644 --- a/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java +++ b/lib/src/main/java/com/diffplug/spotless/FormatterProperties.java @@ -185,12 +185,17 @@ protected Properties executeXmlContent(String content) throws IOException, Illeg } private Properties executeWithSupplier(Supplier isSupplier) throws IOException, IllegalArgumentException { - Node rootNode = getRootNode(isSupplier.get()); - String nodeName = rootNode.getNodeName(); - if (null == nodeName) { - throw new IllegalArgumentException("XML document does not contain a root node."); + Node rootNode; + try (InputStream input = isSupplier.get()) { + rootNode = getRootNode(input); + String nodeName = rootNode.getNodeName(); + if (null == nodeName) { + throw new IllegalArgumentException("XML document does not contain a root node."); + } + } + try (InputStream input = isSupplier.get()) { + return XmlParser.parse(input, rootNode); } - return XmlParser.parse(isSupplier.get(), rootNode); } private Node getRootNode(final InputStream is) throws IOException, IllegalArgumentException { From 015df60ea813ebf4d17f90d2e983248179501d5f Mon Sep 17 00:00:00 2001 From: runner Date: Sun, 20 Jul 2025 18:56:21 +0000 Subject: [PATCH 199/210] Published lib/3.3.0 --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 92525bbfdc..f4ac244ba4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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] + +## [3.3.0] - 2025-07-20 ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) * `GitPrePushHookInstaller`, a reusable library component for installing a Git `pre-push` hook that runs formatter checks. ([#2553](https://github.com/diffplug/spotless/pull/2553)) From 3ce3f7330daf819d7912a8a7e27523beb45a2801 Mon Sep 17 00:00:00 2001 From: runner Date: Sun, 20 Jul 2025 18:57:12 +0000 Subject: [PATCH 200/210] Published gradle/7.2.0 --- plugin-gradle/CHANGES.md | 2 ++ plugin-gradle/README.md | 62 ++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 9e3d18ffa6..0d89813e56 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] + +## [7.2.0] - 2025-07-20 ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) * `spotlessInstallGitPrePushHook` task, which installs a Git `pre-push` hook to run `spotlessCheck` and `spotlessApply`. ([#2553](https://github.com/diffplug/spotless/pull/2553)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index e6b6a37226..c22dab94f7 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -14,9 +14,9 @@ output = [ ].join('\n'); --> [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.1.0-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.2.0-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -130,10 +130,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -189,7 +189,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -405,8 +405,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -469,8 +469,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle @@ -569,7 +569,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -601,7 +601,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -641,7 +641,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -677,7 +677,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -709,7 +709,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -730,7 +730,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -749,7 +749,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -774,7 +774,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -813,7 +813,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -862,7 +862,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -956,7 +956,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -1019,7 +1019,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1139,7 +1139,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1171,7 +1171,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1207,7 +1207,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1236,7 +1236,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1692,7 +1692,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1778,9 +1778,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1813,11 +1813,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.1.0/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From 94da761e14d554ae61f6e665328d7c25d9a86e85 Mon Sep 17 00:00:00 2001 From: runner Date: Sun, 20 Jul 2025 18:58:42 +0000 Subject: [PATCH 201/210] Published maven/2.46.0 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index b2de9d10ca..b91be43d79 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.46.0] - 2025-07-20 ### Added * Allow specifying path to Biome JSON config file directly in `biome` step. Requires biome 2.x. ([#2548](https://github.com/diffplug/spotless/pull/2548)) * `spotless:install-git-pre-push-hook` goal, which installs a Git `pre-push` hook to run `spotless:check` and `spotless:apply`. ([#2553](https://github.com/diffplug/spotless/pull/2553)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 50b90ada1f..ae427d8726 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.45.0-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.45.0/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.46.0-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.46.0/index.html) [![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.spotless) -[![Changelog](https://img.shields.io/badge/changelog-7.2.0-blue.svg)](CHANGES.md) +[![Changelog](https://img.shields.io/badge/changelog-7.2.1-blue.svg)](CHANGES.md) [![MavenCentral](https://img.shields.io/badge/mavencentral-here-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-plugin-gradle%22) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/index.html) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/index.html) [![VS Code plugin](https://img.shields.io/badge/IDE-VS_Code-blueviolet.svg)](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) [![IntelliJ plugin](https://img.shields.io/badge/IDE-IntelliJ-blueviolet.svg)](https://plugins.jetbrains.com/plugin/18321-spotless-gradle) @@ -130,10 +130,10 @@ spotless { ``` Spotless consists of a list of formats (in the example above, `misc` and `java`), and each format has: -- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) -- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. +- a `target` (the files to format), which you set with [`target`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#target-java.lang.Object...-) and [`targetExclude`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#targetExclude-java.lang.Object...-) +- a list of `FormatterStep`, which are just `String -> String` functions, such as [`replace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`replaceRegex`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#replaceRegex-java.lang.String-java.lang.String-java.lang.String-), [`trimTrailingWhitespace`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#replace-java.lang.String-java.lang.CharSequence-java.lang.CharSequence-), [`custom`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#custom-java.lang.String-groovy.lang.Closure-), [`prettier`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#prettier--), [`eclipseWtp`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#eclipseWtp-com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep-), [`licenseHeader`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#licenseHeader-java.lang.String-java.lang.String-) etc. -All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. +All the generic steps live in [`FormatExtension`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html), and there are many language-specific steps which live in its language-specific subclasses, which are described below. ### Requirements @@ -189,7 +189,7 @@ Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is j ## Java -`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) +`com.diffplug.gradle.spotless.JavaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/JavaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java) ```gradle spotless { @@ -405,8 +405,8 @@ spotless { ## Groovy -- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) -- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) +- `com.diffplug.gradle.spotless.GroovyExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/GroovyExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java) +- `com.diffplug.gradle.spotless.GroovyGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/GroovyGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyGradleExtension.java) Configuration for Groovy is similar to [Java](#java), in that it also supports `licenseHeader` and `importOrder`. @@ -469,8 +469,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ## Kotlin -- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) -- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) +- `com.diffplug.gradle.spotless.KotlinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/KotlinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java) +- `com.diffplug.gradle.spotless.KotlinGradleExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/KotlinGradleExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinGradleExtension.java) ```gradle @@ -569,7 +569,7 @@ spotless { ## Scala -`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) +`com.diffplug.gradle.spotless.ScalaExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/ScalaExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java) ```gradle spotless { @@ -601,7 +601,7 @@ spotless { ## C/C++ -`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) +`com.diffplug.gradle.spotless.CppExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/CppExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java) ```gradle spotless { @@ -641,7 +641,7 @@ spotles { ## Python -`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) +`com.diffplug.gradle.spotless.PythonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/PythonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PythonExtension.java) ```gradle spotless { @@ -677,7 +677,7 @@ black().pathToExe('C:/myuser/.pyenv/versions/3.8.0/scripts/black.exe') ### buf -`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) +`com.diffplug.gradle.spotless.ProtobufExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/ProtobufExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ProtobufExtension.java) **WARNING** this step **must** be the first step in the chain, steps before it will be ignored. Thumbs up [this issue](https://github.com/bufbuild/buf/issues/1035) for a resolution, see [here](https://github.com/diffplug/spotless/pull/1208#discussion_r1264439669) for more details on the problem. @@ -709,7 +709,7 @@ buf { ## FreshMark -`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) +`com.diffplug.gradle.spotless.FreshMarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FreshMarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FreshMarkExtension.java) [homepage](https://github.com/diffplug/freshmark). [changelog](https://github.com/diffplug/freshmark/blob/master/CHANGES.md). FreshMark lets you generate markdown in the comments of your markdown. This helps to keep badges and links up-to-date (see the source for this file), and can also be helpful for generating complex tables (see the source for [the parent readme](../README.md)). @@ -730,7 +730,7 @@ spotless { ## Flexmark -`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) +`com.diffplug.gradle.spotless.FlexmarkExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FlexmarkExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FlexmarkExtension.java) [homepage](https://github.com/vsch/flexmark-java). Flexmark is a flexible Commonmark/Markdown parser that can be used to format Markdown files. It supports different [flavors of Markdown](https://github.com/vsch/flexmark-java#markdown-processor-emulation) and [many formatting options](https://github.com/vsch/flexmark-java/wiki/Markdown-Formatter#options). @@ -749,7 +749,7 @@ spotless { ## Antlr4 -`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) +`com.diffplug.gradle.spotless.Antlr4Extension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/Antlr4Extension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/Antlr4Extension.java) ```gradle spotless { @@ -774,7 +774,7 @@ antlr4formatter('1.2.1') // version is optional ## SQL -`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) +`com.diffplug.gradle.spotless.SqlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/SqlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SqlExtension.java) ```gradle spotless { @@ -813,7 +813,7 @@ sql.formatter.indent.size=4 ## Maven POM -`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) +`com.diffplug.gradle.spotless.PomExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/PomExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java) ```gradle spotless { @@ -862,7 +862,7 @@ spotless { ## Typescript -- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) +- `com.diffplug.gradle.spotless.TypescriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/TypescriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/TypescriptExtension.java) ```gradle spotless { @@ -956,7 +956,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## Javascript -- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) +- `com.diffplug.gradle.spotless.JavascriptExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/JavascriptExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java) ```gradle spotless { @@ -1019,7 +1019,7 @@ For details, see the [npm detection](#npm-detection), [`.npmrc` detection](#npmr ## JSON -- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) +- `com.diffplug.gradle.spotless.JsonExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/JsonExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JsonExtension.java) ```gradle spotless { @@ -1139,7 +1139,7 @@ spotless { ## YAML -- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) +- `com.diffplug.gradle.spotless.YamlExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/YamlExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/YamlExtension.java) ```gradle spotless { @@ -1171,7 +1171,7 @@ spotless { ## Shell -`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) +`com.diffplug.gradle.spotless.ShellExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/ShellExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ShellExtension.java) ```gradle spotless { @@ -1207,7 +1207,7 @@ shfmt().pathToExe('/opt/homebrew/bin/shfmt') ## Gherkin -- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) +- `com.diffplug.gradle.spotless.GherkinExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/GherkinExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GherkinExtension.java) ```gradle spotless { @@ -1236,7 +1236,7 @@ spotless { ## CSS -`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) +`com.diffplug.gradle.spotless.CssExtension` [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/CssExtension.html), [code](https://github.com/diffplug/spotless/blob/main/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CssExtension.java) ```gradle spotless { @@ -1692,7 +1692,7 @@ Once a file's license header has a valid year, whether it is a year (`2020`) or * `2017` -> `2017-2020` * `2017-2019` -> `2017-2020` -See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. +See the [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.LicenseHeaderConfig.html) for a complete listing of options. @@ -1778,9 +1778,9 @@ spotless { custom 'lowercase', { str -> str.toLowerCase() } ``` -However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. +However, custom rules will disable up-to-date checking and caching, unless you read [this javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) and follow its instructions carefully. -Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! +Another option is to create proper `FormatterStep` in your `buildSrc`, and then call [`addStep`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#addStep-com.diffplug.spotless.FormatterStep-). The contributing guide describes [how to do this](https://github.com/diffplug/spotless/blob/main/CONTRIBUTING.md#how-to-add-a-new-formatterstep). If the step is generally-useful, we hope you'll open a PR to share it! ```gradle @@ -1813,11 +1813,11 @@ spotless { format 'foo', com.acme.FooLanguageExtension, { ``` -If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). +If you'd like to create a one-off Spotless task outside of the `check`/`apply` framework, see [`FormatExtension.createIndependentApplyTask`](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#createIndependentApplyTask-java.lang.String-). ## Inception (languages within languages within...) -In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.0/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. +In very rare cases, you might want to format e.g. javascript which is written inside JSP templates, or maybe java within a markdown file, or something wacky like that. You can specify hunks within a file using either open/close tags or a regex with a single capturing group, and then specify rules within it, like so. See [javadoc](https://javadoc.io/doc/com.diffplug.spotless/spotless-plugin-gradle/7.2.1/com/diffplug/gradle/spotless/FormatExtension.html#withinBlocks-java.lang.String-java.lang.String-java.lang.String-org.gradle.api.Action-) for more details. ```gradle import com.diffplug.gradle.spotless.JavaExtension From 0572107174aad6709d12d64d4c875b53bb2042ed Mon Sep 17 00:00:00 2001 From: runner Date: Mon, 21 Jul 2025 19:18:02 +0000 Subject: [PATCH 210/210] Published maven/2.46.1 --- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index e1a8ac602b..2f1d93723c 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] + +## [2.46.1] - 2025-07-21 ### Fixed * `spotless:install-git-pre-push-hook` didn't work on windows, now fixed. ([#2562](https://github.com/diffplug/spotless/pull/2562)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index ae427d8726..d0c658d40c 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -8,8 +8,8 @@ output = [ ].join('\n'); --> [![MavenCentral](https://img.shields.io/badge/mavencentral-com.diffplug.spotless%3Aspotless--maven--plugin-blue.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.spotless%22%20AND%20a%3A%22spotless-maven-plugin%22) -[![Changelog](https://img.shields.io/badge/changelog-2.46.0-blue.svg)](CHANGES.md) -[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.46.0/index.html) +[![Changelog](https://img.shields.io/badge/changelog-2.46.1-blue.svg)](CHANGES.md) +[![Javadoc](https://img.shields.io/badge/javadoc-here-blue.svg)](https://javadoc.io/doc/com.diffplug.spotless/spotless-maven-plugin/2.46.1/index.html)