diff --git a/.github/workflows/checkstyle-autofix.yaml b/.github/workflows/checkstyle-autofix.yaml new file mode 100644 index 00000000000..267ff585ad8 --- /dev/null +++ b/.github/workflows/checkstyle-autofix.yaml @@ -0,0 +1,121 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +# Runs the checkstyle auto-fix (storm-checkstyle/README.md) on one module, pushes the result to a +# new branch checkstyle-fix/-- (one per execution) and opens a pull request +# from it against the branch the workflow ran on. The Checkstyle report of the module before and +# after the fix is attached to the run as an artifact; the violations left after the fix are listed +# in the pull request. +name: Checkstyle auto-fix + +on: + workflow_dispatch: + inputs: + module: + description: 'Maven module to fix, as its path in the repository (e.g. storm-client or external/storm-hdfs)' + required: true + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + autofix: + runs-on: ubuntu-latest + timeout-minutes: 120 + env: + MODULE: ${{ inputs.module }} + steps: + - name: Validate the module input + run: | + if ! [[ "$MODULE" =~ ^[A-Za-z0-9._-]+(/[A-Za-z0-9._-]+)*$ ]] || [[ "$MODULE" == *..* ]]; then + echo "::error::'$MODULE' is not a valid module path" + exit 1 + fi + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Check that the module exists + run: test -f "$MODULE/pom.xml" || { echo "::error::$MODULE/pom.xml not found"; exit 1; } + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Set up JDK 25 + uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 + with: + distribution: temurin + java-version: 25 + - name: Check that the module declares the auto-fix plugins + run: | + # without them the auto-fix executions would run with no configuration and silently fix nothing + mvn --batch-mode --quiet -pl "$MODULE" help:effective-pom -Doutput="$RUNNER_TEMP/effective-pom.xml" + python3 - "$RUNNER_TEMP/effective-pom.xml" <<'EOF' + import sys + import xml.etree.ElementTree as ET + ns = {'m': 'http://maven.apache.org/POM/4.0.0'} + plugins = {p.text for p in ET.parse(sys.argv[1]).getroot().findall('m:build/m:plugins/m:plugin/m:artifactId', ns)} + missing = {'rewrite-maven-plugin', 'gmavenplus-plugin'} - plugins + if missing: + sys.exit(f"::error::the module does not declare {', '.join(sorted(missing))} in its build plugins") + EOF + - name: Build the module and the modules it depends on (the Groovy stage resolves its classpath) + run: mvn --batch-mode install -DskipTests -Dcheckstyle.skip=true -pl "$MODULE" -am + - name: Checkstyle report before the fix + run: ./dev-tools/gitact/checkstyle-report.sh before + - name: Auto-fix the module (OpenRewrite, Groovy, OpenRewrite re-indent) + run: | + mvn --batch-mode -pl "$MODULE" -Dcheckstyle.skip=true \ + org.openrewrite.maven:rewrite-maven-plugin:run@checkstyle-autofix-openrewrite \ + org.codehaus.gmavenplus:gmavenplus-plugin:execute@checkstyle-autofix \ + org.openrewrite.maven:rewrite-maven-plugin:run@checkstyle-reindent-openrewrite + - name: Normalize the license headers + run: mvn --batch-mode -pl "$MODULE" -Dcheckstyle.skip=true org.codehaus.gmavenplus:gmavenplus-plugin:execute@normalize-license-headers + - name: Checkstyle report after the fix + run: ./dev-tools/gitact/checkstyle-report.sh after + - name: Upload the Checkstyle reports + if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: checkstyle-reports + path: ${{ runner.temp }}/checkstyle-reports/ + if-no-files-found: ignore + - name: Push the result to a new branch and open a pull request + env: + GH_TOKEN: ${{ github.token }} + run: | + # one branch per execution, so a run never overwrites the branch of an earlier one (or its open PR) + BRANCH="checkstyle-fix/$MODULE-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT" + # only the module itself (build output is git-ignored), never the tooling files + git add -A -- "$MODULE" + if git diff --cached --quiet; then + echo "Nothing to fix in $MODULE" | tee -a "$GITHUB_STEP_SUMMARY" + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git commit -m "Checkstyle auto-fix of $MODULE" + git push origin "$BRANCH" + REPORTS="$RUNNER_TEMP/checkstyle-reports" + { + echo "Checkstyle auto-fix of \`$MODULE\`, made by [this workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) (the full reports are in its \`checkstyle-reports\` artifact)." + echo + cat "$REPORTS/before.md" "$REPORTS/after.md" + } > "$RUNNER_TEMP/pr-body.md" + PR=$(gh pr create --base "$GITHUB_REF_NAME" --head "$BRANCH" \ + --title "Checkstyle auto-fix of $MODULE" --body-file "$RUNNER_TEMP/pr-body.md") + echo "Opened $PR from $BRANCH" | tee -a "$GITHUB_STEP_SUMMARY" diff --git a/.mvn/.gitkeep b/.mvn/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 00000000000..3d61a1f27e7 --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1,11 @@ +--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED +--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED +--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED diff --git a/dev-tools/gitact/checkstyle-report.sh b/dev-tools/gitact/checkstyle-report.sh new file mode 100755 index 00000000000..358dad4164d --- /dev/null +++ b/dev-tools/gitact/checkstyle-report.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +# Runs the build's Checkstyle check on $MODULE and saves its report as +# $RUNNER_TEMP/checkstyle-reports/