diff --git a/CHANGES.md b/CHANGES.md index 0e8940dec6..cbe48b5235 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 * Maven - Support for formatting shell scripts via [shfmt](https://github.com/mvdan/sh). ([#1998](https://github.com/diffplug/spotless/pull/1998)) +* Maven / Gradle - Support for formatting Java Docs for the Palantir formatter ([#2009](https://github.com/diffplug/spotless/pull/2009)) ## [2.44.0] - 2024-01-15 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6fb993f419..f0a4b4d59c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -171,6 +171,17 @@ gradlew :plugin-maven:test --tests com.diffplug.spotless.maven.pom.SortPomMavenT gradlew :plugin-gradle:test --tests com.diffplug.gradle.spotless.FreshMarkExtensionTest ``` +## Check and format code + +Before creating a pull request, you might want to format (yes, spotless is formatted by spotless) +the code and check for possible bugs + +* `./gradlew spotlessApply` +* `./gradlew spotbugsMain` + +These checks are also run by the automated pipeline when you submit a pull request, if +the pipeline fails, first check if the code is formatted and no bugs were found. + ## Integration testing ### Gradle - locally 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 95f7b355f7..a670a6fea7 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java @@ -27,6 +27,7 @@ public class PalantirJavaFormatStep { // prevent direct instantiation private PalantirJavaFormatStep() {} + private static final boolean DEFAULT_FORMAT_JAVADOC = false; 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:"; @@ -42,14 +43,25 @@ public static FormatterStep create(String version, Provisioner provisioner) { return create(version, defaultStyle(), provisioner); } - /** Creates a step which formats everything - code, import order, and unused imports. And with the style input. */ + /** + * Creates a step which formats code, import order, and unused imports, but not Java docs. And with the given format + * style. + */ public static FormatterStep create(String version, String style, Provisioner provisioner) { + return create(version, style, DEFAULT_FORMAT_JAVADOC, provisioner); + } + + /** + * Creates a step which formats everything - code, import order, unused imports, and Java docs. And with the given + * format style. + */ + public static FormatterStep create(String version, String style, boolean formatJavadoc, Provisioner provisioner) { Objects.requireNonNull(version, "version"); Objects.requireNonNull(style, "style"); Objects.requireNonNull(provisioner, "provisioner"); return FormatterStep.createLazy(NAME, - () -> new State(JarState.from(MAVEN_COORDINATE + version, provisioner), version, style), + () -> new State(JarState.from(MAVEN_COORDINATE + version, provisioner), version, style, formatJavadoc), State::createFormat); } @@ -63,6 +75,11 @@ public static String defaultStyle() { return DEFAULT_STYLE; } + /** Get default for whether Java docs should be formatted */ + public static boolean defaultFormatJavadoc() { + return DEFAULT_FORMAT_JAVADOC; + } + private static final class State implements Serializable { private static final long serialVersionUID = 1L; @@ -71,23 +88,23 @@ private static final class State implements Serializable { /** Version of the formatter jar. */ private final String formatterVersion; private final String style; + /** Whether to format Java docs. */ + private final boolean formatJavadoc; - State(JarState jarState, String formatterVersion) { - this(jarState, formatterVersion, DEFAULT_STYLE); - } - - State(JarState jarState, String formatterVersion, String style) { + State(JarState jarState, String formatterVersion, String style, boolean formatJavadoc) { ModuleHelper.doOpenInternalPackagesIfRequired(); this.jarState = jarState; this.formatterVersion = formatterVersion; this.style = style; + this.formatJavadoc = formatJavadoc; } FormatterFunc createFormat() throws Exception { final ClassLoader classLoader = jarState.getClassLoader(); final Class formatterFunc = classLoader.loadClass("com.diffplug.spotless.glue.pjf.PalantirJavaFormatFormatterFunc"); - final Constructor constructor = formatterFunc.getConstructor(String.class); // style - return JVM_SUPPORT.suggestLaterVersionOnError(formatterVersion, (FormatterFunc) constructor.newInstance(style)); + // 1st arg is "style", 2nd arg is "formatJavadoc" + final Constructor constructor = formatterFunc.getConstructor(String.class, boolean.class); + return JVM_SUPPORT.suggestLaterVersionOnError(formatterVersion, (FormatterFunc) constructor.newInstance(style, formatJavadoc)); } } } diff --git a/lib/src/palantirJavaFormat/java/com/diffplug/spotless/glue/pjf/PalantirJavaFormatFormatterFunc.java b/lib/src/palantirJavaFormat/java/com/diffplug/spotless/glue/pjf/PalantirJavaFormatFormatterFunc.java index 189bbb54be..bdec215435 100644 --- a/lib/src/palantirJavaFormat/java/com/diffplug/spotless/glue/pjf/PalantirJavaFormatFormatterFunc.java +++ b/lib/src/palantirJavaFormat/java/com/diffplug/spotless/glue/pjf/PalantirJavaFormatFormatterFunc.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 DiffPlug + * Copyright 2022-2024 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,9 @@ */ package com.diffplug.spotless.glue.pjf; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import com.palantir.javaformat.java.Formatter; import com.palantir.javaformat.java.ImportOrderer; import com.palantir.javaformat.java.JavaFormatterOptions; @@ -28,11 +31,20 @@ public class PalantirJavaFormatFormatterFunc implements FormatterFunc { private final JavaFormatterOptions.Style formatterStyle; - public PalantirJavaFormatFormatterFunc(String style) { + /** + * Creates a new formatter func that formats code via Palantir. + * @param style The style to use for formatting. + * @param formatJavadoc Whether to format Java docs. Requires at least Palantir 2.36.0 or later, otherwise the + * constructor will throw. + */ + public PalantirJavaFormatFormatterFunc(String style, boolean formatJavadoc) { this.formatterStyle = JavaFormatterOptions.Style.valueOf(style); - formatter = Formatter.createFormatter(JavaFormatterOptions.builder() - .style(formatterStyle) - .build()); + JavaFormatterOptions.Builder builder = JavaFormatterOptions.builder(); + builder.style(formatterStyle); + if (formatJavadoc) { + applyFormatJavadoc(builder); + } + formatter = Formatter.createFormatter(builder.build()); } @Override @@ -47,4 +59,15 @@ public String apply(String input) throws Exception { public String toString() { return "PalantirJavaFormatFormatterFunc{formatter=" + formatter + '}'; } + + private static void applyFormatJavadoc(JavaFormatterOptions.Builder builder) { + // The formatJavadoc option is available since Palantir 2.36.0 + // To support older versions for now, attempt to invoke the builder method via reflection. + try { + Method formatJavadoc = JavaFormatterOptions.Builder.class.getMethod("formatJavadoc", boolean.class); + formatJavadoc.invoke(builder, true); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new IllegalStateException("Cannot enable formatJavadoc option, make sure you are using Palantir with version 2.36.0 or later", e); + } + } } diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 593d4a2af8..132ad16ebc 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] +### Added +* Maven / Gradle - Support for formatting Java Docs for the Palantir formatter ([#2009](https://github.com/diffplug/spotless/pull/2009)) + ## [6.24.0] - 2024-01-15 ### Added * Support for shell formatting via [shfmt](https://github.com/mvdan/sh). ([#1994](https://github.com/diffplug/spotless/pull/1994)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 4b57a07f02..e80d143653 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -220,6 +220,8 @@ spotless { palantirJavaFormat() // optional: you can specify a specific version and/or switch to AOSP/GOOGLE style palantirJavaFormat('2.9.0').style("GOOGLE") + // optional: you can also format Javadocs, requires at least Palantir 2.39.0 + palantirJavaFormat('2.39.0').formatJavadoc(true) ``` ### eclipse jdt 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 bb24a716cd..db869dc4e6 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-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. @@ -256,6 +256,7 @@ public PalantirJavaFormatConfig palantirJavaFormat(String version) { public class PalantirJavaFormatConfig { final String version; String style; + boolean formatJavadoc; PalantirJavaFormatConfig(String version) { this.version = Objects.requireNonNull(version); @@ -269,8 +270,14 @@ public PalantirJavaFormatConfig style(String style) { return this; } + public PalantirJavaFormatConfig formatJavadoc(boolean formatJavadoc) { + this.formatJavadoc = formatJavadoc; + replaceStep(createStep()); + return this; + } + private FormatterStep createStep() { - return PalantirJavaFormatStep.create(version, style, provisioner()); + return PalantirJavaFormatStep.create(version, style, formatJavadoc, provisioner()); } } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PalantirJavaFormatIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PalantirJavaFormatIntegrationTest.java index 2283ce34bf..9990039cd3 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PalantirJavaFormatIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PalantirJavaFormatIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 DiffPlug + * Copyright 2022-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,4 +45,26 @@ void integration() throws IOException { "palantirJavaFormat('1.0.1')"); checkRunsThenUpToDate(); } + + @Test + void formatJavaDoc() throws IOException { + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "", + "spotless {", + " java {", + " target file('test.java')", + " palantirJavaFormat('2.39.0').formatJavadoc(true)", + " }", + "}"); + + setFile("test.java").toResource("java/palantirjavaformat/JavaCodeWithJavaDocUnformatted.test"); + gradleRunner().withArguments("spotlessApply").build(); + assertFile("test.java").sameAsResource("java/palantirjavaformat/JavaCodeWithJavaDocFormatted.test"); + + checkRunsThenUpToDate(); + } } diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index f056aadf6e..b95f2e998e 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] ### Added * Support for formatting shell scripts via [shfmt](https://github.com/mvdan/sh). ([#1998](https://github.com/diffplug/spotless/issues/1998)) +* Maven / Gradle - Support for formatting Java Docs for the Palantir formatter ([#2009](https://github.com/diffplug/spotless/pull/2009)) ## [2.42.0] - 2024-01-15 ### Added diff --git a/plugin-maven/README.md b/plugin-maven/README.md index efc15b515f..7785412a32 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -246,8 +246,9 @@ any other maven phase (i.e. compile) then it can be configured as below; ```xml - 2.10.0 + 2.39.0 + false ``` diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PalantirJavaFormat.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PalantirJavaFormat.java index 192588d85d..674238d2e8 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PalantirJavaFormat.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PalantirJavaFormat.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. @@ -30,10 +30,14 @@ public class PalantirJavaFormat implements FormatterStepFactory { @Parameter private String style; + @Parameter + private Boolean formatJavadoc; + @Override public FormatterStep newFormatterStep(FormatterStepConfig config) { String version = this.version != null ? this.version : PalantirJavaFormatStep.defaultVersion(); String style = this.style != null ? this.style : PalantirJavaFormatStep.defaultStyle(); - return PalantirJavaFormatStep.create(version, style, config.getProvisioner()); + boolean formatJavadoc = this.formatJavadoc != null ? this.formatJavadoc : PalantirJavaFormatStep.defaultFormatJavadoc(); + return PalantirJavaFormatStep.create(version, style, formatJavadoc, config.getProvisioner()); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/PalantirJavaFormatTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/PalantirJavaFormatTest.java index 685f00595c..eee4fab8c5 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/PalantirJavaFormatTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/PalantirJavaFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 DiffPlug + * Copyright 2022-2024 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 @@ void specificVersionDefaultStyle() throws Exception { " 1.1.0", ""); - runTest("java/palantirjavaformat/JavaCodeFormatted.test"); + runTest("java/palantirjavaformat/JavaCodeFormatted.test", "java/palantirjavaformat/JavaCodeUnformatted.test"); } @Test @@ -37,12 +37,23 @@ void specificJava11Version2() throws Exception { " 2.39.0", ""); - runTest("java/palantirjavaformat/JavaCodeFormatted.test"); + runTest("java/palantirjavaformat/JavaCodeFormatted.test", "java/palantirjavaformat/JavaCodeUnformatted.test"); } - private void runTest(String targetResource) throws Exception { + @Test + void formatJavaDoc() throws Exception { + writePomWithJavaSteps( + "", + " 2.39.0", + " true", + ""); + + runTest("java/palantirjavaformat/JavaCodeWithJavaDocFormatted.test", "java/palantirjavaformat/JavaCodeWithJavaDocUnformatted.test"); + } + + private void runTest(String targetResource, String sourceResource) throws Exception { String path = "src/main/java/test.java"; - setFile(path).toResource("java/palantirjavaformat/JavaCodeUnformatted.test"); + setFile(path).toResource(sourceResource); mavenRunner().withArguments("spotless:apply").runNoError(); assertFile(path).sameAsResource(targetResource); } diff --git a/testlib/src/main/resources/java/palantirjavaformat/JavaCodeWithJavaDocFormatted.test b/testlib/src/main/resources/java/palantirjavaformat/JavaCodeWithJavaDocFormatted.test new file mode 100644 index 0000000000..9cff5e17a1 --- /dev/null +++ b/testlib/src/main/resources/java/palantirjavaformat/JavaCodeWithJavaDocFormatted.test @@ -0,0 +1,39 @@ +import mylib.Unused; +import mylib.UsedA; +import mylib.UsedB; + +/** + * This is a test class with a long unformatted JavaDoc description. Lorem ipsum dolor sit amet, consectetur adipiscing + * elit. Vestibulum pulvinar condimentum elit, eget mollis magna sollicitudin in. Aenean pharetra nunc nec luctus + * consequat. Donec nec tincidunt quam, in auctor ipsum. Nam in sem orci. Maecenas interdum posuere orci a semper. Cras + * vulputate blandit metus, nec semper urna porttitor at. Praesent velit turpis, consequat in cursus eget, posuere eget + * magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque ante eros, sagittis sed tempus nec, + * rutrum ac arcu. Sed porttitor quam at enim commodo dictum. Sed fringilla tincidunt ex in aliquet. + * + * @author https://www.lipsum.com/ + * @since 0.0.2 + */ +public class Java { + /** + * A very simple method that I really like a lot? + * + *

Care for more details? + * + *

+ * + * @param args Useless args, but see {@link Unused}, perhaps even {@link UsedA} or even {@link UsedB b }? + */ + public static void main(String[] args) { + System.out.println( + "A very very very very very very very very very very very very very very very very very very very very very long string that goes beyond the 100-character line length."); + UsedB.someMethod(); + UsedA.someMethod(); + } +} diff --git a/testlib/src/main/resources/java/palantirjavaformat/JavaCodeWithJavaDocUnformatted.test b/testlib/src/main/resources/java/palantirjavaformat/JavaCodeWithJavaDocUnformatted.test new file mode 100644 index 0000000000..fcb3ad660c --- /dev/null +++ b/testlib/src/main/resources/java/palantirjavaformat/JavaCodeWithJavaDocUnformatted.test @@ -0,0 +1,30 @@ + +import mylib.Unused; +import mylib.UsedB; +import mylib.UsedA; + +/** This is a test class with a long unformatted JavaDoc description. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pulvinar condimentum elit, eget mollis magna sollicitudin in. Aenean pharetra nunc nec luctus consequat. Donec nec tincidunt quam, in auctor ipsum. Nam in sem orci. Maecenas interdum posuere orci a semper. Cras vulputate blandit metus, nec semper urna porttitor at. Praesent velit turpis, consequat in cursus eget, posuere eget magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque ante eros, sagittis sed tempus nec, rutrum ac arcu. Sed porttitor quam at enim commodo dictum. Sed fringilla tincidunt ex in aliquet. + * @author https://www.lipsum.com/ + * @since 0.0.2 + */ +public class Java { + /** + * A very simple method that I + * really + * like + * a lot? + * + * Care for more details? + * + * @param args Useless args, but + * see {@link Unused}, perhaps even {@link UsedA} or even {@link UsedB b }? + */ +public static void main(String[] args) { +System.out.println("A very very very very very very very very very very very very very very very very very very very very very long string that goes beyond the 100-character line length."); +UsedB.someMethod(); +UsedA.someMethod(); +} +} \ No newline at end of file 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 7cd1aad438..cb8777728b 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-2023 DiffPlug + * Copyright 2022-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,14 @@ void behavior() throws Exception { .testResource("java/palantirjavaformat/JavaCodeWithPackageUnformatted.test", "java/palantirjavaformat/JavaCodeWithPackageFormatted.test"); } + @Test + void formatJavadoc() throws Exception { + FormatterStep step = PalantirJavaFormatStep.create("2.39.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"); + } + @Test void behaviorWithGoogleStyle() throws Exception { FormatterStep step = PalantirJavaFormatStep.create("1.1.0", "GOOGLE", TestProvisioner.mavenCentral()); @@ -68,23 +76,33 @@ void equality() { new SerializableEqualityTester() { String version = "1.1.0"; String style = ""; + boolean formatJavadoc = false; @Override protected void setupTest(API api) { // same version == same api.areDifferentThan(); + // change the version, and it's different version = "1.0.0"; api.areDifferentThan(); + version = "1.1.0"; + // change the style, and it's different style = "AOSP"; api.areDifferentThan(); + style = ""; + + // change the format Java doc flag, and it's different + formatJavadoc = true; + api.areDifferentThan(); + formatJavadoc = false; } @Override protected FormatterStep create() { String finalVersion = this.version; - return PalantirJavaFormatStep.create(finalVersion, style, TestProvisioner.mavenCentral()); + return PalantirJavaFormatStep.create(finalVersion, style, formatJavadoc, TestProvisioner.mavenCentral()); } }.testEquals(); }