diff --git a/CHANGES.md b/CHANGES.md index 8a255c5827..9f2c667869 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,11 @@ -# Spotless releases +# spotless-plugin-gradle releases ### Version 3.0.0-SNAPSHOT - TBD ([javadoc](https://diffplug.github.io/spotless/javadoc/snapshot/), [snapshot](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/gradle/spotless/spotless/)) -* Big push towards supporting incremental build. Requires a lot of work for every FormatterStep to properly serialize its state, so this might take a little while. -* Moved eclipse jars out of spotless' core and into spotless-eclipse. Reduces download size significantly for folks that don't need or want the eclipse formatter, and improves repeatability for those that do. +* BREAKING CHANGE: `customReplace` and `customReplaceRegex` renamed to just `replace` and `replaceRegex`. +* BREAKING CHANGE: Plugin portal ID is still `com.diffplug.gradle.spotless`, but maven coordinate has changed to `com.diffplug.spotless:spotless-plugin-gradle`. +* HUGE SPEEDUP: Now supports incremental build / up-to-date-checking. + + If you are using `custom` or `customLazy`, you might want to take a look at [this javadoc](https://diffplug.github.io/spotless/javadoc/snapshot/spotless-gradle-plugin/snapshot/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-). ### Version 2.4.1 - January 2nd 2017 ([javadoc](https://diffplug.github.io/spotless/javadoc/2.4.1/), [jcenter](https://bintray.com/diffplug/opensource/spotless/2.4.1/view)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3de6553483..98c301eceb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,19 +4,26 @@ Pull requests are welcome, preferably against `master`. Feel free to develop sp ## How Spotless works -Spotless' most basic element is the `FormatterStep`, which has one method that really matters: `String format(String rawUnix, File file)`. Each step is guaranteed that its input string will contain only unix newlines, and the step's output should also contain only unix newlines. The file argument is provided only to allow path-dependent formatting (e.g. special formatting for `package-info.java`), but most formatters are path-independent and won't use that input. +Spotless' most basic element is the `FormatterStep`, which has one method that really matters: `String format(String rawUnix, File file)`. Each step is guaranteed that its input string will contain only unix newlines, and the step's output should also contain only unix newlines. The file argument is provided only to allow path-dependent formatting (e.g. special formatting for `package-info.java`), but most formatters are path-independent and won't use that argument. In order to use and combine `FormatterStep`, you first create a `Formatter`, which has the following parameters: - an encoding - a list of `FormatterStep` -- a line endings policy (`LineEnding.GIT_ATTRIBUTES` is usually the best choice) +- a line endings policy (`LineEnding.GIT_ATTRIBUTES` is almost always the best choice) -Once you have an instance of `Formatter`, you can call `boolean isClean(File)`, or `void applyTo(File)` to either check or apply formatting to a file. Spotless will use the encoding to turn the raw bytes into a String, normalize its line endings to `\n`, pass it to each `FormatterStep` one after the other, and then apply line endings according to the policy. You can also use lower-level methods like `String compute(String unix, File file)` if you'd like to do lower-level processing. +Once you have an instance of `Formatter`, you can call `boolean isClean(File)`, or `void applyTo(File)` to either check or apply formatting to a file. Spotless will then: -`Formatter` and all `FormatterStep` implement `equals` and `hashCode` correctly, which means that build systems that support up-to-date checks can easily and correctly determine if any actions need to be taken. +- parse the raw bytes into a String according to the encoding +- normalize its line endings to `\n` +- pass the unix string to each `FormatterStep` one after the other +- apply line endings according to the policy -In addition to the standard usage above, Spotless also provides `PaddedCell`, which makes it easy to diagnose and correct idempotence problems. +You can also use lower-level methods like `String compute(String unix, File file)` if you'd like to do lower-level processing. + +All `FormatterStep` implement `Serializable`, `equals`, and `hashCode`, so build systems that support up-to-date checks can easily and correctly determine if any actions need to be taken. + +Spotless also provides `PaddedCell`, which makes it easy to diagnose and correct idempotence problems. ## Project layout @@ -31,7 +38,7 @@ For the folders below in monospace text, they are published on maven central at | `plugin-maven` | Integrates spotless and all of its formatters into Maven. | | javadoc-publish | Logic for publishing javadoc to github-pages. | | ide | Generates and launches an IDE for developing spotless. | -| _ext | Folder for generating glue jars (specifically packaging Eclipse jars from p2 for consumption using maven). +| _ext | Folder for generating glue jars (specifically packaging Eclipse jars from p2 for consumption using maven). ## How to add a new FormatterStep @@ -43,27 +50,47 @@ FormatterStep identityStep = FormatterStep.createNeverUpToDate("identity", unix This creates a step which will fail up-to-date checks (it is equal only to itself), and will use the function you passed in to do the formatting pass. -To create a step which can handle up-to-date checks properly, use the method ` FormatterStep create(String name, Key key, Function keyToFormatter)`. Here's an example: +To create a step which can handle up-to-date checks properly, use the method ` FormatterStep create(String name, State state, Function stateToFormatter)`. Here's an example: ```java -public final class NeverImport implements Serializable { - Set neverImport; +public final class ReplaceStep { + private ReplaceStep() {} + + public static FormatterStep create(String name, CharSequence target, CharSequence replacement) { + return FormatterStep.create(name, + new State(target, replacement), + State::toFormatter); + } + + private static final class State implements Serializable { + private static final long serialVersionUID = 1L; + + private final CharSequence target; + private final CharSequence replacement; + + State(CharSequence target, CharSequence replacement) { + this.target = target; + this.replacement = replacement; + } + + FormatterFunc toFormatter() { + return raw -> raw.replace(target, replacement); + } + } +} +``` - private NeverImport(Set neverImport) { - this.neverImport = neverImport; - } +The `FormatterStep` created above implements `equals` and `hashCode` based on the serialized representation of its `State`. This trick makes it quick and easy to write steps which properly support up-to-date checks. - private String format(String input) { - - } +Oftentimes, a rule's state will be expensive to compute. `EclipseFormatterStep`, for example, depends on a formatting file. Ideally, we would like to only pay the cost of the I/O needed to load that file if we have to - we'd like to create the FormatterStep now but load its state lazily at the last possible moment. For this purpose, each of the `FormatterStep.create` methods has a lazy counterpart. Here are their signatures: - public static FormatterStep create(String... neverImport) { - - } -} +```java +FormatterStep createNeverUpToDate (String name, FormatterFunc function ) +FormatterStep createNeverUpToDateLazy(String name, Supplier functionSupplier) +FormatterStep create (String name, State state , Function stateToFormatter) +FormatterStep createLazy(String name, Supplier stateSupplier, Function stateToFormatter) ``` - If your formatting step only needs to call one or two methods of the external dependency, you can pull it in at runtime and call it via reflection. See the logic for [`EclipseFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseFormatterStep.java) or [`GoogleJavaFormatStep`](lib/src/main/java/com/diffplug/spotless/extra/java/GoogleJavaFormatStep.java). ## How to add a new plugin for a build system @@ -76,7 +103,7 @@ The gist of it is that you will have to: - (Optional) Tie into the build system's native up-to-date mechanism. - (Optional) Use `PaddedCell` to proactively catch and resolve idempotence issues. -`plugin-gradle` is the canonical example which uses everything that Spotless has to offer. +`plugin-gradle` is the canonical example which uses everything that Spotless has to offer. It's only ~700 lines. If you get something running, we'd love to host your plugin within this repo as a peer to `plugin-gradle` and `plugin-maven`. diff --git a/ECLIPSE_SCREENSHOTS.md b/ECLIPSE_SCREENSHOTS.md new file mode 100644 index 0000000000..345ae44494 --- /dev/null +++ b/ECLIPSE_SCREENSHOTS.md @@ -0,0 +1,16 @@ +## Exporting from & importing into Eclipse + +There are two files to import/export with Eclipse - one for code formatting and one for import ordering. + +### Opening the preferences +![Eclipse preferences](_images/EclipsePreferences.png) + +### Creating `spotless.eclipseformat.xml` +![Eclipse formatter](_images/EclipseFormatter.png) +![Eclipse formatter edit](_images/EclipseFormatterEdit.png) + +The Eclipse formatter's off/on tags are a great feature which is often overlooked. +![Eclipse formatter off/on tags](_images/EclipseFormatterEditOffOnTags.png) + +### Creating `spotless.importorder` +![Eclipse imports](_images/EclipseImports.png) diff --git a/README.md b/README.md index b747437152..ae98c349e3 100644 --- a/README.md +++ b/README.md @@ -1,271 +1,81 @@ -# Spotless: Keep your code spotless with Gradle +# Spotless: Keep your code spotless -[![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.gradle.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.gradle.spotless) -[![Maven central](https://img.shields.io/badge/mavencentral-com.diffplug.gradle.spotless%3Aspotless-blue.svg)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.gradle.spotless%22%20AND%20a%3A%22spotless%22) -[![Javadoc](https://img.shields.io/badge/javadoc-2.4.1-blue.svg)](https://diffplug.github.io/spotless/javadoc/2.4.1/) - -[![Changelog](https://img.shields.io/badge/changelog-3.0.0--SNAPSHOT-brightgreen.svg)](CHANGES.md) [![Travis CI](https://travis-ci.org/diffplug/spotless.svg?branch=master)](https://travis-ci.org/diffplug/spotless) [![Live chat](https://img.shields.io/badge/gitter-chat-brightgreen.svg)](https://gitter.im/diffplug/spotless) [![License Apache](https://img.shields.io/badge/license-apache-brightgreen.svg)](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)) - - -Spotless is a general-purpose formatting plugin. It is completely à la carte, but also includes powerful "batteries-included" if you opt-in. - -To people who use your build, it looks like this: - -``` -cmd> gradlew build -... -:spotlessJavaCheck FAILED -> The following files had format violations: - src\main\java\com\diffplug\gradle\spotless\FormatExtension.java - @@ -109,7 +109,7 @@ - ... - -\t\t····if·(targets.length·==·0)·{ - +\t\tif·(targets.length·==·0)·{ - ... - Run 'gradlew spotlessApply' to fix these violations. - -cmd> gradlew spotlessApply -:spotlessApply -BUILD SUCCESSFUL - -cmd> gradlew build -BUILD SUCCESSFUL -``` - -Inside your buildscript, it looks like this: - -```groovy -spotless { - format 'misc', { - target '**/*.gradle', '**/*.md', '**/.gitignore' - - trimTrailingWhitespace() - indentWithTabs() // or spaces. Takes an integer argument if you don't like 4 - endWithNewline() - } - format 'cpp', { - target '**/*.hpp', '**/*.cpp' - - customReplace 'Not enough space after if', 'if(', 'if (' - customReplaceRegex 'Too much space after if', 'if +\\(', 'if (' - - // Everything before the first #include or #pragma will - // be replaced with whatever is in `spotless.license.cpp` - licenseHeaderFile 'spotless.license.cpp', '#' - } -} -``` - -Spotless can check and apply formatting to any plain-text file, using simple rules ([javadoc](https://diffplug.github.io/spotless/javadoc/2.4.1/com/diffplug/gradle/spotless/FormatExtension.html)) like those above. It also supports more powerful formatters: - -* Eclipse's java code formatter (including style and import ordering) -* Google's [google-java-format](https://github.com/google/google-java-format) -* [FreshMark](https://github.com/diffplug/freshmark) (markdown with variables) -* Any user-defined function which takes an unformatted string and outputs a formatted version. - -Contributions are welcome, see [the contributing guide](CONTRIBUTING.md) for development info. - -Spotless requires Gradle to be running on JRE 8+.See [issue #7](https://github.com/diffplug/spotless/issues/7) for details. - -## Applying to Java source - -```groovy -apply plugin: 'java' -... - -spotless { - java { - // By default, all Java source sets will be formatted. To change - // this, set the 'target' parameter as described in the next section. - - licenseHeader '/* Licensed under Apache-2.0 */' // License header - licenseHeaderFile 'spotless.license.java' // License header file - // Obviously, you can't specify both licenseHeader and licenseHeaderFile at the same time - - importOrder ['java', 'javax', 'org', 'com', 'com.diffplug', ''] // An array of package names - importOrderFile 'spotless.importorder' // An import ordering file, exported from Eclipse - // As before, you can't specify both importOrder and importOrderFile at the same time - // You probably want an empty string at the end - all of the imports you didn't specify - // explicitly will go there. - - eclipseFormatFile 'spotless.eclipseformat.xml' // XML file dumped out by the Eclipse formatter - // If you have an older Eclipse properties file, you can use that too. - - // You can also tweak the formatting with custom regexes or functions, such as: - // Eclipse formatter screws up long literals with underscores inside of annotations (see issue #14) - // @Max(value = 9_999_999 L) // what Eclipse does - // @Max(value = 9_999_999L) // what I wish Eclipse did - custom 'Long literal fix', { it.replaceAll('([0-9_]+) [Ll]', '$1L') } - } -} -``` - -## Applying to Java source ([google-java-format](https://github.com/google/google-java-format)) - -```groovy -spotless { - java { - googleJavaFormat() // googleJavaFormat('1.1') to specify a specific version - // you can then layer other format steps, such as - licenseHeaderFile 'spotless.license.java' - } -} -``` - -## Applying [FreshMark](https://github.com/diffplug/freshmark) to markdown files +Spotless can format <java | markdown | license headers | anything> using <gradle | maven | anything>. -To apply freshmark to all of the `.md` files in your project, with all of your project's properties available for templating, just use this snippet: +- [Spotless for Gradle](plugin-gradle) +- [Spotless for Maven](plugin-maven) +- [Other build systems](CONTRIBUTING.md#how-to-add-a-new-plugin-for-a-build-system) -```groovy -spotless { - freshmark {} -} -``` +Ideally, a code formatter can do more than just find formatting errors - it should fix them as well. Such a formatter is really just a `Function`, which returns a formatted version of its potentially unformatted input. -You can also specify properties manually. +It's easy to build such a function, but there are some gotchas and lots of integration work (newlines, character encodings, idempotency, and build-system integration). Spotless tackles those for you so you can focus on just a simple `Function` which can compose with any of the other formatters and build tools in Spotless' arsenal. -```groovy -spotless { - freshmark { - target 'README.md', 'CONTRIBUTING.md' - properties([lib: 'MyLib', author: 'Me']) - trimTrailingWhitespace() - indentWithTabs() - endWithNewline() - } -} -``` +## Current feature matrix -## Custom rules + +output = [ +'| Feature / FormatterStep | plugin-gradle | plugin-maven | [(Your build tool here)](CONTRIBUTING.md#how-to-add-a-new-plugin-for-a-build-system) |', +'| --------------------------------------------- | ------------- | ------------ | --------|', +lib('generic.EndWithNewlineStep') +'{{yes}} | {{no}} | {{no}} |', +lib('generic.IndentStep') +'{{yes}} | {{no}} | {{no}} |', +lib('generic.LicenseHeaderStep') +'{{yes}} | {{no}} | {{no}} |', +lib('generic.ReplaceRegexStep') +'{{yes}} | {{no}} | {{no}} |', +lib('generic.ReplaceStep') +'{{yes}} | {{no}} | {{no}} |', +lib('generic.TrimTrailingWhitespaceStep') +'{{yes}} | {{no}} | {{no}} |', +lib('java.GoogleJavaFormatStep') +'{{yes}} | {{no}} | {{no}} |', +lib('java.ImportOrderStep') +'{{yes}} | {{no}} | {{no}} |', +extra('java.EclipseFormatterStep') +'{{yes}} | {{no}} | {{no}} |', +lib('markdown.FreshMarkStep') +'{{yes}} | {{no}} | {{no}} |', +'| [(Your FormatterStep here)](https://github.com/nedtwigg/spotless/blob/markdown-preview-temp/CONTRIBUTING.md#how-to-add-a-new-formatterstep) | {{no}} | {{no}} | {{no}} |', +'| Fast up-to-date checking | {{yes}} | {{no}} | {{no}} |', +'| Automatic idempotency safeguard | {{yes}} | {{no}} | {{no}} |', +'' +].join('\n'); +--> +| Feature / FormatterStep | plugin-gradle | plugin-maven | [(Your build tool here)](CONTRIBUTING.md#how-to-add-a-new-plugin-for-a-build-system) | +| --------------------------------------------- | ------------- | ------------ | --------| +| [`generic.EndWithNewlineStep`](lib/src/main/java/com/diffplug/spotless/generic/EndWithNewlineStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`generic.IndentStep`](lib/src/main/java/com/diffplug/spotless/generic/IndentStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`generic.LicenseHeaderStep`](lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`generic.ReplaceRegexStep`](lib/src/main/java/com/diffplug/spotless/generic/ReplaceRegexStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`generic.ReplaceStep`](lib/src/main/java/com/diffplug/spotless/generic/ReplaceStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`generic.TrimTrailingWhitespaceStep`](lib/src/main/java/com/diffplug/spotless/generic/TrimTrailingWhitespaceStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`java.GoogleJavaFormatStep`](lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`java.ImportOrderStep`](lib/src/main/java/com/diffplug/spotless/java/ImportOrderStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`java.EclipseFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseFormatterStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [`markdown.FreshMarkStep`](lib/src/main/java/com/diffplug/spotless/markdown/FreshMarkStep.java) | :+1: | :white_large_square: | :white_large_square: | +| [(Your FormatterStep here)](https://github.com/nedtwigg/spotless/blob/markdown-preview-temp/CONTRIBUTING.md#how-to-add-a-new-formatterstep) | :white_large_square: | :white_large_square: | :white_large_square: | +| Fast up-to-date checking | :+1: | :white_large_square: | :white_large_square: | +| Automatic idempotency safeguard | :+1: | :white_large_square: | :white_large_square: | + ## Acknowledgements -* Formatting by Eclipse 4.6 +* Huge thanks to [Jonathan Bluett-Duncan](https://github.com/jbduncan) for + + implementing up-to-date checking [#31](https://github.com/diffplug/spotless/issues/31) + + breaking spotless into libraries [#56](https://github.com/diffplug/spotless/issues/56) + + lots of other things, but especially the diff support in `spotlessCheck` +* Formatting by Eclipse + Special thanks to [Mateusz Matela](https://waynebeaton.wordpress.com/2015/03/15/great-fixes-for-mars-winners-part-i/) for huge improvements to the eclipse code formatter! -* Forked from [gradle-format-plugin](https://github.com/youribonnaffe/gradle-format-plugin) by Youri Bonnaffé. +* Originally forked from [gradle-format-plugin](https://github.com/youribonnaffe/gradle-format-plugin) by Youri Bonnaffé. * Thanks to Gábor Bernát for improvements to logging and multi-project support. -* Thanks to Jonathan Bluett-Duncan (https://github.com/jbduncan) for providing the diff support in `spotlessCheck`. * Thanks to Andrew Oberstar for improvements to formatting java source in non-java source sets. [PR #60](https://github.com/diffplug/spotless/pull/60). * Import ordering from [EclipseCodeFormatter](https://github.com/krasa/EclipseCodeFormatter). * Built by [gradle](http://gradle.org/). * Tested by [junit](http://junit.org/). * Maintained by [DiffPlug](http://www.diffplug.com/). - -## Exporting from & importing into Eclipse - -There are two files to import/export with Eclipse - one for code formatting and one for import ordering. - -### Opening the preferences -![Eclipse preferences](_images/EclipsePreferences.png) - -### Creating `spotless.eclipseformat.xml` -![Eclipse formatter](_images/EclipseFormatter.png) -![Eclipse formatter edit](_images/EclipseFormatterEdit.png) - -The Eclipse formatter's off/on tags are a great feature which is often overlooked. -![Eclipse formatter off/on tags](_images/EclipseFormatterEditOffOnTags.png) - -### Creating `spotless.importorder` -![Eclipse imports](_images/EclipseImports.png) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md new file mode 100644 index 0000000000..4c4a3b4e3f --- /dev/null +++ b/plugin-gradle/README.md @@ -0,0 +1,239 @@ +# Spotless: Keep your code spotless with Gradle + + +[![Gradle plugin](https://img.shields.io/badge/plugins.gradle.org-com.diffplug.gradle.spotless-blue.svg)](https://plugins.gradle.org/plugin/com.diffplug.gradle.spotless) +[![Maven central](https://img.shields.io/badge/mavencentral-com.diffplug.gradle.spotless%3Aspotless-blue.svg)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.diffplug.gradle.spotless%22%20AND%20a%3A%22spotless%22) +[![Javadoc](https://img.shields.io/badge/javadoc-2.4.1-blue.svg)](https://diffplug.github.io/spotless/javadoc/2.4.1/) + +[![Changelog](https://img.shields.io/badge/changelog-3.0.0--SNAPSHOT-brightgreen.svg)](CHANGES.md) +[![Travis CI](https://travis-ci.org/diffplug/spotless.svg?branch=master)](https://travis-ci.org/diffplug/spotless) +[![Live chat](https://img.shields.io/badge/gitter-chat-brightgreen.svg)](https://gitter.im/diffplug/spotless) +[![License Apache](https://img.shields.io/badge/license-apache-brightgreen.svg)](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)) + + + + +Spotless is a general-purpose formatting plugin. It is completely à la carte, but also includes powerful "batteries-included" if you opt-in. + +To people who use your build, it looks like this: + +``` +cmd> gradlew build +... +:spotlessJavaCheck FAILED +> The following files had format violations: + src\main\java\com\diffplug\gradle\spotless\FormatExtension.java + @@ -109,7 +109,7 @@ + ... + -\t\t····if·(targets.length·==·0)·{ + +\t\tif·(targets.length·==·0)·{ + ... + Run 'gradlew spotlessApply' to fix these violations. + +cmd> gradlew spotlessApply +:spotlessApply +BUILD SUCCESSFUL + +cmd> gradlew build +BUILD SUCCESSFUL +``` + +Inside your buildscript, it looks like this: + +```groovy +spotless { + format 'misc', { + target '**/*.gradle', '**/*.md', '**/.gitignore' + + trimTrailingWhitespace() + indentWithTabs() // or spaces. Takes an integer argument if you don't like 4 + endWithNewline() + } + format 'cpp', { + target '**/*.hpp', '**/*.cpp' + + replace 'Not enough space after if', 'if(', 'if (' + replaceRegex 'Too much space after if', 'if +\\(', 'if (' + + // Everything before the first #include or #pragma will + // be replaced with whatever is in `spotless.license.cpp` + licenseHeaderFile 'spotless.license.cpp', '#' + } +} +``` + +Spotless can check and apply formatting to any plain-text file, using simple rules ([javadoc](https://diffplug.github.io/spotless/javadoc/2.4.1/com/diffplug/gradle/spotless/FormatExtension.html)) like those above. It also supports more powerful formatters: + +* Eclipse's java code formatter (including style and import ordering) +* Google's [google-java-format](https://github.com/google/google-java-format) +* [FreshMark](https://github.com/diffplug/freshmark) (markdown with variables) +* Any user-defined function which takes an unformatted string and outputs a formatted version. + +Contributions are welcome, see [the contributing guide](../CONTRIBUTING.md) for development info. + +Spotless requires Gradle to be running on JRE 8+.See [issue #7](https://github.com/diffplug/spotless/issues/7) for details. + +## Applying to Java source + +```groovy +apply plugin: 'java' +... + +spotless { + java { + // By default, all Java source sets will be formatted. To change + // this, set the 'target' parameter as described in the next section. + + licenseHeader '/* Licensed under Apache-2.0 */' // License header + licenseHeaderFile 'spotless.license.java' // License header file + // Obviously, you can't specify both licenseHeader and licenseHeaderFile at the same time + + importOrder ['java', 'javax', 'org', 'com', 'com.diffplug', ''] // An array of package names + importOrderFile 'spotless.importorder' // An import ordering file, exported from Eclipse + // As before, you can't specify both importOrder and importOrderFile at the same time + // You probably want an empty string at the end - all of the imports you didn't specify + // explicitly will go there. + + eclipseFormatFile 'spotless.eclipseformat.xml' // XML file dumped out by the Eclipse formatter + // If you have an older Eclipse properties file, you can use that too. + } +} +``` + +See [ECLIPSE_SCREENSHOTS](../ECLIPSE_SCREENSHOTS.md) for screenshots that demonstrate how to get and install the eclipseFormatFile and importOrderFile mentioned above. + +## Applying to Java source ([google-java-format](https://github.com/google/google-java-format)) + +```groovy +spotless { + java { + googleJavaFormat() // googleJavaFormat('1.1') to specify a specific version + // you can then layer other format steps, such as + licenseHeaderFile 'spotless.license.java' + } +} +``` + +## Applying [FreshMark](https://github.com/diffplug/freshmark) to markdown files + +To apply freshmark to all of the `.md` files in your project, with all of your project's properties available for templating, just use this snippet: + +```groovy +spotless { + freshmark {} +} +``` + +You can also specify properties manually. + +```groovy +spotless { + freshmark { + target 'README.md', 'CONTRIBUTING.md' + properties([lib: 'MyLib', author: 'Me']) + trimTrailingWhitespace() + indentWithTabs() + endWithNewline() + } +} +``` + +## Custom rules + +Spotless is a generic system for specifying a sequence of steps which are applied to a set of files. + +```groovy +spotless { + // this will create two tasks: spotlessMiscCheck and spotlessMiscApply + format 'misc', { + // target determines which files this format will apply to + // - if you pass a string or a list of strings, they will be treated + // as 'include' parameters to a fileTree in the root directory + // - if you pass a FileCollection, it will pass through untouched + // e.g. project.files('build.gradle', 'settings.gradle') + // - if you pass anything else, it will be sent to project.files(yourArg) + target '**/*.gradle', '**/*.md', '**/.gitignore' + + // spotless has built-in rules for the most basic formatting tasks + trimTrailingWhitespace() + indentWithTabs() // or spaces. Takes an integer argument if you don't like 4 + endWithNewline() + + // you can also call out to your own function + custom 'superFormatter', { + // when writing a custom step, it will be helpful to know + // how the formatting process works, which is as follows: + + // 1) Load each target file, and convert it to unix-style line endings ('\n') + // 2) Pass its content through a series of steps, feeding the output of each step to the next + // 3) Put the correct line endings back on, then either check or apply + + // each step receives a string as input, and should output + // a formatted string as output. Each step can trust that its + // input will have unix newlines, and it must promise to output + // only unix newlines. Other than that, anything is fair game! + } + } +} +``` + +If you use `custom` or `customLazy`, you might want to take a look at [this javadoc](https://diffplug.github.io/spotless/javadoc/2.4.1/spotless-gradle-plugin/snapshot/com/diffplug/gradle/spotless/FormatExtension.html#bumpThisNumberIfACustomStepChanges-int-) for a big performance win. + +See [`JavaExtension.java`](src/main/java/com/diffplug/gradle/spotless/java/JavaExtension.java?ts=4) if you'd like to see how a language-specific set of custom rules is implemented. We'd love PR's which add support for other languages. + +## Line endings and encodings (invisible stuff) + +Spotless uses UTF-8 by default, but you can use [any encoding which Java supports](https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html). You can set it globally, and you can also set it per-format. + +```gradle +spotless { + java { + ... + encoding 'Cp1252' // java will have Cp1252 + } + encoding 'US-ASCII' // but all other formats will be interpreted as US-ASCII +} +``` + +Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports four line ending modes: `UNIX`, `WINDOWS`, `PLATFORM_NATIVE`, and `GIT_ATTRIBUTES`. The default value is `GIT_ATTRIBUTES`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time. + +You can easily set the line endings of different files using [a `.gitattributes` file](https://help.github.com/articles/dealing-with-line-endings/). Here's an example `.gitattributes` which sets all files to unix newlines: `* text eol=lf`. + +## How do I preview what `spotlessApply` will do? + +- Save your working tree with `git add -A`, then `git commit -m "Checkpoint before spotless."` +- Run `gradlew spotlessApply` +- View the changes with `git diff` +- If you don't like what spotless did, `git reset --hard` +- If you'd like to remove the "checkpoint" commit, `git reset --soft head~1` will make the checkpoint commit "disappear" from history, but keeps the changes in your working directory. + +## Example configurations (from real-world projects) + +Spotless is hosted on jcenter and at plugins.gradle.org. [Go here](https://plugins.gradle.org/plugin/com.diffplug.gradle.spotless) if you're not sure how to import the plugin. + +* [JUnit 5](https://github.com/junit-team/junit-lambda/blob/151d52ffab07881de71a8396a9620f18072c65ec/build.gradle#L86-L101) (aka JUnit Lambda) +* [opentest4j](https://github.com/ota4j-team/opentest4j/blob/aab8c204be05609e9f76c2c964c3d6845cd0de14/build.gradle#L63-L80) +* [Durian](https://github.com/diffplug/durian) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/durian/blob/v3.2.0/build.gradle#L65-L85)) +* [DurianRx](https://github.com/diffplug/durian-rx) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/durian-rx/blob/v1.1.0/build.gradle#L92-L113)) +* [DurianSwt](https://github.com/diffplug/durian-swt) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/durian-swt/blob/v1.3.0/build.gradle#L137-L158)) +* [MatConsoleCtl](https://github.com/diffplug/matconsolectl) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/matconsolectl/blob/v4.4.1/build.gradle#L169-L189)) +* [MatFileRW](https://github.com/diffplug/matfilerw) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/matfilerw/blob/v1.3.1/build.gradle#L129-L149)) +* [Goomph](https://github.com/diffplug/goomph) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/goomph/blob/v1.0.0/build.gradle#L78-L99)) +* [FreshMark](https://github.com/diffplug/freshmark) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/freshmark/blob/v1.3.0/build.gradle#L52-L73)) +* [JScriptBox](https://github.com/diffplug/jscriptbox) ([direct link to spotless section in its build.gradle](https://github.com/diffplug/jscriptbox/blob/v3.0.0/build.gradle#L45-L65)) +* (Your project here) + + diff --git a/plugin-maven/README.md b/plugin-maven/README.md new file mode 100644 index 0000000000..0696c782c3 --- /dev/null +++ b/plugin-maven/README.md @@ -0,0 +1,3 @@ +# Spotless: Keep your code spotless with Gradle + +We're looking for a contributor to build the maven plugin. See [CONTRIBUTING.md](../CONTRIBUTING.md) for more info - you'll have lots of help on hand! diff --git a/spotlessSelf.gradle b/spotlessSelf.gradle index b620ee0398..3d1989b5e1 100644 --- a/spotlessSelf.gradle +++ b/spotlessSelf.gradle @@ -15,6 +15,10 @@ spotless { freshmark { target '**/*.md' propertiesFile('gradle.properties') + properties { + it.put('yes', ':+1:') + it.put('no', ':white_large_square:') + } } format 'misc', { target '**/*.gradle', '**/*.md', '**/*.gitignore'