Keep your code spotless

Overview

Spotless: Keep your code spotless

Circle CI Live chat License Apache

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 | sql | typeScript | vue | yaml | anything> using <gradle | maven | anything>.

You probably want one of the links below:

❇️ Spotless for Gradle (with VS Code integration)

❇️ Spotless for Maven

❇️ Spotless for SBT (external for now)

Other build systems

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 👍 👍
cpp.ClangFormatStep 👍
cpp.EclipseFormatterStep 👍 👍 👍
groovy.GrEclipseFormatterStep 👍 👍 👍
java.GoogleJavaFormatStep 👍 👍 👍
java.ImportOrderStep 👍 👍 👍
java.RemoveUnusedImportsStep 👍 👍 👍
java.EclipseJdtFormatterStep 👍 👍 👍
kotlin.KtLintStep 👍 👍 👍
kotlin.KtfmtStep 👍 👍
kotlin.DiktatStep 👍 👍
markdown.FreshMarkStep 👍
npm.PrettierFormatterStep 👍 👍
npm.TsFmtFormatterStep 👍 👍
pom.SortPomStepStep 👍
python.BlackStep 👍
scala.ScalaFmtStep 👍 👍 👍
sql.DBeaverSQLFormatterStep 👍 👍 👍
wtp.EclipseWtpFormatterStep 👍 👍
(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

Comments
  • Declare inputs and outputs to support up-to-date checking

    Declare inputs and outputs to support up-to-date checking

    The spotless check task currently doesn't have any inputs and outputs declared and is thus never considered up-to-date. This is slowing down user's builds unnecessarily.

    enhancement 
    opened by oehme 104
  • Task configuration avoidance (WIP) (#269)

    Task configuration avoidance (WIP) (#269)

    This is a WIP PR to show how task configuration avoidance may look like in the Spotless Gradle plugin (see issue https://github.com/diffplug/spotless/issues/269).

    No profiling against Spotless itself or against an external project has been done yet. Those are the next things which need to be done.

    Feedback is more than welcome!

    Resolves #269.


    Please make sure that your PR allows edits from maintainers. Sometimes its faster for us to just fix something than it is to describe how to fix it.

    Allow edits from maintainers

    After creating the PR, please add a commit that adds a bullet-point under the -SNAPSHOT section of CHANGES.md and plugin-gradle/CHANGES.md which includes:

    • [ ] a summary of the change
    • [ ] a link to the newly created PR

    If your change only affects a build plugin, and not the lib, then you only need to update the CHANGES.md for that plugin.

    If your change affects lib in an end-user-visible way (fixing a bug, updating a version) then you need to update CHANGES.md for both the lib and the build plugins. Users of a build plugin shouldn't have to refer to lib to see changes that affect them.

    This makes it easier for the maintainers to quickly release your changes :)

    opened by jbduncan 48
  • Proposal: replace `check` and `apply` with a single task with a CLI flag

    Proposal: replace `check` and `apply` with a single task with a CLI flag

    Instead of having spotlessCheck and spotlessApply, we could instead just have spotless, which could do the same thing as spotlessCheck. In place of spotlessApply, the user would instead run gradlew spotless --apply.

    This might mesh better with the incremental build model being implemented in #31.

    enhancement 
    opened by nedtwigg 44
  • Initial version of Spotless Maven plugin

    Initial version of Spotless Maven plugin

    Hi!

    This PR adds a very minimal implementation of the Maven plugin. It's primary goal is to get feedback on the general approach and potential tips for further implementation.

    Plugin is able to apply Eclipse formatter step to all java files in the project. It only takes a single parameter - 'eclipseFormatFile' which is a path to the formatter configuration.

    Two main blocks:

    1. Build of the plugin This part is quite ugly. I was not able to find a good way to make Gradle natively create a JAR equivalent to one with <packaging>maven-plugin</packaging> in Maven. Such packaging includes some additional plugin configuration xml files. That is why Gradle build script invokes Maven via Exec plugin and makes it assemble the final plugin JAR. Two Spotless dependencies lib.jar and lib-extra.jar are installed in a directory-based Maven repo that is used during the build. They are also shaded into the final plugin JAR. Plugin sources and prepared pom.xml are copied to a temp directory. Then simple mvn clean install is executed there by Gradle Exec. Final JAR is copied to build/libs.

    2. Plugin code Lives in the class SpotlessMojo that has needed Maven components and 'eclipseFormatFile' config value injected by the Plexus container. It uses ArtifactResolver to create a MavenProvisioner that is able to download specified Maven dependencies. Mojo creates a single EclipseFormatterStep, then walks all*.java` files in the compile sources roots and formats them using this step.

    Missing/unclear bits:

    • unclear if it is actually possible to not invoke Maven from Gradle
    • dependency information is duplicated in pom.xml and build.gradle. pom.xml can be generated with all dependencies from build.gradle
    • publishing of the Maven plugin to Maven Central
    • support for more configuration of the plugin, different formatter steps, line endings, etc.
    • use Formatter
    • use Maven Wrapper to not require pre-installed Maven when building
    • unclear how to version the plugin
    • unit tests

    Existence of mvn command is assumed during the build. Plugin can be added to a Maven project like this:

    <plugin>
      <groupId>com.diffplug.spotless</groupId>
      <artifactId>spotless-maven-plugin</artifactId>
      <version>1.0-SNAPSHOT</version>
      <configuration>
        <eclipseFormatFile>${basedir}/build/eclipse-format.xml</eclipseFormatFile>
      </configuration>
    </plugin>
    

    and invoked manually using this command:

    mvn com.diffplug.spotless:spotless-maven-plugin:spotless
    

    "As is" PR is not really ready for merge. Maybe it can be a start?

    P.S. thanks a lot for the Gradle plugin! :)

    opened by lutovich 42
  • Adding npm-based formatters typescript-formatter (tsfmt) and prettier

    Adding npm-based formatters typescript-formatter (tsfmt) and prettier

    The goal of this PR is to add two new formatter steps to spotless

    • prettier.io
    • tsfmt

    This enables spotless to format typescript and all the languages supported by prettier.

    The state of the code is currently in draft. A lot needs to be done, but I start the PR now, to be able to discuss on the code rather than in issue #119

    opened by simschla 39
  • [SECURITY] CVE-2019-10753: Releases are built/executed/released in the context of insecure/untrusted code

    [SECURITY] CVE-2019-10753: Releases are built/executed/released in the context of insecure/untrusted code

    CWE-829: Inclusion of Functionality from Untrusted Control Sphere

    The build files indicate that this project is resolving dependencies over HTTP instead of HTTPS. Any of these artifacts could have been MITM to maliciously compromise them and infect the build artifacts that were produced. Additionally, if any of these JAR files were compromised, any developers using these could continue to be infected past updating to fix this.

    • https://github.com/diffplug/spotless/blob/366c1b9042ec938cf70ee19a152570f91426c6fb/_ext/eclipse-cdt/build.gradle#L6
    • https://github.com/diffplug/spotless/blob/96e74ec3fb5ca050ec5aa67f4801e11bf744acef/_ext/eclipse-groovy/build.gradle#L6
    • https://github.com/diffplug/spotless/blob/e1734c082a1123d8a40df9424fb021873d7744ad/_ext/eclipse-wtp/build.gradle#L6

    This vulnerability has a CVSS v3.0 Base Score of 8.1/10 https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

    This isn't just theoretical; POC code exists already to maliciously compromise jar file inflight.

    See:

    • https://max.computer/blog/how-to-take-over-the-computer-of-any-java-or-clojure-or-scala-developer/
    • https://github.com/mveytsman/dilettante

    To fix: We need to update our build.gradle so that artifacts are resolved over HTTPS instead of HTTP.

    I've been finding this vulnerability in a lot of places today and have responsibly disclosed it to some of the larger organizations involved.

    security 
    opened by JLLeitschuh 36
  • Add support for Gradle Configuration Cache

    Add support for Gradle Configuration Cache

    Gradle 6.6 introduces the configuration cache. It looks useful, and it would be great to refactor Spotless to support it. I am okay with bumping our minimum required Gradle in order to support it. https://github.com/gradle/gradle/issues/13490

    enhancement 
    opened by nedtwigg 33
  • Cannot add a configuration with name 'classpath' as a configuration with that name already exists (intermittent plugin-gradle concurrency bug)

    Cannot add a configuration with name 'classpath' as a configuration with that name already exists (intermittent plugin-gradle concurrency bug)

    Hi, we just had a spurious error on our jenkins after upgrading our spotless gradle plugin to 3.18 due to "org.gradle.api.InvalidUserDataException: Cannot add a configuration with name 'classpath' as a configuration with that name already exists." This is for a multiproject build with parallel execution and it seems that gradle tries to create the classpath configuration multiple times in DefaultScriptHandler. Seeing as there are no locks in this code, I'm guessing that defineConfiguration() is not meant to be called in parallel but somehow it is being called that way.

    Also the error message printed to the log about missing repos is a bit confusing due to GradleProvisioner catching Exception and printing a error message that's better suited for catching ResolveException. I first troubleshooting thought was to go to our artifactory and check our logs (it sent the files correctly).

    Gradle 5.2.1, Spotless gradle plugin 3.18, Ubuntu 16.04 docker container.

    buildSrc/build.gradle
    =====================
    
    repositories {
      maven {
        url 'https://ourartifactory.stuff/mvn'
        credentials {
          username = artifactory_user
          password = artifactory_password
        }
      }
    }
    dependencies {
      compile "com.diffplug.spotless:spotless-plugin-gradle:3.18.0" // Use of buildSrc to infer repositories/dependencies to all build scripts
    }
    
    
    build.gradle
    ============
    allprojects {
      pluginManager.withPlugin('java') {
        apply plugin: "com.diffplug.gradle.spotless"
        spotless {
          // See https://github.com/diffplug/spotless/tree/master/plugin-gradle for configuration
          java {
            target 'src/**/*.java' // Only format checked in code, not generated sources        
            removeUnusedImports() // removes any unused imports
            eclipse('4.9.0').configFile "$rootDir/utils/.settings/org.eclipse.jdt.core.prefs"
          }
        }
        tasks.withType(JavaCompile)*.dependsOn 'spotlessApply'    
      }
    }
    
    07:42:47  > Task :SubProj1:spotlessJava
    07:42:47  You probably need to add a repository containing the '[com.google.googlejavaformat:google-java-format:1.7]' artifact in the 'build.gradle' of your root project.
    07:42:47  E.g.: 'buildscript { repositories { mavenCentral() }}'
    07:42:47  Note that included buildscripts (using 'apply from') do not share their buildscript repositories with the underlying project.
    07:42:47  You have to specify the missing repository explicitly in the buildscript of the root project.
    07:42:47  
    07:42:47  org.gradle.api.InvalidUserDataException: Cannot add a configuration with name 'classpath' as a configuration with that name already exists.
    07:42:47  	at org.gradle.api.internal.DefaultNamedDomainObjectCollection.assertCanAdd(DefaultNamedDomainObjectCollection.java:212)
    07:42:47  	at org.gradle.api.internal.AbstractNamedDomainObjectContainer.create(AbstractNamedDomainObjectContainer.java:93)
    07:42:47  	at org.gradle.api.internal.AbstractValidatingNamedDomainObjectContainer.create(AbstractValidatingNamedDomainObjectContainer.java:46)
    07:42:47  	at org.gradle.api.internal.AbstractNamedDomainObjectContainer.create(AbstractNamedDomainObjectContainer.java:75)
    07:42:47  	at org.gradle.api.internal.initialization.DefaultScriptHandler.defineConfiguration(DefaultScriptHandler.java:111)
    07:42:47  	at org.gradle.api.internal.initialization.DefaultScriptHandler.getConfigurations(DefaultScriptHandler.java:101)
    07:42:47  	at com.diffplug.gradle.spotless.GradleProvisioner.lambda$fromProject$1(GradleProvisioner.java:40)
    07:42:47  	at com.diffplug.spotless.JarState.provisionWithTransitives(JarState.java:87)
    07:42:47  	at com.diffplug.spotless.JarState.from(JarState.java:76)
    07:42:47  	at com.diffplug.spotless.JarState.from(JarState.java:71)
    07:42:47  	at com.diffplug.spotless.java.GoogleJavaFormatStep$State.<init>(GoogleJavaFormatStep.java:99)
    07:42:47  	at com.diffplug.spotless.java.GoogleJavaFormatStep$State.<init>(GoogleJavaFormatStep.java:95)
    07:42:47  	at com.diffplug.spotless.java.RemoveUnusedImportsStep.lambda$create$0(RemoveUnusedImportsStep.java:33)
    07:42:47  	at com.diffplug.spotless.FormatterStepImpl.calculateState(FormatterStepImpl.java:56)
    07:42:47  	at com.diffplug.spotless.LazyForwardingEquality.state(LazyForwardingEquality.java:56)
    07:42:47  	at com.diffplug.spotless.LazyForwardingEquality.writeObject(LazyForwardingEquality.java:68)
    07:42:47  	at sun.reflect.GeneratedMethodAccessor535.invoke(Unknown Source)
    07:42:47  	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    07:42:47  	at java.lang.reflect.Method.invoke(Method.java:498)
    07:42:47  	at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1128)
    07:42:47  	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    07:42:47  	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    07:42:47  	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    07:42:47  	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    07:42:47  	at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.serialize(DefaultValueSnapshotter.java:180)
    07:42:47  	at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.processValue(DefaultValueSnapshotter.java:172)
    07:42:47  	at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.snapshot(DefaultValueSnapshotter.java:59)
    07:42:47  	at org.gradle.internal.snapshot.ValueSnapshotStrategy.snapshot(ValueSnapshotStrategy.java:30)
    07:42:47  	at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.processValue(DefaultValueSnapshotter.java:99)
    07:42:47  	at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.snapshot(DefaultValueSnapshotter.java:59)
    07:42:47  	at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionStateTaskExecuter.snapshotTaskInputProperties(ResolveBeforeExecutionStateTaskExecuter.java:124)
    07:42:47  	at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionStateTaskExecuter.createExecutionState(ResolveBeforeExecutionStateTaskExecuter.java:90)
    07:42:47  	at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionStateTaskExecuter.execute(ResolveBeforeExecutionStateTaskExecuter.java:72)
    07:42:47  	at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    07:42:47  	at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:109)
    07:42:47  	at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionOutputsTaskExecuter.execute(ResolveBeforeExecutionOutputsTaskExecuter.java:67)
    07:42:47  	at org.gradle.api.internal.tasks.execution.ResolveAfterPreviousExecutionStateTaskExecuter.execute(ResolveAfterPreviousExecutionStateTaskExecuter.java:46)
    07:42:47  	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:93)
    07:42:47  	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:45)
    07:42:47  	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:94)
    07:42:47  	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
    07:42:47  	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
    07:42:47  	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
    07:42:47  	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:63)
    07:42:47  	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:49)
    07:42:47  	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:46)
    07:42:47  	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
    07:42:47  	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
    07:42:47  	at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
    07:42:47  	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
    07:42:47  	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
    07:42:47  	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
    07:42:47  	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
    07:42:47  	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:46)
    07:42:47  	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:43)
    07:42:47  	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:355)
    07:42:47  	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343)
    07:42:47  	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:336)
    07:42:47  	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:322)
    07:42:47  	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:134)
    07:42:47  	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:129)
    07:42:47  	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:202)
    07:42:47  	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:193)
    07:42:47  	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:129)
    07:42:47  	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    07:42:47  	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    07:42:47  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    07:42:47  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    07:42:47  	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    07:42:47  	at java.lang.Thread.run(Thread.java:748)
    07:42:47  
    
    bug 
    opened by staffanf 33
  • CVE-2019-9843: The XML parser isn't respecting resolveExternalEntities as false

    CVE-2019-9843: The XML parser isn't respecting resolveExternalEntities as false

    Original Comment: https://github.com/diffplug/spotless/issues/308#issuecomment-463297964

    12:48:55.013 [DEBUG] [sun.net.www.protocol.http.HttpURLConnection] Redirected from http://java.sun.com/xml/ns/javaee/javaee_5.xsd to http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/javaee_5.xsd
    

    If we are seeing HTTP get requests inside of the XML parser that means that the parser is vulnerable to XXE.

    We need to fix this so that the spotless XML formatter is not making external entity requests.

    We can't have our linting infrastructure making web requests. Especially web requests over HTTP as those can be maliciously intercepted by a MITM.

    Here's an example where this has been a serious problem in the past.

    https://research.checkpoint.com/parsedroid-targeting-android-development-research-community/

    CC: @nedtwigg

    This is a security vulnerability in spotless and should be treated as such.

    bug security 
    opened by JLLeitschuh 31
  • Custom Spotless Task

    Custom Spotless Task

    Hello!

    I'm trying to create a custom spotless task that only acts on files changed in git. I would also like the option to act on all files, so ideally I would have two separate tasks. For example, spotlessJavaCheck should check the pattern **/*.java, while spotlessChangedCheck should check only the files changed in git.

    I've already written a function in the build script which identifies the changed files, and I would like to set the spotless target to these files.

    Any advice?

    question 
    opened by t-rad679 29
  • "java.lang.IllegalStateException: Workspace is closed" with eclipse('4.7.2')

    spotless 3.8.0

    21:21:13.863 [ERROR] [com.diffplug.spotless.Formatter] Step 'eclipse formatter' found problem in 'src/main/java/com/[...]/config/schema/[FieldSchema.java](https://github.com/diffplug/spotless/files/1650522/FieldSchema.txt)
    ':
    null
    
    java.lang.reflect.InvocationTargetException
            at com.diffplug.spotless.extra.java.EclipseFormatterStep$State.lambda$createFormat$0(EclipseFormatterStep.java:100)
            at com.diffplug.spotless.FormatterStepImpl$Standard.format(FormatterStepImpl.java:78)
            at com.diffplug.spotless.FormatterStep$Strict.format(FormatterStep.java:76)
            at com.diffplug.spotless.Formatter.compute(Formatter.java:230)
            at com.diffplug.spotless.Formatter.isClean(Formatter.java:167)
            at com.diffplug.gradle.spotless.SpotlessTask.check(SpotlessTask.java:263)
            at com.diffplug.gradle.spotless.SpotlessTask.performAction(SpotlessTask.java:205)
            at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
            at org.gradle.api.internal.project.taskfactory.IncrementalTaskAction.doExecute(IncrementalTaskAction.java:46)
            at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:39)
            at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:26)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:121)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
            at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
            at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
            at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
            at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:60)
            at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
            at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
            at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
            at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
            at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
            at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
            at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
            at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
            at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
            at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
            at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:626)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:581)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
            at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
            at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
            at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    Caused by: java.lang.IllegalStateException: Workspace is closed.
            at org.eclipse.core.resources.ResourcesPlugin.getWorkspace(ResourcesPlugin.java:412)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.createParser(DefaultCodeFormatter.java:332)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.parseSourceCode(DefaultCodeFormatter.java:317)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareFormattedCode(DefaultCodeFormatter.java:213)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareFormattedCode(DefaultCodeFormatter.java:206)
            at org.eclipse.jdt.internal.formatter.CommentsPreparator.formatCode(CommentsPreparator.java:1063)
            at org.eclipse.jdt.internal.formatter.CommentsPreparator.handleFormatCodeTag(CommentsPreparator.java:801)
            at org.eclipse.jdt.internal.formatter.CommentsPreparator.handleHtml(CommentsPreparator.java:665)
            at org.eclipse.jdt.internal.formatter.CommentsPreparator.endVisit(CommentsPreparator.java:621)
            at org.eclipse.jdt.core.dom.TagElement.accept0(TagElement.java:282)
            at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2796)
            at org.eclipse.jdt.core.dom.ASTNode.acceptChildren(ASTNode.java:2867)
            at org.eclipse.jdt.core.dom.Javadoc.accept0(Javadoc.java:205)
            at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2796)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareComments(DefaultCodeFormatter.java:399)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareFormattedCode(DefaultCodeFormatter.java:222)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.format(DefaultCodeFormatter.java:177)
            at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.format(DefaultCodeFormatter.java:160)
            at com.diffplug.gradle.spotless.java.eclipse.EclipseFormatterStepImpl.format(EclipseFormatterStepImpl.java:38)
            ... 47 more
    
    bug question 
    opened by d1ss0nanz 29
  • fix(deps): update ver_ktlint to v0.48.1

    fix(deps): update ver_ktlint to v0.48.1

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | com.pinterest.ktlint:ktlint-ruleset-standard | 0.46.1 -> 0.48.1 | age | adoption | passing | confidence | | com.pinterest.ktlint:ktlint-ruleset-experimental | 0.46.1 -> 0.48.1 | age | adoption | passing | confidence | | com.pinterest.ktlint:ktlint-core | 0.46.1 -> 0.48.1 | age | adoption | passing | confidence | | com.pinterest:ktlint | 0.46.1 -> 0.48.1 | age | adoption | passing | confidence |


    ⚠ Dependency Lookup Warnings ⚠

    Warnings were logged while processing this repo. Please check the Dependency Dashboard for more information.


    Release Notes

    pinterest/ktlint

    v0.48.1

    Compare Source

    Added
    Removed
    Fixed
    • An enumeration class having a primary constructor and in which the list of enum entries is followed by a semicolon then do not remove the semicolon in case it is followed by code element no-semi (#​1733)
    • Add API so that KtLint API consumer is able to process a Kotlin script snippet without having to specify a file path (#​1738)
    • Disable the standard:filename rule whenever Ktlint CLI is run with option --stdin (#​1742)
    • Fix initialization of the logger when --log-level is specified. Throw exception when an invalid value is passed. (#​1749)
    • Fix loading of custom rule set JARs.
    • Rules provided via a custom rule set JAR (Ktlint CLI) or by an API provider are enabled by default. Only rules in the experimental rule set are disabled by default. (#​1747)
    Changed
    • Update Kotlin development version to 1.8.0 and Kotlin version to 1.8.0.

    v0.48.0

    Compare Source

    Indent rule

    The indent rule has been rewritten from scratch. Solving problems in the old algorithm was very difficult. With the new algorithm this becomes a lot easier. Although the new implementation of the rule has been compared against several open source projects containing over 400,000 lines of code, it is still likely that new issues will be discovered. Please report your indentation issues so that these can be fixed as well.

    .editorconfig property to disable rules

    In the previous release (0.47.x), the .editorconfig property disabled_rules was deprecated and replaced with ktlint_disabled_rules. This latter property has now been deprecated as well in favour of a more flexible and better maintainable solution. Rule and rule sets can now be enabled/disabled with a separate property per rule (set). Please read deprecation of (ktlint_)disable_rules property for more information.

    The KtLint CLI has not been changed. Although you can still use parameter --experimental to enable KtLint's Experimental rule set, you might want to set .editorconfig property ktlint_experimental = enabled instead.

    API Changes & RuleSet providers

    If you are not an API consumer or Rule Set provider then you can skip this section.

    Class relocations

    Classes below have been relocated:

    • Class com.pinterest.ktlint.core.api.UsesEditorConfigProperties.EditorConfigProperty has been replaced with com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty.
    • Class com.pinterest.ktlint.core.KtLintParseException has been replaced with com.pinterest.ktlint.core.api.KtLintParseException.
    • Class com.pinterest.ktlint.core.RuleExecutionException has been replaced with com.pinterest.ktlint.core.api.KtLintRuleException.
    • Class com.pinterest.ktlint.reporter.format.internal.Color has been moved to com.pinterest.ktlint.reporter.format.Color.
    • Class com.pinterest.ktlint.reporter.plain.internal.Color has been moved to com.pinterest.ktlint.reporter.plain.Color.
    Invoking lint and format

    This is the last release that supports the ExperimentalParams to invoke the lint and format functions of KtLint. The ExperimentalParams contains a mix of configuration settings which are not dependent on the file/code which is to be processed. Other parameters in that class describe the code/file to be processed but can be configured inconsistently (for example a file with name "foo.kt" could be marked as a Kotlin Script file).

    The static object KtLint is deprecated and replaced by class KtLintRuleEngine which is configured with KtLintRuleEngineConfiguration. The instance of the KtLintRuleEngine is intended to be reused for scanning all files in a project and should not be recreated per file.

    Both lint and format are simplified and can now be called for a code block or for an entire file.

    import java.io.File
    
    // Define a reusable instance of the KtLint Rule Engine
    val ktLintRuleEngine = KtLintRuleEngine(
      // Define configuration
    )
    
    // Process a collection of files
    val files: Set<File> // Collect files in a convenient way
    files.forEach(file in files) {
        ktLintRuleEngine.lint(file) {
            // Handle lint violations
        }
    }
    
    // or process a code sample for a given filepath
    ktLintRuleEngine.lint(
      code = "code to be linted",
      filePath = Path("/path/to/source/file")
    ) {
      // Handle lint violations
    }
    
    Retrieve .editorconfigs

    The list of .editorconfig files which will be accessed by KtLint when linting or formatting a given path can now be retrieved with the new API KtLint.editorConfigFilePaths(path: Path): List<Path>.

    This API can be called with either a file or a directory. It's intended usage is that it is called once with the root directory of a project before actually linting or formatting files of that project. When called with a directory path, all .editorconfig files in the directory or any of its subdirectories (except hidden directories) are returned. In case the given directory does not contain an .editorconfig file or if it does not contain the root=true setting, the parent directories are scanned as well until a root .editorconfig file is found.

    Calling this API with a file path results in the .editorconfig files that will be accessed when processing that specific file. In case the directory in which the file resides does not contain an .editorconfig file or if it does not contain the root=true setting, the parent directories are scanned until a root .editorconfig file is found.

    Psi filename replaces FILE_PATH_USER_DATA_KEY

    Constant KtLint.FILE_PATH_USER_DATA_KEY is deprecated and will be removed in KtLint version 0.49.0. The file name will be passed correctly to the node with element type FILE and can be retrieved as follows:

    if (node.isRoot()) {
        val fileName = (node.psi as? KtFile)?.name
        ...
    }
    
    Added
    • Wrap blocks in case the max line length is exceeded or in case the block contains a new line wrapping (#​1643)
    • patterns can be read in from stdin with the --patterns-from-stdin command line options/flags (#​1606)
    • Add basic formatting for context receiver in indent rule and new experimental rule context-receiver-wrapping (#​1672)
    • Add naming rules for classes and objects (class-naming), functions (function-naming) and properties (property-naming) (#​44)
    • Add new built-in reporter plain-summary which prints a summary the number of violation which have been autocorrected or could not be autocorrected, both split by rule.
    Fixed
    • Let a rule process all nodes even in case the rule is suppressed for a node so that the rule can update the internal state (#​1644)
    • Read .editorconfig when running CLI with options --stdin and --editorconfig (#​1651)
    • Do not add a trailing comma in case a multiline function call argument is found but no newline between the arguments trailing-comma-on-call-site (#​1642)
    • Add missing ktlint_disabled_rules to exposed editorConfigProperties (#​1671)
    • Do not add a second trailing comma, if the original trailing comma is followed by a KDOC trailing-comma-on-declaration-site and trailing-comma-on-call-site (#​1676)
    • A function signature preceded by an annotation array should be handled similar as function preceded by a singular annotation function-signature (#​1690)
    • Fix offset of annotation violations
    • Fix line offset when blank line found between class and primary constructor
    • Remove needless blank line between class followed by EOL, and primary constructor
    • Fix offset of unexpected linebreak before assignment
    • Remove whitespace before redundant semicolon if the semicolon is followed by whitespace
    Changed
    • Update Kotlin development version to 1.8.0-RC and Kotlin version to 1.7.21.
    • The default value for trailing comma's on call site is changed to true unless the android codestyle is enabled. Note that KtLint from a consistency viewpoint enforces the trailing comma on call site while default IntelliJ IDEA formatting only allows the trailing comma but leaves it up to the developer's discretion. (#​1670)
    • The default value for trailing comma's on declaration site is changed to true unless the android codestyle is enabled. Note that KtLint from a consistency viewpoint enforces the trailing comma on declaration site while default IntelliJ IDEA formatting only allows the trailing comma but leaves it up to the developer's discretion. (#​1669)
    • CLI options --debug, --trace, --verbose and -v are replaced with --log-level=<level> or the short version `-l=, see CLI log-level. (#​1632)
    • In CLI, disable logging entirely by setting --log-level=none or -l=none (#​1652)
    • Rewrite indent rule. Solving problems in the old algorithm was very difficult. With the new algorithm this becomes a lot easier. Although the new implementation of the rule has been compared against several open source projects containing over 400,000 lines of code, it is still likely that new issues will be discovered. Please report your indentation issues so that these can be fixed as well. (#​1682, #​1321, #​1200, #​1562, #​1563, #​1639)
    • Add methods "ASTNode.upsertWhitespaceBeforeMe" and "ASTNode.upsertWhitespaceAfterMe" as replacements for "LeafElement.upsertWhitespaceBeforeMe" and "LeafElement.upsertWhitespaceAfterMe". The new methods are more versatile and allow code to be written more readable in most places. (#​1687)
    • Rewrite indent rule. Solving problems in the old algorithm was very difficult. With the new algorithm this becomes a lot easier. Although the new implementation of the rule has been compared against several open source projects containing over 400,000 lines of code, it is still likely that new issues will be discovered. Please report your indentation issues so that these can be fixed as well. (#​1682, #​1321, #​1200, #​1562, #​1563, #​1639, #​1688)
    • Add support for running tests on java 19, remove support for running tests on java 18.
    • Update io.github.detekt.sarif4k:sarif4k version to 0.2.0 (#​1701).

    v0.47.1

    Compare Source

    Fixed
    • Do not add trailing comma in empty parameter/argument list with comments (trailing-comma-on-call-site, trailing-comma-on-declaration-site) (#​1602)
    • Fix class cast exception when specifying a non-string editorconfig setting in the default ".editorconfig" (#​1627)
    • Fix indentation before semi-colon when it is pushed down after inserting a trailing comma (#​1609)
    • Do not show deprecation warning about property "disabled_rules" when using CLi-parameter --disabled-rules (#​1599)
    • Traversing directory hierarchy at Windows (#​1600)
    • Ant-style path pattern support (#​1601)
    • Apply @file:Suppress on all toplevel declarations (#​1623)
    Changed
    • Display warning instead of error when no files are matched, and return with exit code 0. (#​1624)

    v0.47.0

    Compare Source

    API Changes & RuleSet providers

    If you are not an API consumer nor a RuleSet provider, then you can safely skip this section. Otherwise, please read below carefully and upgrade your usage of ktlint. In this and coming releases, we are changing and adapting important parts of our API in order to increase maintainability and flexibility for future changes. Please avoid skipping a releases as that will make it harder to migrate.

    Rule lifecycle hooks / deprecate RunOnRootOnly visitor modifier

    Up until ktlint 0.46 the Rule class provided only one life cycle hook. This "visit" hook was called in a depth-first-approach on all nodes in the file. A rule like the IndentationRule used the RunOnRootOnly visitor modifier to call this lifecycle hook for the root node only in combination with an alternative way of traversing the ASTNodes. Downside of this approach was that suppression of the rule on blocks inside a file was not possible (#​631). More generically, this applied to all rules, applying alternative traversals of the AST.

    The Rule class now offers new life cycle hooks:

    • beforeFirstNode: This method is called once before the first node is visited. It can be used to initialize the state of the rule before processing of nodes starts. The ".editorconfig" properties (including overrides) are provided as parameter.
    • beforeVisitChildNodes: This method is called on a node in AST before visiting its child nodes. This is repeated recursively for the child nodes resulting in a depth first traversal of the AST. This method is the equivalent of the "visit" life cycle hooks. However, note that in KtLint 0.48, the UserData of the rootnode no longer provides access to the ".editorconfig" properties. This method can be used to emit Lint Violations and to autocorrect if applicable.
    • afterVisitChildNodes: This method is called on a node in AST after all its child nodes have been visited. This method can be used to emit Lint Violations and to autocorrect if applicable.
    • afterLastNode: This method is called once after the last node in the AST is visited. It can be used for teardown of the state of the rule.

    Optionally, a rule can stop the traversal of the remainder of the AST whenever the goal of the rule has been achieved. See KDoc on Rule class for more information.

    The "visit" life cycle hook will be removed in Ktlint 0.48. In KtLint 0.47 the "visit" life cycle hook will be called only when hook "beforeVisitChildNodes" is not overridden. It is recommended to migrate to the new lifecycle hooks in KtLint 0.47. Please create an issue, in case you need additional assistence to implement the new life cycle hooks in your rules.

    Ruleset providing by Custom Rule Set Provider

    The KtLint engine needs a more fine-grained control on the instantiation of new Rule instances. Currently, a new instance of a rule can be created only once per file. However, when formatting files the same rule instance is reused for a second processing iteration in case a Lint violation has been autocorrected. By re-using the same rule instance, state of that rule might leak from the first to the second processing iteration.

    Providers of custom rule sets have to migrate the custom rule set JAR file. The current RuleSetProvider interface which is implemented in the custom rule set is deprecated and marked for removal in KtLint 0.48. Custom rule sets using the old RuleSetProvider interface will not be run in KtLint 0.48 or above.

    For now, it is advised to implement the new RuleSetProviderV2 interface without removing the old RuleSetProvider interface. In this way, KtLint 0.47 and above use the RuleSetProviderV2 interface and ignore the old RuleSetProvider interface completely. KtLint 0.46 and below only use the old RuleSetProvider interface.

    Adding the new interface is straight forward, as can be seen below:

    // Current implementation
    public class CustomRuleSetProvider : RuleSetProvider {
        override fun get(): RuleSet = RuleSet(
            "custom",
            CustomRule1(),
            CustomRule2(),
        )
    }
    
    // New implementation
    public class CustomRuleSetProvider :
        RuleSetProviderV2(CUSTOM_RULE_SET_ID),
        RuleSetProvider {
        override fun get(): RuleSet =
            RuleSet(
                CUSTOM_RULE_SET_ID,
                CustomRule1(),
                CustomRule2()
            )
    
        override fun getRuleProviders(): Set<RuleProvider> =
            setOf(
                RuleProvider { CustomRule1() },
                RuleProvider { CustomRule2() }
            )
    
        private companion object {
            const val CUSTOM_RULE_SET_ID = custom"
        }
    }
    
    

    Also note that file 'resource/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2' needs to be added. In case your custom rule set provider implements both RuleSetProvider and RuleSetProviderV2, the resource directory contains files for both implementation. The content of those files is identical as the interfaces are implemented on the same class.

    Once above has been implemented, rules no longer have to clean up their internal state as the KtLint rule engine can request a new instance of the Rule at any time it suspects that the internal state of the Rule is tampered with (e.g. as soon as the Rule instance is used for traversing the AST).

    Rule set providing by API Consumer

    The KtLint engine needs a more fine-grained control on the instantiation of new Rule instances. Currently, a new instance of a rule can be created only once per file. However, when formatting files the same rule instance is reused for a second processing iteration in case a Lint violation has been autocorrected. By re-using the same rule instance, state of that rule might leak from the first to the second processing iteration.

    The ExperimentalParams parameter which is used to invoke "KtLint.lint" and "KtLint.format" contains a new parameter "ruleProviders" which will replace the "ruleSets" parameter in KtLint 0.48. Exactly one of those parameters should be a non-empty set. It is preferred that API consumers migrate to using "ruleProviders".

    // Old style using "ruleSets"
    KtLint.format(
        KtLint.ExperimentalParams(
            ...
            ruleSets = listOf(
                RuleSet(
                    "custom",
                    CustomRule1(),
                    CustomRule2()
                )
            ),
            ...
        )
    )
    
    // New style using "ruleProviders"
    KtLint.format(
        KtLint.ExperimentalParams(
            ...
            ruleProviders = setOf(
                RuleProvider { CustomRule1() },
                RuleProvider { CustomRule2() }
            ),
            cb = { _, _ -> }
        )
    )
    

    Once above has been implemented, rules no longer have to clean up their internal state as the KtLint rule engine can request a new instance of the Rule at any time it suspects that the internal state of the Rule is tampered with (e.g. as soon as the Rule instance is used for traversing the AST).

    Format callback

    The callback function provided as parameter to the format function is now called for all errors regardless whether the error has been autocorrected. Existing consumers of the format function should now explicitly check the autocorrected flag in the callback result and handle it appropriately (in most case this will be ignoring the callback results for which autocorrected has value true).

    CurrentBaseline

    Class com.pinterest.ktlint.core.internal.CurrentBaseline has been replaced with com.pinterest.ktlint.core.api.Baseline.

    Noteworthy changes:

    • Field baselineRules (nullable) is replaced with `lintErrorsPerFile (non-nullable).
    • Field baselineGenerationNeeded (boolean) is replaced with status (type Baseline.Status).

    The utility functions provided via com.pinterest.ktlint.core.internal.CurrentBaseline are moved to the new class. One new method List<LintError>.doesNotContain(lintError: LintError) is added.

    .editorconfig property "disabled_rules"

    The .editorconfig property disabled_rules (api property DefaultEditorConfigProperties.disabledRulesProperty) has been deprecated and will be removed in a future version. Use ktlint_disabled_rules (api property DefaultEditorConfigProperties.ktlintDisabledRulesProperty) instead as it more clearly identifies that ktlint is the owner of the property. This property is to be renamed in .editorconfig files and ExperimentalParams.editorConfigOverride.

    Although, Ktlint 0.47.0 falls back on property disabled_rules whenever ktlint_disabled_rules is not found, this result in a warning message being printed.

    Default/alternative .editorconfig

    Parameter "ExperimentalParams.editorConfigPath" is deprecated in favor of the new parameter "ExperimentalParams.editorConfigDefaults". When used in the old implementation this resulted in ignoring all ".editorconfig" files on the path to the file. The new implementation uses properties from the "editorConfigDefaults"parameter only when no ".editorconfig" files on the path to the file supplies this property for the filepath.

    API consumers can easily create the EditConfigDefaults by calling "EditConfigDefaults.load(path)" or creating it programmatically.

    Reload of .editorconfig file

    Some API Consumers keep a long-running instance of the KtLint engine alive. In case an .editorconfig file is changed, which was already loaded into the internal cache of the KtLint engine this change would not be taken into account by KtLint. One way to deal with this, was to clear the entire KtLint cache after each change in an .editorconfig file.

    Now, the API consumer can reload an .editorconfig. If the .editorconfig with given path is actually found in the cached, it will be replaced with the new value directly. If the file is not yet loaded in the cache, loading will be deferred until the file is actually requested again.

    Example:

    KtLint.reloadEditorConfigFile("/some/path/to/.editorconfig")
    
    Miscellaneous

    Several methods for which it is unlikely that they are used by API consumers have been marked for removal from the public API in KtLint 0.48.0. Please create an issue in case you have a valid business case to keep such methods in the public API.

    Added
    • Add format reporter. This reporter prints a one-line-summary of the formatting status per file. (#​621).
    Fixed
    • Fix cli argument "--disabled_rules" (#​1520).
    • A file which contains a single top level declaration of type function does not need to be named after the function but only needs to adhere to the PascalCase convention. filename (#​1521).
    • Disable/enable IndentationRule on blocks in middle of file. (indent) #​631
    • Allow usage of letters with diacritics in enum values and filenames (enum-entry-name-case, filename) (#​1530).
    • Fix resolving of Java version when JAVA_TOOL_OPTIONS is set (#​1543)
    • When a glob is specified then ensure that it matches files in the current directory and not only in subdirectories of the current directory (#​1533).
    • Execute ktlint cli on default kotlin extensions only when an (existing) path to a directory is given. (#​917).
    • Invoke callback on format function for all errors including errors that are autocorrected (#​1491)
    • Merge first line of body expression with function signature only when it fits on the same line function-signature (#​1527)
    • Add missing whitespace when else is on same line as true condition multiline-if-else (#​1560)
    • Fix multiline if-statements multiline-if-else (#​828)
    • Prevent class cast exception on ".editorconfig" property ktlint_code_style (#​1559)
    • Handle trailing comma in enums trailing-comma (#​1542)
    • Allow EOL comment after annotation (#​1539)
    • Split rule trailing-comma into trailing-comma-on-call-site and trailing-comma-on-declaration-site (#​1555)
    • Support globs containing directories in the ".editorconfig" supplied via CLI "--editorconfig" (#​1551)
    • Fix indent of when entry with a dot qualified expression instead of simple value when trailing comma is required (#​1519)
    • Fix whitespace between trailing comma and arrow in when entry when trailing comma is required (#​1519)
    • Prevent false positive in parameter list for which the last value parameter is a destructuring declaration followed by a trailing comma wrapping (#​1578)
    Changed
    • Print an error message and return with non-zero exit code when no files are found that match with the globs (#​629).
    • Invoke callback on format function for all errors including errors that are autocorrected (#​1491)
    • Improve rule annotation (#​1574)
    • Rename .editorconfig property disabled_rules to ktlint_disabled_rules (#​701)
    • Allow file and directory paths in CLI-parameter "--editorconfig" (#​1580)
    • Update Kotlin development version to 1.7.20-beta and Kotlin version to 1.7.10.
    • Update release scripting to set version number in mkdocs documentation (#​1575).
    • Update Gradle to 7.5.1 version
    Removed
    • Remove support to generate IntelliJ IDEA configuration files as this no longer fits the scope of the ktlint project (#​701)

    Configuration

    📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about these updates again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    opened by renovate[bot] 0
  • Enable json in maven plugin

    Enable json in maven plugin

    Following https://github.com/diffplug/spotless/issues/1445


    Please DO NOT FORCE PUSH. Don't worry about messy history, it's easier to do code review if we can tell what happened after the review, and force pushing breaks that.

    Please make sure that your PR allows edits from maintainers. Sometimes its faster for us to just fix something than it is to describe how to fix it.

    Allow edits from maintainers

    After creating the PR, please add a commit that adds a bullet-point under the [Unreleased] section of CHANGES.md, plugin-gradle/CHANGES.md, and plugin-maven/CHANGES.md which includes:

    • [ ] a summary of the change
    • either
      • [ ] a link to the issue you are resolving (for small changes)
      • [ ] a link to the PR you just created (for big changes likely to have discussion)

    If your change only affects a build plugin, and not the lib, then you only need to update the plugin-foo/CHANGES.md for that plugin.

    If your change affects lib in an end-user-visible way (fixing a bug, updating a version) then you need to update CHANGES.md for both the lib and all build plugins. Users of a build plugin shouldn't have to refer to lib to see changes that affect them.

    This makes it easier for the maintainers to quickly release your changes :)

    opened by blacelle 1
  • JSON Formatting in mvn plugin

    JSON Formatting in mvn plugin

    The maven plugin seems not to support JSON formatting. Is there a good reason for this? Or would it be considered a good contribution from a new-comer ?

    enhancement 
    opened by blacelle 5
  • Support new way to disable rules in ktlint 0.48

    Support new way to disable rules in ktlint 0.48

    • [ 6.12.1 ] spotless version

    Currently, using the ktlint_disabled_rules causes many warnings to be printed in the console:

    Property 'ktlint_disabled_rules' is deprecated: Update all your all '.editorconfig' files. See [link below]
    

    https://pinterest.github.io/ktlint/faq/#why-is-editorconfig-property-disabled_rules-deprecated-and-how-do-i-resolve-this

    Following that, if I configure Spotless as below, the config is ignored and rules are still enabled.

    configure<com.diffplug.gradle.spotless.SpotlessExtension> {
        kotlin {
            ktlint("0.48.0")
                .editorConfigOverride(
                    mapOf(
                        "ktlint_standard_filename" to "disabled",
                    ),
                )
        }
    }
    
    opened by bcmedeiros 2
  • Support for skipping lines before license header

    Support for skipping lines before license header

    This PR proposes a solution for supporting license headers on files where the header cannot be added immediately to the top of the file because of the format's restrictions. Examples are XML (<?xml version="1.0" ...) or shell scripts (#!/bin/bash).

    The change simply allows configuring a regex for the LicenseHeaderStep. All the lines at the beginning of the file that match this regex will be skipped, and written directly to the output, then the rest of the lines will be processed the same way as before.

    An example configuration would be something like:

    format "licenseHeaderSh", {
      target "**/*.sh"
      licenseHeaderFile(file("$rootDir/config/license/sh.txt"), "^(?!##).+")
        .skipLinesPattern("^#!.+?$")
    }
    

    This PR contains a working proof of concept, but lacks the following:

    • New test cases
    • Maven support
    • Change log updates

    I'll add these if the concept is accepted.

    Related issues: #496

    opened by abelk2 0
Owner
DiffPlug
View, edit, compare. Anything, from anywhere.
DiffPlug
A Kotlin Android library for heuristics evasion that prevents your code from being tested.

EvadeMe An Android library for heuristics evasion that prevents your code from being tested. User Instructions Add the maven repository to your projec

Chris Basinger 29 Dec 26, 2022
KaMP Kit by Touchlab is a collection of code and tools designed to get your mobile team started quickly with Kotlin Multiplatform.

KaMP Kit Welcome to the KaMP Kit! About Goal The goal of the KaMP Kit is to facilitate your evaluation of Kotlin Multiplatform (aka KMP). It is a coll

Touchlab 1.7k Jan 3, 2023
Ratio + don't care, in your kotlin code

Ratio + don't care, in your kotlin code

Emma Böcker 7 Jul 1, 2022
This program will read from your android application string.xml file and generate translated strings.xml files in your preferred languages using google sheet.

Localize your application content This program will read from your application string.xml file and generate translated strings.xml files in your prefe

DhiWise 4 Jul 29, 2022
Display code with syntax highlighting :sparkles: in native way.

CodeView (Android) CodeView helps to show code content with syntax highlighting in native way. Description CodeView contains 3 core parts to implement

Kirill Biakov 827 Dec 22, 2022
:bouquet: An easy way to persist and run code block only as many times as necessary on Android.

Only ?? An easy way to persist and run code block only as many times as necessary on Android. Download Gradle Add below codes to your root build.gradl

Jaewoong Eum 479 Dec 25, 2022
:bouquet: An easy way to persist and run code block only as many times as necessary on Android.

Only ?? An easy way to persist and run code block only as many times as necessary on Android. Download Gradle Add below codes to your root build.gradl

Jaewoong Eum 468 Apr 14, 2021
An Awesome Kotlin Location library to retrieve location merely in 3 lines of code

An Awesome Kotlin Location library to retrieve location merely in 3 lines of code

Birju Vachhani 288 Dec 30, 2022
Clean Code and Reactive Programming PlayGround for Bangkit 2021

Clean Code and Reactive Programming PlayGround for Bangkit 2021 Hello! This repo contains the IntelliJ project that I use to present my talk, "Clean A

raditya gumay 3 May 16, 2021
Library to use Kotlin Coroutines from Swift code in KMP apps

KMP-NativeCoroutines A library to use Kotlin Coroutines from Swift code in KMP apps. Flows Kotlin Create an extension property to expose the Flow as a

Rick Clephas 508 Jan 3, 2023
JavaScript evaluation from kotlin common code for android & iOS

Mobile Kotlin javascript This is a Kotlin MultiPlatform library that allows you to run JavaScript code from common Kotlin code Table of Contents Featu

IceRock Development 14 Aug 29, 2022
Code generation of Kotlin DSL for AWS CDK

Code generation of Kotlin DSL for AWS CDK

Semantic Configuration 5 Dec 24, 2022
👋 A common toolkit (utils) ⚒️ built to help you further reduce Kotlin boilerplate code and improve development efficiency. Do you think 'kotlin-stdlib' or 'android-ktx' is not sweet enough? You need this! 🍭

Toolkit [ ?? Work in progress ⛏ ?? ??️ ?? ] Snapshot version: repositories { maven("https://s01.oss.sonatype.org/content/repositories/snapshots") }

凛 35 Jul 23, 2022
Pragmateam code challenge server (Kotlin)

Pragmateam code challenge server (Kotlin) Please refer to the provided document for the code challenge requirements. Framework & languages This projec

Pragmateam 0 Nov 9, 2021
This repository contains the source code for the PokeApi Android app.

PokeApi App This repository contains the source code for the PokeApi Android app.

Nilton Huamaní Carlos 0 Nov 4, 2021
Android application showcasing the MVVM architecture, Clean code using Kotlin, Coroutine, Flow and databinding.

Code4Lyst Android application showcasing the MVVM architecture, Clean code using Kotlin, Coroutine, Flow and databinding. App Architecture MVVM CleanC

Plabon Modak 1 Nov 29, 2021
The source code for SuCraft.

SuCraft What is this? This repository contains the source code for SuCraft. You can help in three ways: If there is a bug on the server, please report

SuCraft 8 Dec 17, 2022
Sample Code for fake Kotlin library written in Java

Jatlin このリポジトリは ブログ記事 のためのサンプルコードです。詳細は記事をご覧ください。 プロジェクト構成 :java-lib にKotlinに偽装したJavaファイルが含まれます。 :kotlin-lib は :java-lib をビルドしたJARファイルをKotlinから読み込んで実行

Takaki Hoshikawa 3 Dec 10, 2021
Muhammad Bilal 0 Jan 6, 2022