diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..f91f646
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,12 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# Linux start script should use lf
+/gradlew text eol=lf
+
+# These are Windows script files and should use crlf
+*.bat text eol=crlf
+
+# Binary files should be left untouched
+*.jar binary
+
diff --git a/.github/renovate.json5 b/.github/renovate.json5
new file mode 100644
index 0000000..5d85c09
--- /dev/null
+++ b/.github/renovate.json5
@@ -0,0 +1,8 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": [
+ "config:recommended",
+ ],
+ "packageRules": [
+ ]
+}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..995d058
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,180 @@
+---
+name: "ci_checks"
+on:
+ pull_request: null
+ push:
+ branches:
+ - "main"
+ - "initial-version"
+ workflow_dispatch:
+ inputs:
+ force_gradle_cache_clean:
+ description: "Force gradle cache clean"
+ required: false
+ default: "false"
+concurrency:
+ group: "${{ github.workflow }}-${{ github.ref }}"
+ cancel-in-progress: true
+jobs:
+ gradleCheck:
+ name: "run checks using gradlew"
+ runs-on: "ubuntu-latest"
+ outputs:
+ RELEASE_VERSION: ${{ steps.get_version.outputs.VERSION }}
+ env:
+ SEGMENT_DOWNLOAD_TIMEOUT_MINS: "15"
+ steps:
+ - name: "Checkout"
+ uses: "actions/checkout@v4"
+ with:
+ fetch-depth: 0
+ - name: "Install JDK 21"
+ uses: "actions/setup-java@v4"
+ with:
+ distribution: "graalvm"
+ java-version: 21
+ - name: "Install Node.js"
+ uses: actions/setup-node@v4
+ with:
+ node-version: "lts/jod" # 22
+ - name: "debug node"
+ run: "node --version && npm --version"
+ - name: "Setup Gradle"
+ uses: "gradle/actions/setup-gradle@v4"
+ with:
+ cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/initial-version' }} # TODO remove when initial-version is removed
+ - name: "Nuke gradle cache"
+ if: "${{ github.event.inputs.force_gradle_cache_clean == 'true' }}"
+ run: "rm -rf ~/.gradle/caches"
+ - name: "Run check on build-logic subproject"
+ run: "./gradlew :build-logic:check --no-configuration-cache"
+ - name: "Run check on project"
+ run: "./gradlew generateUsage && ./gradlew check"
+ - name: "Get version and set to output"
+ id: get_version
+ run: echo "VERSION=$(./gradlew changelogPrintCurrentVersion --quiet)" >> "$GITHUB_OUTPUT"
+ - name: "junit result"
+ uses: "mikepenz/action-junit-report@v5"
+ if: "always()"
+ with:
+ check_name: "JUnit Report"
+ report_paths: "**/build/test-results/tes*/*.xml" # multiple test tasks
+ nativeCompile:
+ name: "${{ matrix.platform.name }} nativeCompile testing"
+ needs: "gradleCheck"
+ strategy:
+ matrix:
+ platform:
+ - name: "linux-x86_64"
+ runner: "ubuntu-latest"
+ - name: "linux-aarch_64"
+ runner: "ubuntu-24.04-arm"
+ - name: "windows-x86_64"
+ runner: "windows-latest"
+ - name: "osx-aarch_64"
+ runner: "macos-latest"
+ - name: "osx-x86_64"
+ runner: "macos-13"
+ fail-fast: false
+ runs-on: "${{ matrix.platform.runner }}"
+ env:
+ SEGMENT_DOWNLOAD_TIMEOUT_MINS: "15"
+ steps:
+ - name: "Checkout"
+ uses: "actions/checkout@v4"
+ with:
+ fetch-depth: 0
+ - name: "Install JDK 21"
+ uses: "actions/setup-java@v4"
+ with:
+ distribution: "graalvm"
+ java-version: 21
+ - name: "Install Node.js"
+ uses: actions/setup-node@v4
+ with:
+ node-version: "lts/jod" # 22
+ - name: "Setup Gradle"
+ uses: "gradle/actions/setup-gradle@v4"
+ with:
+ cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/initial-version' }} # TODO remove when initial-version is removed
+ - name: "Check if binary works"
+ run: "./gradlew testAllCliNative"
+ - name: "junit result"
+ uses: "mikepenz/action-junit-report@v5"
+ if: "always()"
+ with:
+ check_name: "JUnit Report ${{ matrix.platform.name }}"
+ report_paths: "**/build/test-results/tes*/*.xml" # multiple test tasks
+ - name: "upload binary" # for debugging
+ uses: actions/upload-artifact@v4
+ with:
+ name: "spotless-native-binary--${{ matrix.platform.name }}"
+ path: app/build/native/nativeCompile/spotless*
+ retention-days: 7
+ if-no-files-found: "error"
+
+ dryRunRelease:
+ name: "dry run release"
+ needs: ["gradleCheck", "nativeCompile"]
+ strategy:
+ matrix:
+ platform:
+ - name: "linux-x86_64"
+ runner: "ubuntu-latest"
+ - name: "windows-x86_64"
+ runner: "windows-latest"
+ runs-on: "${{ matrix.platform.runner }}"
+ steps:
+ - name: "Checkout"
+ uses: "actions/checkout@v4"
+ with:
+ fetch-depth: 0
+ - name: "Install JDK 21"
+ uses: "actions/setup-java@v4"
+ with:
+ distribution: "graalvm"
+ java-version: 21
+ - name: "Setup Gradle"
+ uses: "gradle/actions/setup-gradle@v4"
+ - name: "Retrieve binaries"
+ uses: "actions/download-artifact@v4"
+ with:
+ # no name - download all artifacts
+ path: "app/build/collected-binaries"
+ - name: "Prepare release zips for distribution"
+ run: "./gradlew -PreleaseBinariesRootDir=app/build/collected-binaries prepareReleaseBinaryZips"
+ - name: "Prepare jreleaser for distribution"
+ run: "./gradlew prepareJReleaserConfig"
+ - name: "Dry-run choco distribution"
+ if: "${{ matrix.platform.name == 'windows-x86_64' }}"
+ uses: jreleaser/release-action@v2
+ with:
+ setup-java: false
+ arguments: "publish --dry-run"
+ env:
+ JRELEASER_PROJECT_VERSION: ${{ needs.gradleCheck.outputs.RELEASE_VERSION }}
+ JRELEASER_GITHUB_TOKEN: abc # don't provide correct token, just a dry-run
+ JRELEASER_DISTRIBUTIONS_SPOTLESS_CLI_CHOCOLATEY_ACTIVE: ALWAYS
+ JRELEASER_CHOCOLATEY_GITHUB_TOKEN: abc # don't provide correct token, just a dry-run
+ JRELEASER_CHOCOLATEY_USER: abc # don't provide correct token, just a dry-run
+ JRELEASER_CHOCOLATEY_API_KEY: abc # don't provide correct token, just a dry-run
+ - name: "Dry-run brew distribution"
+ if: "${{ matrix.platform.name == 'linux-x86_64' }}"
+ uses: jreleaser/release-action@v2
+ with:
+ setup-java: false
+ arguments: "publish --dry-run"
+ env:
+ JRELEASER_PROJECT_VERSION: ${{ needs.gradleCheck.outputs.RELEASE_VERSION }}
+ JRELEASER_GITHUB_TOKEN: abc # don't provide correct token, just a dry-run
+ JRELEASER_DISTRIBUTIONS_SPOTLESS_CLI_BREW_ACTIVE: ALWAYS
+ JRELEASER_HOMEBREW_GITHUB_TOKEN: abc # don't provide correct token, just a dry-run
+ - name: "Persist jreleaser output"
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: "jreleaser-distribution-dry-run--${{ matrix.platform.name }}"
+ path: |
+ out/jreleaser/trace.log
+ out/jreleaser/output.properties
+ out/jreleaser/package/spotless-cli/**
diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml
new file mode 100644
index 0000000..9de411a
--- /dev/null
+++ b/.github/workflows/gradle-wrapper-validation.yml
@@ -0,0 +1,23 @@
+---
+name: "Validate Gradle Wrapper"
+
+on:
+ workflow_dispatch: null
+ push:
+ paths:
+ - "gradlew"
+ - "gradlew.bat"
+ - "gradle/wrapper/"
+ pull_request:
+ paths:
+ - "gradlew"
+ - "gradlew.bat"
+ - "gradle/wrapper/"
+
+jobs:
+ validation:
+ name: "Validation"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: gradle/actions/wrapper-validation@v4
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..08c82f6
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,162 @@
+---
+name: "publish a release"
+
+on:
+ workflow_dispatch:
+ inputs:
+ force_version:
+ description: "Force version number to publish (empty for automatic semver versioning)"
+ required: false
+ default: ""
+ to_publish: #TODO
+ description: "What to publish"
+ required: true
+ default: "all"
+ type: choice
+ options:
+ - plugin-gradle
+ - plugin-maven
+ - all
+ - lib
+
+permissions:
+ contents: write
+
+concurrency:
+ group: "${{ github.workflow }}-${{ github.ref }}"
+ cancel-in-progress: true
+jobs:
+ nativeCompile:
+ name: "${{ matrix.platform.name }}: create production-binary"
+ strategy:
+ matrix:
+ platform:
+ - name: "linux-x86_64"
+ runner: "ubuntu-latest"
+ - name: "linux-aarch_64"
+ runner: "ubuntu-24.04-arm"
+ - name: "windows-x86_64"
+ runner: "windows-latest"
+ - name: "osx-aarch_64"
+ runner: "macos-latest"
+ - name: "osx-x86_64"
+ runner: "macos-13"
+ runs-on: "${{ matrix.platform.runner }}"
+ env:
+ SEGMENT_DOWNLOAD_TIMEOUT_MINS: "15"
+ steps:
+ - name: "Checkout"
+ uses: "actions/checkout@v4"
+ with:
+ fetch-depth: 0
+ - name: "Install JDK 21"
+ uses: "actions/setup-java@v4"
+ with:
+ distribution: "graalvm"
+ java-version: 21
+ - name: "Install Node.js"
+ uses: actions/setup-node@v4
+ with:
+ node-version: "lts/jod" # 22
+ - name: "Setup Gradle"
+ uses: "gradle/actions/setup-gradle@v4"
+ - name: "Run nativeCompile"
+ run: "./gradlew -Prelease=true nativeCompile"
+ - name: "upload binary" # for collecting later
+ uses: actions/upload-artifact@v4
+ with:
+ name: "spotless-native-binary--${{ matrix.platform.name }}"
+ path: app/build/native/nativeCompile/spotless*
+ retention-days: 3
+ if-no-files-found: "error"
+ createRelease:
+ needs: nativeCompile
+ name: "Create a new release"
+ runs-on: ubuntu-latest
+ outputs:
+ RELEASE_VERSION: ${{ steps.get_version.outputs.VERSION }}
+ env:
+ SEGMENT_DOWNLOAD_TIMEOUT_MINS: "15"
+ steps:
+ - name: "Checkout"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: "Install JDK 21"
+ uses: "actions/setup-java@v4"
+ with:
+ distribution: "graalvm"
+ java-version: 21
+ - name: "Setup Gradle"
+ uses: "gradle/actions/setup-gradle@v4"
+ - name: "Retrieve production-binaries"
+ uses: "actions/download-artifact@v4"
+ with:
+ # no name - download all artifacts
+ path: "app/build/collected-binaries"
+ - name: "Create release"
+ run: "./gradlew -Prelease=true -PreleaseBinariesRootDir=app/build/collected-binaries changelogPush"
+ - name: "Get version and set to output"
+ id: get_version
+ run: echo "VERSION=$(./gradlew changelogPrintCurrentVersion -Prelease=true --quiet)" >> "$GITHUB_OUTPUT"
+ - name: "Prepare jreleaser for distribution"
+ run: "./gradlew prepareJReleaserConfig"
+ - name: "Publish distributions"
+ uses: jreleaser/release-action@v2
+ with:
+ setup-java: false
+ arguments: "publish"
+ env:
+ JRELEASER_PROJECT_VERSION: ${{ steps.get_version.outputs.VERSION }}
+ JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ JRELEASER_HOMEBREW_GITHUB_TOKEN: ${{ secrets.BREW_CHOCO_CLI_GH_TOKEN }}
+ JRELEASER_DISTRIBUTIONS_SPOTLESS_CLI_BREW_ACTIVE: ALWAYS
+ - name: "Persist jreleaser output"
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: jreleaser-release-unix
+ path: |
+ out/jreleaser/trace.log
+ out/jreleaser/output.properties
+ createChocoRelase:
+ needs: createRelease
+ name: "Publish chocolatey package"
+ runs-on: windows-latest
+ env:
+ SEGMENT_DOWNLOAD_TIMEOUT_MINS: "15"
+ steps:
+ - name: "Checkout"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: "Install JDK 21"
+ uses: "actions/setup-java@v4"
+ with:
+ distribution: "graalvm"
+ java-version: 21
+ - name: "Retrieve production-binaries"
+ uses: "actions/download-artifact@v4"
+ with:
+ # no name - download all artifacts
+ path: "app/build/collected-binaries"
+ - name: "Publish distributions"
+ uses: jreleaser/release-action@v2
+ with:
+ setup-java: false
+ arguments: "publish"
+ env:
+ JRELEASER_PROJECT_VERSION: ${{ needs.createRelease.outputs.RELEASE_VERSION }}
+ JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ JRELEASER_CHOCOLATEY_GITHUB_TOKEN: ${{ secrets.BREW_CHOCO_CLI_GH_TOKEN }}
+ JRELEASER_CHOCOLATEY_USER: ${{ secrets.CHOCO_USER }} #manually extracted in jreleaser.yml
+ JRELEASER_CHOCOLATEY_API_KEY: ${{ secrets.CHOCO_API_KEY }}
+ JRELEASER_DISTRIBUTIONS_SPOTLESS_CLI_CHOCOLATEY_ACTIVE: ALWAYS
+ - name: "Persist jreleaser output"
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: jreleaser-release-windows
+ path: |
+ out/jreleaser/trace.log
+ out/jreleaser/output.properties
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2859905
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,175 @@
+# Created by https://www.toptal.com/developers/gitignore/api/java,gradle,intellij
+# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,intellij
+
+### Intellij ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Intellij Patch ###
+# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
+
+# *.iml
+# modules.xml
+# .idea/misc.xml
+# *.ipr
+
+# Sonarlint plugin
+# https://plugins.jetbrains.com/plugin/7973-sonarlint
+.idea/**/sonarlint/
+
+# SonarQube Plugin
+# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
+.idea/**/sonarIssues.xml
+
+# Markdown Navigator plugin
+# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
+.idea/**/markdown-navigator.xml
+.idea/**/markdown-navigator-enh.xml
+.idea/**/markdown-navigator/
+
+# Cache file creation bug
+# See https://youtrack.jetbrains.com/issue/JBR-2257
+.idea/$CACHE_FILE$
+
+# CodeStream plugin
+# https://plugins.jetbrains.com/plugin/12206-codestream
+.idea/codestream.xml
+
+# Azure Toolkit for IntelliJ plugin
+# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
+.idea/**/azureSettings.xml
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
+
+### Gradle ###
+.gradle
+**/build/
+!src/**/build/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Avoid ignore Gradle wrappper properties
+!gradle-wrapper.properties
+
+# Cache of project
+.gradletasknamecache
+
+# Eclipse Gradle plugin generated files
+# Eclipse Core
+.project
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+### Gradle Patch ###
+# Java heap dump
+*.hprof
+
+# End of https://www.toptal.com/developers/gitignore/api/java,gradle,intellij
+
+####### Custom stuff below here #######
+
+# jreleaser
+jreleaser.yml
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..465c268
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/ktfmt.xml b/.idea/ktfmt.xml
new file mode 100644
index 0000000..228bfae
--- /dev/null
+++ b/.idea/ktfmt.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..eee4477
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..e3d2e4b
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/app/spotless-cli.app.main.iml b/.idea/modules/app/spotless-cli.app.main.iml
new file mode 100644
index 0000000..8c0fb26
--- /dev/null
+++ b/.idea/modules/app/spotless-cli.app.main.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/testlib/spotless-cli.testlib.main.iml b/.idea/modules/testlib/spotless-cli.testlib.main.iml
new file mode 100644
index 0000000..a20ef52
--- /dev/null
+++ b/.idea/modules/testlib/spotless-cli.testlib.main.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/testlib/spotless-cli.testlib.test.iml b/.idea/modules/testlib/spotless-cli.testlib.test.iml
new file mode 100644
index 0000000..d3d99d0
--- /dev/null
+++ b/.idea/modules/testlib/spotless-cli.testlib.test.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/palantir-java-format.xml b/.idea/palantir-java-format.xml
new file mode 100644
index 0000000..3815718
--- /dev/null
+++ b/.idea/palantir-java-format.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..332b5da
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,19 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added
+
+- Initial version of the CLI
+- Supported formatters (in alphabetical order):
+ - clang-format
+ - format-annotations
+ - google-java-format
+ - license-header
+ - palantir-java-format
+ - prettier
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..160ea88
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,22 @@
+# Description: A minimal Dockerfile for running/building spotless-cli and tests in a GraalVM environment.
+# --- Stage 1: Build/Install GraalVM ---
+FROM ghcr.io/graalvm/graalvm-community:21.0.2 AS graalvm-builder
+
+# --- Stage 2: Minimal Runtime Image ---
+FROM ubuntu:22.04
+
+# System packages you need at runtime
+RUN apt-get update && \
+ apt-get install -y \
+ libssl-dev \
+ libc6 \
+ npm \
+ && rm -rf /var/lib/apt/lists/*
+
+# Copy GraalVM from the first stage
+COPY --from=graalvm-builder /opt/graalvm-community-java21 /opt/graalvm
+
+# Set up environment
+ENV GRAALVM_HOME=/opt/graalvm
+ENV PATH="${GRAALVM_HOME}/bin:${PATH}"
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..dff5599
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,195 @@
+
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "{}" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ 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.
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..407abcc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,605 @@
+# Spotless Command Line Interface CLI
+
+_Keep your code Spotless from the command line_
+
+
+
+[](CHANGES.md)
+
+[](README.md)
+[](README.md)
+[](README.md)
+
+
+
+> [!NOTE]
+> This project is a work in progress :hourglass_flowing_sand: and not yet released.
+>
+> Please check back later for the first release. :heart:
+
+`spotless` is a command line interface (CLI) for the [spotless code formatter](../README.md).
+It intends to be a simple alternative to its siblings: the plugins for [gradle](../plugin-gradle/README.md), [maven](../plugin-maven/README.md)
+and others. It supports formatting a plethora of file types and can be easily configured.
+
+Example usage:
+
+```shell
+spotless --target '**/src/**/*.java' \
+ google-java-format \
+ license-header --header='/* (c) DiffPlug $YEAR */'
+```
+
+This command formats all java files in any `src` folder with the [google-java-format](https://github.com/google/google-java-format) and adds (or updates an existing) license header.
+
+Using the above command line you go
+
+
+
+| From this | to this |
+| ---------------------------------------------------- | ------------------------------------------------------------ |
+|  |  |
+
+
+
+## Installation
+
+To install with Homebrew on macOS or Linux:
+
+```shell
+brew install diffplug/tap/spotless-cli
+
+# or if you prefer
+brew tap diffplug/tap
+brew install spotless-cli
+```
+
+To install with Chocolatey on Windows:
+
+```shell
+choco install ...
+```
+
+Alternatively, you can download the latest binary for your system from the [releases page](https://...) and add it to your PATH.
+
+## General usage
+
+The general principle is to specify the files to format, configure global options and then add one or more formatter steps - with configuration if needed.
+
+```shell
+# general structure of the invocation
+spotless --target [... more options] formatter1 [config-of-formatter1] formatter2 [config-of-formatter2] ...
+```
+
+Be aware that the order of the formatter steps is important. The formatters are applied in the order they are specified.
+
+To see all available options and formatters, run:
+
+```shell
+spotless --help
+```
+
+This will show you the available options and formatters as such:
+
+
+
+```
+ __ __
+ _________ ____ / /_/ /__ __________
+ / ___/ __ \/ __ \/ __/ / _ \/ ___/ ___/
+ (__ ) /_/ / /_/ / /_/ / __(__ |__ )
+/____/ .___/\____/\__/_/\___/____/____/ Spotless CLI
+ /_/
+
+
+Usage: spotless [-hV] [-e=] [-l=] [--log-file=]
+ [-m=] [-p=N] [-t=]... [-q | -v [-v]...]
+ [FORMATTING_STEPS]
+
+spotless is a command line interface (CLI) for the spotless code formatter.
+It can either check if your files are formatted according to your configuration
+or apply the formatting to the files.
+
+ -e, --encoding= The encoding of the files to format.
+ (default: UTF-8)
+ -h, --help Show this help message and exit.
+ -l, --line-ending=
+ The line ending of the files to format.
+ One of: GIT_ATTRIBUTES,
+ GIT_ATTRIBUTES_FAST_ALLSAME, PLATFORM_NATIVE,
+ WINDOWS, UNIX, MAC_CLASSIC, PRESERVE
+ (default: UNIX)
+ --log-file= The log file to write the output to.
+ -m, --mode= The mode to run spotless in.
+ One of: CHECK, APPLY
+ (default: APPLY)
+ APPLY: Apply the correct formatting where needed
+ (replace file contents with formatted content).
+ CHECK: Check if the files are formatted or show
+ the diff of the formatting.
+ -p, --parallelity=N The number of parallel formatter threads to run.
+ (default: #cores * 0.5)
+ -q, --quiet Disable as much output as possible.
+ -t, --target= The target files to format. Blobs are supported.
+ Examples:
+ -t 'src/**/*.java'
+ -t 'src/**/*.kt'
+ -t 'README.md'
+ -v Enable verbose output. Multiple -v options
+ increase the verbosity (max 5).
+ -V, --version Print version information and exit.
+
+Available formatting steps:
+ clang-format Runs clang-format
+ format-annotations Corrects line break formatting of type annotations in
+ java files.
+ google-java-format Runs google java format
+ license-header Runs license header
+ palantir-java-format Runs palantir java format
+ prettier Runs prettier, the opinionated code formatter.
+
+Possible exit codes:
+ 0 Successful formatting.
+ In APPLY mode, this means all files were formatted successfully.
+ In CHECK mode, this means all files were already formatted properly.
+ 1 Some files need to be formatted.
+ In APPLY mode, this means some files failed to be formatted (see output
+ for details).
+ In CHECK mode, this means some files are currently not formatted
+ properly (and might be fixed in APPLY mode).
+ -1 Some files did not converge. This can happen when one formatter does not
+ converge on the file content.
+ You can find more about this special case here:
+
+ -2 An exception occurred during execution.
+```
+
+
+
+## Available Formatter Steps
+
+Spotless CLI supports the following formatter steps in alphabetical order:
+
+- [clang-format](#clang-format)
+- [format-annotations](#format-annotations)
+- [google-java-format](#google-java-format)
+- [license-header](#license-header)
+- [palantir-java-format](#palantir-java-format)
+- [prettier](#prettier)
+
+### clang-format
+
+Formats C/C++/Objective-C and more files according to the [clang-format](https://clang.llvm.org/docs/ClangFormat.html) style guide.
+
+To see usage instructions for the clang-format formatter, run: `spotless clang-format --help`
+
+
+
+```
+Usage: spotless clang-format [-hV] [-c=] [-s=