Giter VIP home page Giter VIP logo

spotless's Introduction

Spotless: Keep your code spotless

Gradle Plugin Maven Plugin SBT Plugin

Spotless can format <antlr | c | c# | c++ | css | flow | graphql | groovy | html | java | javascript | json | jsx | kotlin | less | license headers | markdown | objective-c | protobuf | python | scala | scss | shell | sql | typeScript | vue | yaml | anything> using <gradle | maven | sbt | anything>.

You probably want one of the links below:

❇️ Spotless for Gradle (with integrations for VS Code and IntelliJ)

user@machine repo % ./gradlew build
:spotlessJavaCheck FAILED
  The following files had format violations:
  src\main\java\com\diffplug\gradle\spotless\FormatExtension.java
    -\t\t····if·(targets.length·==·0)·{
    +\t\tif·(targets.length·==·0)·{
  Run './gradlew spotlessApply' to fix these violations.
user@machine repo % ./gradlew spotlessApply
:spotlessApply
BUILD SUCCESSFUL
user@machine repo % ./gradlew build
BUILD SUCCESSFUL
user@machine repo % mvn spotless:check
[ERROR]  > The following files had format violations:
[ERROR]  src\main\java\com\diffplug\gradle\spotless\FormatExtension.java
[ERROR]    -\t\t····if·(targets.length·==·0)·{
[ERROR]    +\t\tif·(targets.length·==·0)·{
[ERROR]  Run 'mvn spotless:apply' to fix these violations.
user@machine repo % mvn spotless:apply
[INFO] BUILD SUCCESS
user@machine repo % mvn spotless:check
[INFO] BUILD SUCCESS

How it works (for potential contributors)

Ideally, a code formatter can do more than just find formatting errors - it should fix them as well. Such a formatter is just a Function<String, String>, which returns a formatted version of its potentially unformatted input.

It's easy to build such a function, but there are some gotchas and lots of integration work (newlines, character encodings, idempotency, git ratcheting, and build-system integration). Spotless tackles those for you so you can focus on just a simple Function<String, String> which can compose with any of the other formatters and build tools in Spotless' arsenal.

Current feature matrix

Feature / FormatterStep gradle maven sbt (Your build tool here)
Automatic idempotency safeguard 👍 👍 👍
Misconfigured encoding safeguard 👍 👍 👍
Toggle with spotless:off and spotless:on 👍 👍
Ratchet from origin/main or other git ref 👍 👍
Define line endings using git 👍 👍 👍
Fast incremental format and up-to-date check 👍 👍
Fast format on fresh checkout using buildcache 👍
generic.EndWithNewlineStep 👍 👍
generic.IndentStep 👍 👍
generic.Jsr223Step 👍
generic.LicenseHeaderStep 👍 👍 👍
generic.NativeCmdStep 👍 👍
generic.ReplaceRegexStep 👍 👍
generic.ReplaceStep 👍 👍
generic.TrimTrailingWhitespaceStep 👍 👍
antlr4.Antlr4FormatterStep 👍 👍
biome.BiomeStep 👍 👍
cpp.ClangFormatStep 👍
cpp.EclipseFormatterStep 👍 👍 👍
go.GofmtFormatStep 👍
gherkin.GherkinUtilsStep 👍 👍
groovy.GrEclipseFormatterStep 👍 👍 👍
java.GoogleJavaFormatStep 👍 👍 👍
java.ImportOrderStep 👍 👍 👍
java.PalantirJavaFormatStep 👍 👍
java.RemoveUnusedImportsStep 👍 👍 👍
java.EclipseJdtFormatterStep 👍 👍 👍
java.FormatAnnotationsStep 👍 👍
java.CleanthatJavaStep 👍 👍
json.gson.GsonStep 👍 👍
json.JacksonJsonStep 👍 👍
json.JsonSimpleStep 👍 👍
json.JsonPatchStep 👍 👍
kotlin.KtLintStep 👍 👍 👍
kotlin.KtfmtStep 👍 👍
kotlin.DiktatStep 👍 👍
markdown.FreshMarkStep 👍
markdown.FlexmarkStep 👍 👍
npm.EslintFormatterStep 👍 👍
npm.PrettierFormatterStep 👍 👍
npm.TsFmtFormatterStep 👍 👍
pom.SortPomStep 👍 👍
protobuf.BufStep 👍
python.BlackStep 👍
scala.ScalaFmtStep 👍 👍 👍
shell.ShfmtStep 👍 👍
sql.DBeaverSQLFormatterStep 👍 👍 👍
wtp.EclipseWtpFormatterStep 👍 👍
yaml.JacksonYamlStep 👍 👍
(Your FormatterStep here)

Why are there empty squares?

Many projects get harder to work on as they get bigger. Spotless is easier to work on than ever, and one of the reasons why is that we don't require contributors to "fill the matrix". If you want to add Bazel support, we'd happily accept the PR even if it only supports the one formatter you use. And if you want to add FooFormatter support, we'll happily accept the PR even if it only supports the one build system you use.

Once someone has filled in one square of the formatter/build system matrix, it's easy for interested parties to fill in any empty squares, since you'll now have a working example for every piece needed.

Acknowledgements

spotless's People

Contributors

abelk2 avatar andrewparmet avatar awa-xima avatar bigdaz avatar blacelle avatar blutorange avatar dependabot[bot] avatar eirnym avatar fvgh avatar goooler avatar jamietanna avatar jbduncan avatar jlleitschuh avatar kwin avatar lutovich avatar magneticflux- avatar matthiasbalke avatar mernst avatar nedtwigg avatar nulls avatar petertrr avatar renovate[bot] avatar simschla avatar sineaggi avatar source-knights avatar star-zero avatar tcrawford-figure avatar tisoft avatar tisonkun avatar zacsweers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spotless's Issues

Add support for Scala

It would be nice to get comments from @alenkacz and @hierynomus, since they likely have more scala/gradle experience than I do.

Some context: Spotless is a formatting "switchboard" that composes different formatters for different languages with different build systems. Some of its value-add include stuff like:

  • up-to-date checking
  • automatically fixing minor idempotence glitches
  • handling encoding and newline stuff (including .gitattributes support)

Spotless understands a formatting rule as a Function<String, String>, and it integrates third-party formatters like google-java-format, eclipse-jdt, etc. using reflection.

We've added an initial implementation of scala support using scala-fmt, available in #68. Do you mind taking a look to see if it's got any obvious problems?

Of special note:

If you have any feedback, we'd love to have it! We're also eager to incorporate other kinds of formatter, if you know of any :)

Break into spotless-lib (reusable for other projects) and spotless-gradle

Spotless now has quite a few utilities for mass string manipulation which are useful outside of a gradle plugin:

  • ensuring idempotency, and working around it when there are bugs
  • writing functions in an easy-to-serialize way

If we break the core functionality into spotless-lib, that would allow spotless-maven, etc. It would also speed up the spotless test suite by relying less on the excellent but slow gradle testkit. Going to explore this in the spotless-lib branch.

Spotless fails with an exception if the project is checked out using the git worktree functionality

There is a RFE filed for JGit at https://bugs.eclipse.org/bugs/show_bug.cgi?id=477475

Maybe there is something that can be done in Spotless besides forcing me to either disable Spotless or making a full clone for the working tree?

Stacktrace is:

org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'gradle-test-master'.
        at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:94)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.notifyAfterEvaluate(LifecycleProjectEvaluator.java:89)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.doConfigure(LifecycleProjectEvaluator.java:76)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.access$000(LifecycleProjectEvaluator.java:33)
        at org.gradle.configuration.project.LifecycleProjectEvaluator$1.execute(LifecycleProjectEvaluator.java:53)
        at org.gradle.configuration.project.LifecycleProjectEvaluator$1.execute(LifecycleProjectEvaluator.java:50)
        at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:50)
        at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:628)
        at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:129)
        at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:35)
        at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:60)
        at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:38)
        at org.gradle.initialization.DefaultGradleLauncher$1.execute(DefaultGradleLauncher.java:161)
        at org.gradle.initialization.DefaultGradleLauncher$1.execute(DefaultGradleLauncher.java:158)
        at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:158)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:119)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:102)
        at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:71)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:41)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
        at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:75)
        at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
        at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:44)
        at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:29)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:47)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
        at org.gradle.util.Swapper.swap(Swapper.java:38)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
        at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
