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_ + + + +[![Changelog](https://img.shields.io/badge/changelog-versionLast%3DUNKNOWN-blue.svg)](CHANGES.md) + +[![OS Win](https://img.shields.io/badge/OS-Windows-blueviolet.svg)](README.md) +[![OS Linux](https://img.shields.io/badge/OS-Linux-blueviolet.svg)](README.md) +[![OS macOS](https://img.shields.io/badge/OS-macOS-blueviolet.svg)](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 | +| ---------------------------------------------------- | ------------------------------------------------------------ | +| ![before](docs/examples/intro/FormattingExample.png) | ![after](docs/examples/intro/FormattingExampleFormatted.png) | + + + +## 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=