diff --git a/.github/regenerate-good.sh b/.github/regenerate-good.sh new file mode 100755 index 0000000..943ed0b --- /dev/null +++ b/.github/regenerate-good.sh @@ -0,0 +1,14 @@ +#!/bin/sh +act -W .github/workflows/test-regenerate-good.yml 2>/dev/null | +perl -ne ' + unless ($state) { + $state = 1 if (/run-scalafmt\.sh/); + next; + } + if ($state == 1) { + $state = 2 if (/docker exec/); + next; + } + last unless s/^.*\| //; + print; +' > .github/testdata/Good.scala diff --git a/.github/testdata/.scalafmt.conf b/.github/testdata/.scalafmt.conf index ae8e9a8..f7da8a3 100644 --- a/.github/testdata/.scalafmt.conf +++ b/.github/testdata/.scalafmt.conf @@ -1,3 +1,5 @@ -# I dont like this formatting directive in reality, but lets +# I don't like this formatting directive in reality, but it lets # us verify that this is reading a conf file easily -align = most +align.preset = most +version = 3.7.15 +runner.dialect = scala213 diff --git a/.github/testdata/Bad.scala b/.github/testdata/Bad.scala index f65f5d7..85b0fa8 100644 --- a/.github/testdata/Bad.scala +++ b/.github/testdata/Bad.scala @@ -16,7 +16,6 @@ sealed abstract class Formatted { } /** Aligned by first asterisk, default ScalaDoc style is second. - * */ object Formatted { case class Success(formattedCode: String) extends Formatted diff --git a/.github/testdata/Good.scala b/.github/testdata/Good.scala index 264d1ae..7dad55e 100644 --- a/.github/testdata/Good.scala +++ b/.github/testdata/Good.scala @@ -3,6 +3,7 @@ messiness added to it. -mroth */ package org.scalafmt sealed abstract class Formatted { + def toEither: Either[Throwable, String] = this match { case Formatted.Success(s) => Right(s) case Formatted.Failure(e) => Left(e) // too much space before comment @@ -15,7 +16,6 @@ sealed abstract class Formatted { } /** Aligned by first asterisk, default ScalaDoc style is second. - * */ object Formatted { case class Success(formattedCode: String) extends Formatted diff --git a/.github/workflows/test-all.yml b/.github/workflows/test-all.yml new file mode 100644 index 0000000..2d168ad --- /dev/null +++ b/.github/workflows/test-all.yml @@ -0,0 +1,12 @@ +on: [workflow_dispatch] +name: Check with all testdata + +jobs: + check-testdata: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Checking testdata + uses: ./ + with: + args: "-c .github/testdata/.scalafmt.conf --list" diff --git a/.github/workflows/test-regenerate-good.yml b/.github/workflows/test-regenerate-good.yml new file mode 100644 index 0000000..d089d7d --- /dev/null +++ b/.github/workflows/test-regenerate-good.yml @@ -0,0 +1,12 @@ +on: [workflow_dispatch] +name: Regenerate Good file (run in act) + +jobs: + regenerate-good: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Checking testdata + uses: ./ + with: + args: "-c .github/testdata/.scalafmt.conf --stdout .github/testdata/Bad.scala" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 17908a5..1010c85 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,12 +1,12 @@ on: [push] -name: Check with testdata +name: Check with good testdata jobs: - check-testdata: + check-good-testdata: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: Checking testdata + - uses: actions/checkout@v4 + - name: Checking testdata (pass) uses: ./ with: args: "-c .github/testdata/.scalafmt.conf --exclude .github/testdata/Bad.scala --list" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 09b53be..0000000 --- a/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -# This is essentially just scalafmt loaded into an alpine container, so -# that we have a shell present to expand wildcards etc. -FROM mrothy/scalafmt:2.3.2 as scalafmt - -FROM eclipse-temurin:11-jre - -COPY --from=scalafmt /usr/local/bin/scalafmt /usr/local/bin/scalafmt -COPY entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] -CMD ["--list"] diff --git a/Makefile b/Makefile index 4bc3353..7b921c8 100644 --- a/Makefile +++ b/Makefile @@ -1,34 +1,17 @@ -IMAGE := openlaw/scalafmt-ci -# DEFAULT_ARGS := --list -WORKDIR := /github/workspace TESTDATA := .github/testdata .PHONY: test testfail testdata clean -image: - docker build -t $(IMAGE) . - test: - docker run --rm -it \ - -w=$(WORKDIR) \ - -v "$$(pwd)/$(TESTDATA)":$(WORKDIR) \ - $(IMAGE) --list --exclude Bad.scala + act -W .github/workflows/test.yml # expected failure, to see output testfail: - docker run --rm -it \ - -w=$(WORKDIR) \ - -v "$$(pwd)/$(TESTDATA)":$(WORKDIR) \ - $(IMAGE) --list + act -W .github/workflows/test-all.yml # generate the "good" version of the sample file $(TESTDATA)/Good.scala: $(TESTDATA)/Bad.scala $(TESTDATA)/.scalafmt.conf - docker run --rm -i \ - -v "$$(pwd)/$(TESTDATA)":/conf \ - mrothy/scalafmt-native:2.2.2 \ - --config /conf/.scalafmt.conf \ - --stdin --stdout \ - < $< > $@ + ./.github/regenerate-good.sh testdata: $(TESTDATA)/Good.scala diff --git a/README.md b/README.md index 7a2e76f..277f909 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Scalafmt GitHub Action -Runs `scalafmt --list` on your repository automatically with every push. +Run `scalafmt` on your repository automatically with every push. + +By default, it runs with `--list`, but that's configurable. Uses [scalafmt-native](https://github.com/mroth/scalafmt-native) under the hood to keep things small and booting super quick by avoiding the JVM. :racehorse: @@ -11,7 +13,7 @@ Simply add a step such as the following to your your workflow yml file: ```yml - name: Check for scalafmt conformance - uses: openlawteam/scalafmt-ci@v2 + uses: garnercorp/scalafmt-ci@v3 ``` Example in the full context of a workflow file, with some optional arguments: @@ -24,28 +26,19 @@ jobs: scalafmt-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: fetch-depth: 1 - name: Checking your code to see if u r naughty or nice - uses: openlawteam/scalafmt-ci@v2 + uses: garnercorp/scalafmt-ci@v3 with: args: "--exclude=third_party --list" ``` -### Installing with GitHub Marketplace - -https://github.com/marketplace/actions/scalafmt-action +## Compatibility -### (Legacy) HCL Syntax +### v2 to v3 -If you are still using legacy HCL format (from the GitHub Actions Alpha test), -you will need to pin to a previous version of this action. - -```hcl -action "lint" { - uses="openlawteam/scalafmt-ci@v0" - # optional additional args - args="--exclude ./vendor" -} -``` +- [v2](https://github.com/garnerCorp/scalafmt-ci/tree/v2) is built around [scalafmt](https://github.com/scalameta/scalafmt) [`3.5.2`](https://github.com/scalameta/scalafmt/releases/tag/v3.5.2), [v3](https://github.com/garnerCorp/scalafmt-ci/tree/v3) is built around scalafmt [`3.7+`](https://github.com/scalameta/scalafmt/releases/tag/v3.7.15) + - The formatting defaults have changed + - `--list --test` is no longer accepted as arguments, you should try just one of them. diff --git a/action.yml b/action.yml index a183910..4def6f9 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,6 @@ name: "Scalafmt Action" description: "Format Scala code using scalafmt" -author: "Matthew Rothenberg " +author: "GarnerCorp " branding: icon: "wind" color: "red" @@ -9,8 +9,40 @@ inputs: description: "Args to pass to scalafmt" default: "--list" required: false + version: + description: "Version of scalafmt" + default: "3.7.15" + required: false + runs: - using: "docker" - image: "Dockerfile" - args: - - ${{ inputs.args }} + using: "composite" + steps: + - shell: bash + run: | + "$action_path/set-path.sh" + env: + scalafmt_version: ${{ inputs.version }} + action_path: ${{ github.action_path }} + - uses: actions/cache/restore@v4 + id: cache + with: + path: ${{ env.SCALAFMT_PATH }} + key: scalafmt-${{ inputs.version }} + - shell: bash + id: retrieve-scalafmt + if: ${{ !steps.cache.outputs.cache-hit }} + run: | + curl -sL https://github.com/scalameta/scalafmt/releases/download/v${scalafmt_version}/scalafmt-linux-glibc > "$SCALAFMT_PATH/scalafmt" + chmod +x "$SCALAFMT_PATH/scalafmt" + echo "retrieved=1" >> "$GITHUB_OUTPUT" + - shell: bash + run: | + run-scalafmt.sh + env: + args: ${{ inputs.args }} + - name: Cache scalafmt + if: ${{ always() && steps.retrieve-scalafmt.outputs.retrieved }} + uses: actions/cache/save@v4 + with: + path: ${{ env.SCALAFMT_PATH }} + key: scalafmt-${{ inputs.version }} diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index 1d0389b..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -sh -c "/usr/local/bin/scalafmt --non-interactive $*" diff --git a/extract-errors.pl b/extract-errors.pl new file mode 100755 index 0000000..091d8b9 --- /dev/null +++ b/extract-errors.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +my $source_file = $ENV{source}; +my $errors_file = $ENV{errors}; +my $new_source_file = "$source_file.new"; +open my $source_in, "<", $source_file; +open my $source_out, ">", $new_source_file; +open my $errors, ">>", $errors_file; +my $found_error=0; +while (<$source_in>) { + if ($found_error) { + print $errors $_; + } elsif (/^error:|^Segmentation fault/) { + $found_error=1; + print $errors $_; + } else { + print $source_out $_; + } +} +close $source_in; +close $source_out; +close $errors; +rename $new_source_file, $source_file; diff --git a/run-scalafmt.sh b/run-scalafmt.sh new file mode 100755 index 0000000..6f538b1 --- /dev/null +++ b/run-scalafmt.sh @@ -0,0 +1,45 @@ +#!/bin/sh +output=$(mktemp) +warnings=$(mktemp) +errors=$(mktemp) + +enforce_scala_format_version() { + if [ -e .scalafmt.conf ]; then + perl -pi -e 'next unless s/^\s*(version)=.*/$1=$ENV{scalafmt_version}/' .scalafmt.conf + fi +} + +enforce_scala_format_version +scalafmt --non-interactive $args > "$output" 2> "$warnings" +result=$? +cat "$output" +cat "$warnings" >&2 +[ $result -eq 0 ] && exit + +report() { + file="$1" + summary="$2" + + [ -s "$file" ] || return + echo "
$summary" + echo + echo '```' + perl -pe 's/$ENV{GITHUB_WORKSPACE}//g' "$file" + echo '```' + echo '
' + echo +} + +source="$output" errors="$errors" extract-errors.pl +source="$warnings" errors="$errors" extract-errors.pl + +( + echo "# scalafmt failed ($result)" + if [ -s "$errors" ]; then + echo '# Errors' + cat "$errors" + fi + report "$warnings" "Warnings" + report "$output" "Status" +) >> "$GITHUB_STEP_SUMMARY" +exit $result diff --git a/set-path.sh b/set-path.sh new file mode 100755 index 0000000..e91d1cd --- /dev/null +++ b/set-path.sh @@ -0,0 +1,11 @@ +#!/bin/sh +SCALAFMT_PATH="/tmp/scalafmt/${scalafmt_version}" +mkdir -p "$SCALAFMT_PATH" +( + echo "SCALAFMT_PATH=$SCALAFMT_PATH" + echo "scalafmt_version=$scalafmt_version" +) >> "$GITHUB_ENV" +( + echo "$SCALAFMT_PATH" + echo "$action_path" +) >> "$GITHUB_PATH"