Caused by: org.eclipse.jgit.errors.NoWorkTreeException: Bare Repository has neither a working tree, nor an index
        at org.eclipse.jgit.lib.Repository.getWorkTree(Repository.java:1379)
        at com.diffplug.gradle.spotless.GitAttributesLineEndingPolicy.lambda$create$25(GitAttributesLineEndingPolicy.java:62)
        at com.diffplug.common.base.Errors$Rethrowing.lambda$wrap$11(Errors.java:342)
        at com.diffplug.common.base.Errors$Rethrowing.get(Errors.java:334)
        at com.diffplug.gradle.spotless.GitAttributesLineEndingPolicy.create(GitAttributesLineEndingPolicy.java:53)
        at com.diffplug.gradle.spotless.LineEnding.createPolicy(LineEnding.java:40)
        at com.diffplug.gradle.spotless.FormatExtension.getLineEndingPolicy(FormatExtension.java:72)
        at com.diffplug.gradle.spotless.FormatExtension.setupTask(FormatExtension.java:275)
        at com.diffplug.gradle.spotless.java.JavaExtension.setupTask(JavaExtension.java:97)
        at com.diffplug.gradle.spotless.SpotlessPlugin.createTask(SpotlessPlugin.java:71)
        at com.diffplug.gradle.spotless.SpotlessPlugin.createTasks(SpotlessPlugin.java:55)
        at com.diffplug.common.base.Errors.lambda$wrap$5(Errors.java:218)
        at com.diffplug.common.base.Errors.run(Errors.java:210)
        at com.diffplug.gradle.spotless.SpotlessPlugin.lambda$apply$33(SpotlessPlugin.java:42)
        at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:93)
        at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:82)
        at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:44)
        at org.gradle.internal.event.BroadcastDispatch.dispatch(BroadcastDispatch.java:79)
        at org.gradle.internal.event.BroadcastDispatch.dispatch(BroadcastDispatch.java:30)
        at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
        at com.sun.proxy.$Proxy15.afterEvaluate(Unknown Source)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.notifyAfterEvaluate(LifecycleProjectEvaluator.java:82)
        ... 56 more

