Spotless Code Formatting Tool

repository·main·Indexed 26 days ago

https://github.com/diffplug/spotless

Spotless is a general-purpose code formatting tool that integrates with build systems such as Gradle, Maven, and SBT to ensure code consistency. It supports a wide array of languages including Java, Kotlin, Groovy, C/C++, and Python. Key features include incremental builds, remote/local build caches, and the ability to check or automatically apply formatting via tasks like `spotlessCheck` and `spotlessApply`. It integrates with various formatters such as google-java-format, ktlint, Black, and Eclipse JDT.

Tokens
35K
Snippets
115
Records
146
Agent score
87%

What's inside Spotless

  1. Overview of Spotless

    main

    Spotless is a general-purpose code formatting plugin that can format a wide variety of languages and file types, including but not limited to:

    • Languages: antlr, c, c#, c++, css, flow, graphql, groovy, html, java, javascript, json, jsx, kotlin, less, markdown, objective-c, protobuf, python, scala, scss, shell, sql, typeScript, vue, yaml.
    • Other: license headers, and anything else supported by the underlying formatters.

    It integrates with major build systems like Gradle, Maven, and SBT to check for formatting violations and automatically apply fixes.

  2. Understand how Spotless formatting works

    main

    Spotless operates by applying a sequence of formatting steps to your files. Each step is a function that takes a String as input and returns a String as output.

    • spotlessApply: Reads a file, applies all configured steps sequentially, and writes the resulting output back to the disk.
    • spotlessCheck: Reads a file, applies all configured steps sequentially, and compares the final output to the original input. If they are not identical, the check fails, indicating the file is incorrectly formatted and needs spotlessApply to be run.
  3. Quickstart Spotless for Gradle

    main

    Spotless is a general-purpose formatting plugin for Gradle that allows you to check and apply code formatting. It supports incremental builds, remote/local build caches, and lazy configuration.

    To use Spotless, you typically run two main tasks:

    1. ./gradlew spotlessCheck: Verifies if files follow the defined formatting rules. If violations are found, the build fails.
    2. ./gradlew spotlessApply: Automatically fixes the formatting violations in your files.

    Example workflow:

    # Check for violations
    ./gradlew build
    # If spotlessJavaCheck fails, run:
    ./gradlew spotlessApply
    # Now the build will pass
    ./gradlew build
    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
  4. Quickstart Spotless for Gradle

    main

    To use Spotless in your Gradle project, add the Spotless dependency and configure the spotless block in your build script. You can define multiple formats (e.g., misc, java), each with its own target files and a list of FormatterStep functions to apply.

    Key features:

    • ratchetFrom 'origin/main': Limits format enforcement to only files changed relative to a specific branch.
    • target: Defines the files to apply the format to.
    • targetExclude: Defines files to exclude from the format.
    • FormatterStep: Functions like trimTrailingWhitespace(), leadingSpacesToTabs(), endWithNewline(), replace(), and licenseHeader() that transform the code.
    spotless {
      // optional: limit format enforcement to just the files changed by this feature branch
      ratchetFrom 'origin/main'
    
      format 'misc', {
        // define the files to apply `misc` to
        target '*.gradle', '.gitattributes', '.gitignore'
    
        // define the steps to apply to those files
        trimTrailingWhitespace()
        leadingSpacesToTabs() // or leadingTabsToSpaces. Takes an integer argument if you don't like 4
        endWithNewline()
      }
      java {
        // don't need to set target, it is inferred from java
    
        // apply a specific flavor of google-java-format
        googleJavaFormat('1.8').aosp().reflowLongStrings().skipJavadocFormatting()
        // fix formatting of type annotations
        formatAnnotations()
        // make sure every file has the following copyright header.
        licenseHeader '/* (C)$YEAR */'
      }
    }
  5. Enforce formatting gradually using ratchet

    main

    To avoid massive commits when introducing Spotless to a legacy project, use the ratchetFrom feature. This ensures Spotless only formats files that have changed since a specific reference point.

    Usage:

    • ratchetFrom 'origin/main': Only formats files changed since the origin/main branch.
    • You can set ratchetFrom globally or per-format (e.g., java { ratchetFrom '...' }).

    Best Practices:

    • Use a non-local branch (like a tag or origin/main) rather than HEAD. Using HEAD can make incorrect formatting the new canonical state immediately upon commit.
    • CI Note: If using shallow clones in CI (GitHub/GitLab), you must run git fetch origin main before Spotless to avoid No such reference errors.
    spotless {
      ratchetFrom 'origin/main'
    }
  6. Use stdin and stdout for Spotless IDE integration

    main

    For advanced IDE integration (such as formatting unsaved editor buffers), you can use the following flags:

    • -PspotlessIdeHookUseStdIn: Tells Spotless to read the file content from stdin instead of the file system.
    • -PspotlessIdeHookUseStdOut: Tells Spotless to return the formatted content on stdout instead of writing to a file.

    Note: When using UseStdOut, you should also include the --quiet flag to prevent Gradle logging from polluting your stdout stream.

  7. Configure Java formatting in Spotless for Gradle

    main

    Use the spotless { java { ... } } block in your build.gradle to configure Java code style. You can specify import orders, remove unused imports, forbid or expand wildcard imports, and choose a formatter (e.g., googleJavaFormat(), eclipse(), prettier(), clangFormat(), idea(), or palantirJavaFormat()).

    Note on Target Detection: Spotless automatically detects most Java source sets, but for Android or java-gradle-plugin sources, you must manually specify the target path.

    spotless {
      java {
        // Manually specify target for Android or java-gradle-plugin
        target 'src/*/java/**/*.java'
    
        importOrder()
        removeUnusedImports()
        forbidWildcardImports()
        
        googleJavaFormat()
        licenseHeader '/* (C) $YEAR */'
      }
    }
  8. Use Spotless Maven IDE Hook for fast single-file formatting

    main

    The Spotless Maven plugin provides an IDE hook mode designed for fast, single-file formatting. When using this mode, spotless:check is disabled, and spotless:apply targets only the specific file provided. This is significantly faster than a standard invocation because it bypasses the full project scan.

    To use this mode, pass the -DspotlessIdeHook argument with the absolute path to the file you wish to format.

  9. Configure License Headers

    main

    Spotless can manage license headers. It supports dynamic year replacement using $YEAR or $today.year tokens.

    Features:

    • Year Replacement: /* Licensed under Apache-2.0 $YEAR. */ becomes /* Licensed under Apache-2.0 2020. */.
    • Handling Fixed Headers: For files with fixed lines (like shebangs #! or XML declarations), use skipLinesMatching(regex) to define which lines to skip before applying the header.
    • Git History Repair: You can retroactively apply copyright years based on git history by running Gradle with -PspotlessSetLicenseHeaderYearsFromGitHistory=true.