Proposal: Break existing DSL to match gradle idioms

First off, let's review how Spotless works. Each FormatTask has an Iterable<File>, and a list of FormatterStep. FormatterStep is really just a Function<String, String> - take an unformatted string, return a formatted string. So to create a new task, you specify the files you want to format, then the list of steps you want to take to format them.

Right now, the spotless DSL works like this:

spotless {
    // create a new FormatExtension, and delegate it to the closure
    format 'misc', {
        // specify the files you want to format
        target '**/*.md'
        // and the steps you want to apply, in order
        trimTrailingWhitespace()
        custom 'customStepName', {
            // some function which takes a string, and returns a string
        }
    }

Over in #31, @oehme made a suggestion to change the DSL to be more gradle idiomatic, which i'm moving here. A first proposal is this:

spotless {
    // define formats for applying to certain kinds of code
    formats {
        misc {
            extensions '.gradle', '.md'
            trimTrailingWhitespace true
            step('customStep') {
                  // imperative code here
            }
        }
        all {
            indentWith '\t'
        }
    }
    // target specific file trees to format
    targets {
        buildFiles {
            dir
        }
    }
}

There's three changes wrapped up in this:

  1. Separate the definition of a format, and the files which it applies to.
    • Looking at the buildscripts where Spotless is in use, there is a 1:1 between formats and the files they apply to. I think this adds a concept to learn without adding a feature users need.
  2. Rather than trimTrailingWhitespace() being a step which gets added, it becomes a property which gets set. Presumably if it is set to true then we add the step, and if it is not set to true then it doesn't get added.
    • This makes Spotless more declarative, and allows us to remove an empty pair of parentheses to better match the Gradle style, since Gradle DSL doesn't allow no-argument statements.
    • Unfortunately, function application does not commute. If you change the order that you apply rules, it will change the output, as happened here. Depending on what order you set the properties, or what order Spotless listens to the results of what you set, you'll get a different outcome.
    • Spotless currently "fibs" a bit. It looks a little declarative, but it's actually very imperative. Each "line" in a format adds a function to a list, and then those functions are applied in order. The nice part is that it's easy to describe this to users who need custom rules, and in the corner-cases where the order of formatting steps matters, it's easy to fix.
  3. By using gradle containers, rather than format 'misc', {}, we can now just say misc {}, which allows us to also use the all{} block to apply some logic to all the formats.
    • Pro: Definitely looks better.
    • Con: When does the 'all' block take effect? Does it run before the others or after? Does it depend on its order in the file relative to the other blocks?
    • Con: The distinction between a custom "format" block and a "magic" java/freshmark block is now less clear. How come I can call eclipseFormatFile if my block is called java but not javaSource?
    • Con: Breaks all existing custom scripts.
    • Con: Future contributors will have to know a little about gradle containers, which makes test code like this harder to write.

Imo, 1 & 2 do not improve Spotless. 3 definitely does, but the tradeoff is that we have to add the Gradle-specific container concept. Gradle has done a fantastic job of taking the "convention-over-configuration" idea, mixing it with a scripting language, and fostering a vibrant plugin ecosystem. But it's also, imo, made a few mistakes. I'm skeptical about whether the container idea adds enough value to be worth learning, and asking Spotless' users to learn.

Certainly there are ways to improve Spotless' design, but I'm hesitant to break existing user's builds unless it makes a big difference for future adopters. My ears are open, but I don't see a clear enough win to justify the cost.

Does spotless support the use of regular expression for the header license?

example:

/*
 * Copyright <^(19|20)\d{2}$>   [a-zA-Z]
 *
 * 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.
 */

Ps: for the year and author.
Thanks before

Add support for google-java-format

The google java format is popular, and until 2014 it could be enforced using the eclipse code formatter.

Now they have a separate jar called google-java-format. It would be nice if Spotless had a step:

spotless {
    java {
        googleJavaFormat()
    }
}

Which used the google-java-gormat jar.

One tricky issue is it seems that these jars are evolving, and there is some desire in the community to have access to snapshot versions of the jar. Very easy to support a fixed version of the jar (it is available on maven central, but I'm not sure how to support multiple versions...

If any contributors are interested in adding this functionality, all that is required is a method here: JavaExtension.java.

lineEndings cannot be set

We have a multi-platform developer environment and switching code between Windows, Mac and Linux is causing all sorts of line ending problem.

I tried adding:

lineEndings = PLATFORM_NATIVE

lineEndings = UNIX

in the applies spotless { } but it thrown an exception:

Could not find property 'PLATFORM_NATIVE' on com.diffplug.gradle.spotless.SpotlessExtension_Decorated@1d012c85.

Is there an import missing?

Release 3.0.0

I just published 3.0.0.BETA2. It's still waiting for approval on the gradle plugin portal because of the groupId/artifactId change, but it's up on jcenter and mavencentral here: com.diffplug.spotless:spotless-plugin-gradle:3.0.0.BETA2

Let's bang on it a little and make sure it's ready to go. I know it's got some issues, let's hunt them down and ship this sucker!

importOrderFile fails on "all unmatched type imports" group

If you create an Eclipse import order including an "all unmatched type imports" group and attempt to use it with Spotless, Spotless errors.

Example import order file matching the Google Java style guide:

#Organize Import Order
#Sat Aug 22 12:43:31 BST 2015
4=javax
3=java
2=
1=com.google
0=\#

Note that "all unmatched type imports" (as the Eclipse UI phrases it) is represented by an empty string (number 2).

I think the error is produced in

where it is assumed that splitting the line on = will produce two strings.

Formatting Java breaks long literals with underscores

I guess this a bug of the Eclipse formatter used under the hood, nevertheless I'm going to report it here:
My Java source files contain long literals like

long foo = 123_456_789L;

Using spotlessApply turns this into the syntactically wrong line

long foo = 123_456_789 L;

(note the additional space between the digits and the L).

This problem can be fixed by adding the following custom rule

custom 'long literal fix', { it.replaceAll('([0-9_]+) [Ll]', '$1L') }

However, spotless should work correctly without requiring this tweak.

If spotlessCheck fails, the error message could include a diff

This would make it easier to understand what spotlessApply would do, if it were called. If anybody wants to contribute this functionality:

  • FormatTask.formatCheck() is where the exception is exception is thrown right now.
  • Formatter.isClean(File) is where the formatted and unformatted strings are both available. So that's where you'd get the things to diff.

Eclipse formatting not performed during the build

I inserted
apply plugin: 'com.diffplug.gradle.spotless' ... spotless { java { eclipseFormatFile '../misc/collections-team-format.xml' // XML file dumped out by the Eclipse formatter } } into my build.gradle.
I understand the formatting should happen automatically (why would I need the plugin otherwise?), but it doesn't - I receive "> The following files had format violations:..." diff and the build fails. I realize that explicit invocation of "./gradlew spotlessApply build" will format the code prior to the build but why wouldn't it automatically format when "./gradlew build" is invoked?

Specify that Java 8 is required

Documentation apparently does not specify in an obvious place that Gradle needs to be run under Java 8 in order for this to work. Should be stated early in docs.

Provide explicit support for Groovy source code

Status Quo

Groovy source code files are not officially supported by Spotless.

You therefore have to hack something together like the following:

format 'groovy', {
    target '**/*.groovy'
    indentWithTabs()
    trimTrailingWhitespace()
    endWithNewline()
    licenseHeaderFile rootProject.file('src/spotless/eclipse-public-license-1.0.java'), "package "

    customReplaceRegex 'class-level Javadoc indentation fix', /^\*/, ' *'
    customReplaceRegex 'nested Javadoc indentation fix', /\t\*/, '\t *'
}

Without the custom regular expressions, Spotless will mangle Javadoc and license header comment blocks.

Proposal

  • Support Groovy scripts as a first-class citizen with built-in support for license headers and Javadoc comment blocks.

Skip the spotlessCheck by default

Is it possible to run the spotlessCheck if we explicitly mention it?

At the moment, the command gradle build with this plugin automatically runs the spotlessCheck.
one of the work arounds is to use the command gradle build -x spotlessCheck.

Kindly advice

Add support for Kotlin

With Kotlin build scripts coming, it would be great for Spotless to add support for kotlin. shyiko/ktlint seems to be the main entry in this space.

Added a first cut in feature/kotlin, but it's pretty difficult to integrate via reflection at the moment because some of the args are hard to instantiate (code). Should be easy to fix with a small change on the library side, I'll contact the author there.

Eclipse formatter doesn't format javadoc

The eclipse formatter isn't applying itself to javadoc blocks for some unknown reason. As a semi-workaround, you can add trimTrailingWhitespace() to the end your spotless block and at least ensure there's no trailing whitespace.

I'll look into this when Eclipse Neon and Gradle 2.14 land, as there are likely to be helpful bugfixes in those.

Java files under src/*/groovy aren't detected by default

Spotless Version 2.4

In projects that do joint Java/Groovy compilation, you often need some or all of the Java files to be under the src/main/groovy directory. Spotless currently uses sourceSets.main.java to get the Java files to format by default. Using sourceSets.main.allJava would pick up the full set of Java source in these joint compile scenarios and the existing use case.

I should have a PR ready today for this.

spotlessCheck failed in Windows but not in linux

with the same spotless plugin applied, the project's build failed in Windows, but not in Linux, is it possible to have a log to check the issue? Could it be an issue of line ending characters? Please advise

Feature suggestion: Fail compile on file contents

It's very nice that we can automatically reformat code and replace things with spotless, but we also have sometimes problems that aren't easily fixed by replacements (for example missing license headers (no, just adding them automatically doesn't work because we want to list contributors and so on), usage of prohibited/deprecated classes, swear words in comments and so on.

It would be great if we could do something like

spotless {
		java {
			customFailure 'test', {
                            // it = file contents
                            if(it.contains("java.util.Scanner") {
                                fail('please use BufferedReader instead')
                            }
			}
		}

of course that's a very rough example. The currect "custom" block unfortunately eats all exceptions more or less silently ("Unable to apply step "), else that would be a workaround by just replacing nothing and throwing an exception.

Imports are not in lexicographical order

Hi,
I have mentioned my imports to be in order : ['java', 'javax', 'org', 'com'']
but after spotlessApply, imports are organized in order : ['java', 'javax', 'lombok' ,'org', 'com','io'].
I guess lombok should come after 'io'.

Consider bumping default version of google-java-format from 1.1 to 1.2.

I think this is a worthwhile change to pursue, but before opening a PR, I want to understand the pros and cons of it.

These are the pros and cons I can think of at the moment:

Pros:

  • More "correct" behaviour by default.

Cons:

  • Can break people's builds if they depend on the default version being 1.1.
  • Requires a new version of spotless-lib (but that would be par for the course).

Consider changing README to include updated error message example

Currently, the README shows the following example error message.

cmd> gradlew build
...
:spotlessJavaCheck FAILED
> Format violations were found. Run 'gradlew spotlessApply' to fix them.
    src\test\java\com\diffplug\gradle\spotless\ResourceTest.java

cmd> gradlew spotlessApply
:spotlessApply
BUILD SUCCESSFUL

cmd> gradlew build
BUILD SUCCESSFUL

But since Spotless version 2.3.0, it now outputs a different message that includes a git-style diff for each of the first few files that violate the specified formatting rules. I suspect this confuses new users, from my observation of issue #51.

When we have the time, I think we should update the README to show what a typical error message looks like now.

Spotless replaces package-info.java's javadoc with the license

If Spotless has a licenseHeader specified, it replaces everything between the top of the file and the package statement with the license. This works for regular classes, but it doesn't work for package-info.java files.

As a workaround, you can do this:

java {
    target project.fileTree(project.rootDir) {
        include '**/*.java'
        exclude '**/package-info.java'
        exclude 'spotless.license.java'
    }
    ... (the rest of the config)
}

Spotless' default settings should play nicely with package-info.java, but at the moment it's not a big enough problem for me to actually fix. If this is an actual problem for you, reply to this issue and I'll actually fix it.

Error: Unsupported major.minor version 52.

Executed: gradle build
Output: java.lang.UnsupportedClassVersionError: com/diffplug/gradle/spotless/SpotlessPlugin : Unsupported major.minor version 52.0

gradle.build:

plugins {
id "com.diffplug.gradle.spotless" version "1.3.3"
}

apply plugin: 'com.diffplug.gradle.spotless'
spotless {
java {
eclipseFormatFile 'eclipse-java-google-style.xml' // XML file dumped out by the Eclipse formatter
}
}

Java version: 1.7.0_79

Allow configuration of when to run spotless in gradle build

Currently spotless adds itself automatically to the gradle checkTask.

// Add our check task as a dependency on the global check task
// getTasks() returns a "live" collection, so this works even if the
// task doesn't exist at the time this call is made
project.getTasks()
    .matching(task -> task.getName().equals(JavaBasePlugin.CHECK_TASK_NAME))
    .all(task -> task.dependsOn(rootCheckTask));

We would like to be able to decide when to actually run the spotless task or even be able to only run it when directly invoked from the command line like gradlew spotless

e.g. for configuration

spotless {
    ...
}
// new
taskX.dependsOn spotless

Quick up-to-date checking for custom rules (sub to #31)

In order for incremental builds and up-to-date checking to work, we need FormatCheckTask to properly implement serializable, equals, and hashCode. This means that FormatStep and all of its implementations (eclipse, google-java-format, regex, etc.) will also have to implement these contracts, which is straightforward to do.

The downside is that custom rules, along the lines of:

custom 'No scanners', {
    if (it.contains('java.util.Scanner') {
        throw new AssertionError('please use BufferedReader instead')
    }
}

will always be out-of-date unless they properly implement the contract. One quick way to resolve this is to have a ForwardingFormatStep which delegates all of its serializable/equals/hashCode tasks to some delegate object. Then custom rules could easily be written as

custom 'No scanners', {
    if (it.contains('java.util.Scanner') {
        throw new AssertionError('please use BufferedReader instead')
    }
}, upToDateVersion=1

But if any rule in a list has changed, then the entire format has to rerun. Sooo, instead of checking each rule, we could instead check them globally across the format:

format 'someFormat' {
    custom 'someStep', {}
    custom 'someOtherStep', {}
    bumpThisNumberIfRulesChange(1)
}

If a project has even two custom rules, then this format-global approach is easier than having a version per custom rule.

The next question is whether we want to use this functionality to remove the requirement for FormatTasks to implement serializable/equals/hashCode at all, and just rely on bumpThisNumberIfRulesChange() to entirely encapsulate changes to the rules.

On the one side, we should have spotless be as fast as possible with as little user input as possible, and there are plenty of users that are only using built-in rules, so bumpThisNumberIfRulesChange() should be limited to a useful override for handling custom rules. Thoughts?

Spotless does not respect line endings on Windows 10

We have lineEndings = 'unix'; specified in our Spotless config, but it appears to not be respected in Windows 10 or Windows Server 2016.

Here are the instructions to reproduce:

I ran ./gradlew spotlessApply on the Windows 10 machine using git bash this
is what has happened.
NOTE: I started the below steps on a fresh git clone of the open side.
[Steps:

  1. git clone https://git-wip-us.apache.org/repos/asf/incubator-geode.git
    open
  2. cd open
  3. git checkout -b develop origin/develop]

Step 1. ./gradlew clean build -Dskip.tests=true

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':geode-core:spotlessJavaCheck'.
    Format violations were found. Run 'gradlew spotlessApply' to fix them.

geode-core\src\main\java\org\apache\geode\internal\statistics\StatArchiveReader.java

geode-core\src\test\java\org\apache\geode\cache\query\dunit\PdxLocalQueryVersionedClassDUnitTest.java

geode-core\src\test\java\org\apache\geode\internal\cache\execute\ClientServerFunctionExecutionDUnitTest.java

geode-core\src\test\java\org\apache\geode\internal\cache\functions\TestFunction.java

geode-core\src\test\java\org\apache\geode\internal\statistics\StatArchiveWithMissingResourceTypeRegressionTest.java

Step 2: ./gradlew spotlessApply

BUILD SUCCESSFUL

Total time: 12.728 secs

Step 3: git status

modified:
geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveReader.java
modified:
geode-core/src/test/java/org/apache/geode/cache/query/dunit/PdxLocalQueryVersionedClassDUnitTest.java
modified:
geode-core/src/test/java/org/apache/geode/internal/cache/execute/ClientServerFunctionExecutionDUnitTest.java
modified:
geode-core/src/test/java/org/apache/geode/internal/cache/functions/TestFunction.java
modified:
geode-core/src/test/java/org/apache/geode/internal/statistics/StatArchiveWithMissingResourceTypeRegressionTest.java

Step 4 : git add .
warning: LF will be replaced by CRLF in
geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveReader.java.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in
geode-core/src/test/java/org/apache/geode/cache/query/dunit/PdxLocalQueryVersionedClassDUnitTest.java.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in
geode-core/src/test/java/org/apache/geode/internal/cache/execute/ClientServerFunctionExecutionDUnitTest.java.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in
geode-core/src/test/java/org/apache/geode/internal/cache/functions/TestFunction.java.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in
geode-core/src/test/java/org/apache/geode/internal/statistics/StatArchiveWithMissingResourceTypeRegressionTest.java.
The file will have its original line endings in your working directory.

Step 5: git status
On branch develop
Your branch is up-to-date with 'origin/develop'.
nothing to commit, working tree clean

Step 6: ./gradlew clean build -Dskip.tests=true
BUILD SUCCESSFUL

Total time: 5 mins 28.64 secs

Support license header for Java classes in default package

Overview

Disclaimer: I don't condone the use of the default package in Java at all.

However... having said that, we need to support test classes declared in the default package in JUnit 5. So I added a DefaultPackageTestCase to our test suite to verify our support for such use cases.

Consequently, when Spotless is applied during the JUnit 5 builds, we now see the following:

Unable to apply step LicenseHeader to src/test/java/DefaultPackageTestCase.java: Unable to find delimiter regex ^package

Since a Java class in the default package does not have a package declaration, it makes sense that your regular expression would fail to find ^package; however, just because a class exists in the default package shouldn't mean that it does not have the license header rule applied.

Proposal

If a class is in the default package, consider doing one of the following:

  1. use a different means for determining the location of the license header file -- for example, prior to ^import, ^/**, or similar.
  2. just make sure the license header exists at the top of the document.

Add support for enforcing line endings from .gitattributes

@chkpnt submitted a great PR #22 which allows different line endings for different formats. After discussion, we've decided to instead implement support for the .gitattributes eol property.

Provisionally, support will look like this:

spotless {
    lineEndings GITATTRIBUTES
}

This should probably have been the default behavior all along, but it's a breaking change compared to the current default, lineEndings PLATFORM_NATIVE. As a result I think I'll make this next release version 2.0 to alert users to check the changelog.

As for timeline, I'm planning on implementing this in late June when Eclipse 4.6 and Gradle 2.14 will be released, the combination of which should fix quite a few issues.

Spotless can't run Spotless on itself

For some reason, we can't add Spotless to the buildscript classpath of Spotless, which means we have to manually run SelfTest.java from an IDE to check and apply formatting.

Here's the error, straight from Travis.

* What went wrong:
A problem occurred configuring root project 'spotless'.
> Could not resolve all dependencies for configuration ':classpath'.
   > Module version com.diffplug.gradle.spotless:spotless:1.3.0-SNAPSHOT, configuration 'classpath' declares a dependency on configuration 'default' which is not declared in the module descriptor for com.diffplug.gradle.spotless:spotless:1.3.0-SNAPSHOT

To reproduce the issue, just checkout issueWithBootstrap. The commit that introduces the change is c06839ae.

Unexpected behaviour from `indentWithSpaces(int)`

Given the following build script and Java file on Gradle 3.2.1:
build.gradle

plugins {
    id 'java'
    id 'com.diffplug.gradle.spotless' version '2.4.0'
}

group 'org.jbduncan'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

spotless {
    format('example') {
        target '**/*.java'
        indentWithSpaces(4)
    }
}

src/main/java/HelloWorld.java

public final class HelloWorld {
      public String greeting() {
        return "Hello, world!";
    }
}

...I would have expected the Java file to turn into:

public final class HelloWorld {
    public String greeting() {
        return "Hello, world!";
    }
}

or:

public final class HelloWorld {
        public String greeting() {
        return "Hello, world!";
    }
}

...but it seems it doesn't.

Have I misunderstood what indentWithSpaces(4) is supposed to do here? I understand that it turns all tab indents into 4-space indents, but by my intuitive understanding it should also make sure that all space-indents have a number of spaces equal to a multiple of 4.

Is the license header for Spotless itself correct?

By my understanding, Spotless was first released in 2014, so wouldn't the following license header be more accurate?

/*
 * Copyright 2014-2016 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.
 */

I suppose my reason for raising this issue is because I recently read DotNetAnalyzers/StyleCopAnalyzers#1661, which goes into rather gory detail about the apparent legal consequences of having the wrong year on license headers of source code files.

(It also seems to suggest that all source files should be indicated with the year that the project was started (2014 for us), rather than a year range (2014-2016 for us), but I'm doubtful about the accuracy of this suggestion as I've never seen it in practice before and no-one on the thread seems to be a laywer...)

(Also, yes, I know, cheeriest thing ever to talk about on Christmas Day. 😉)

Upgrade to Eclipse 4.5.1+ regarding bug fixes in formatter

Overview

As discussed in the JUnit 5 repository, the Eclipse Java formatter used by Spotless 1.3.2 is hard coded to version R-4.5-201506032000 (see build.gradle for Spotless), and this version contains a bug regarding whitespace after [] in annotation attribute declarations.

This bug has been fixed in Eclipse 4.5.1 and 4.6.

However, since Spotless embeds the Eclipse JARs, it is (AFAIK) not possible to perform an upgrade to the Eclipse version used by Spotless.

Deliverables

  • Either release a version of Spotless that embeds Eclipse 4.5.1+
  • Or release a version of Spotless that makes it possible to upgrade the version of Eclipse used by Spotless via standard dependency management within a Gradle build
  • Or release a version of Spotless that provides both of the aforementioned improvements

EOL CRLF vs LF

Is there a way that we can force spotless to use LF eol for both windows and unix?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.