From 787a9ddbf7576d051ce489ff0e8defac8791df8a Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Fri, 16 May 2025 10:38:29 -0700 Subject: [PATCH 1/3] Add spotless autofix for PRs --- .github/workflows/auto-spotless-apply.yml | 109 ++++++++++++++++++++++ .github/workflows/auto-spotless-check.yml | 53 +++++++++++ 2 files changed, 162 insertions(+) create mode 100644 .github/workflows/auto-spotless-apply.yml create mode 100644 .github/workflows/auto-spotless-check.yml diff --git a/.github/workflows/auto-spotless-apply.yml b/.github/workflows/auto-spotless-apply.yml new file mode 100644 index 000000000..98be72fb3 --- /dev/null +++ b/.github/workflows/auto-spotless-apply.yml @@ -0,0 +1,109 @@ +name: Auto spotless apply +on: + workflow_run: + workflows: + - "Auto spotless check" + types: + - completed + +permissions: + contents: read + +jobs: + apply: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - id: download-patch + name: Download patch + uses: actions/github-script@v7.0.1 + with: + # this script copied from + # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#using-data-from-the-triggering-workflow + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id + }); + let patchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "patch" + })[0]; + if (!patchArtifact) { + core.info('No patch to apply.'); + return; + } + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: patchArtifact.id, + archive_format: 'zip' + }); + const fs = require('fs'); + const path = require('path'); + const temp = '${{ runner.temp }}/artifacts'; + if (!fs.existsSync(temp)){ + fs.mkdirSync(temp); + } + fs.writeFileSync(path.join(temp, 'patch.zip'), Buffer.from(download.data)); + core.setOutput("exists", "true"); + + - id: get-pr-number + name: Get PR number + uses: actions/github-script@v7.0.1 + with: + script: | + const response = await github.request(context.payload.workflow_run.url); + core.setOutput('pr-number', response.data.pull_requests[0].number); + + - name: Unzip patch + if: steps.download-patch.outputs.exists == 'true' + working-directory: ${{ runner.temp }}/artifacts + run: unzip patch.zip + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + if: steps.download-patch.outputs.exists == 'true' + + - name: Check out PR branch + if: steps.download-patch.outputs.exists == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: gh pr checkout ${{ steps.get-pr-number.outputs.pr-number }} + + - name: Use CLA approved github bot + if: steps.download-patch.outputs.exists == 'true' + # IMPORTANT do not call the .github/scripts/use-cla-approved-bot.sh + # since that script could have been compromised in the PR branch + run: | + git config user.name otelbot + git config user.email 197425009+otelbot@users.noreply.github.com + + - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + if: steps.download-patch.outputs.exists == 'true' + id: otelbot-token + with: + app-id: ${{ vars.OTELBOT_APP_ID }} + private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }} + + - name: Apply patch and push + if: steps.download-patch.outputs.exists == 'true' + env: + GH_TOKEN: ${{ steps.otelbot-token.outputs.token }} + run: | + git apply "${{ runner.temp }}/artifacts/patch" + git commit -a -m "./gradlew spotlessApply" + git push + + - if: steps.download-patch.outputs.exists == 'true' && success() + env: + GH_TOKEN: ${{ steps.otelbot-token.outputs.token }} + run: | + gh pr comment ${{ steps.get-pr-number.outputs.pr-number }} --body "🔧 The result from spotlessApply was committed to the PR branch." + + - if: steps.download-patch.outputs.exists == 'true' && failure() + env: + GH_TOKEN: ${{ steps.otelbot-token.outputs.token }} + run: | + gh pr comment ${{ steps.get-pr-number.outputs.pr-number }} --body "❌ The result from spotlessApply could not be committed to the PR branch, see logs: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID." diff --git a/.github/workflows/auto-spotless-check.yml b/.github/workflows/auto-spotless-check.yml new file mode 100644 index 000000000..c5dfd9196 --- /dev/null +++ b/.github/workflows/auto-spotless-check.yml @@ -0,0 +1,53 @@ +name: Auto spotless check +on: + pull_request: + types: + - opened + - synchronize + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up JDK for running Gradle + uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + with: + distribution: temurin + java-version: 17 + + - name: Set up gradle + uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + with: + cache-read-only: true + + - name: Check out PR branch + env: + GH_TOKEN: ${{ github.token }} + run: gh pr checkout ${{ github.event.pull_request.number }} + + - name: Spotless + run: ./gradlew spotlessApply + + - id: create-patch-file + name: Create patch file + run: | + git diff > patch + if [ -s patch ]; then + echo "non-empty=true" >> "$GITHUB_OUTPUT" + fi + + - name: Upload patch file + if: steps.create-patch-file.outputs.non-empty == 'true' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + path: patch + name: patch From fba8b11140177965e24b49a73203cca90fd34213 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 19 May 2025 10:42:48 -0700 Subject: [PATCH 2/3] retrigger workflow --- .github/workflows/auto-spotless-apply.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/auto-spotless-apply.yml b/.github/workflows/auto-spotless-apply.yml index 98be72fb3..253b58439 100644 --- a/.github/workflows/auto-spotless-apply.yml +++ b/.github/workflows/auto-spotless-apply.yml @@ -63,8 +63,17 @@ jobs: working-directory: ${{ runner.temp }}/artifacts run: unzip patch.zip + - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + if: steps.download-patch.outputs.exists == 'true' + id: otelbot-token + with: + app-id: 1295839 + private-key: ${{ secrets.OTELBOT_JAVA_CONTRIB_PRIVATE_KEY }} + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 if: steps.download-patch.outputs.exists == 'true' + with: + token: ${{ steps.otelbot-token.outputs.token }} - name: Check out PR branch if: steps.download-patch.outputs.exists == 'true' @@ -80,17 +89,8 @@ jobs: git config user.name otelbot git config user.email 197425009+otelbot@users.noreply.github.com - - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - if: steps.download-patch.outputs.exists == 'true' - id: otelbot-token - with: - app-id: ${{ vars.OTELBOT_APP_ID }} - private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }} - - name: Apply patch and push if: steps.download-patch.outputs.exists == 'true' - env: - GH_TOKEN: ${{ steps.otelbot-token.outputs.token }} run: | git apply "${{ runner.temp }}/artifacts/patch" git commit -a -m "./gradlew spotlessApply" From 41cb793c71b1144c988d56a5b2add911850e84c7 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 19 May 2025 12:24:09 -0700 Subject: [PATCH 3/3] fix --- .github/workflows/auto-spotless-apply.yml | 98 ++++++++++------------- .github/workflows/auto-spotless-check.yml | 6 +- 2 files changed, 45 insertions(+), 59 deletions(-) diff --git a/.github/workflows/auto-spotless-apply.yml b/.github/workflows/auto-spotless-apply.yml index 253b58439..65b03f006 100644 --- a/.github/workflows/auto-spotless-apply.yml +++ b/.github/workflows/auto-spotless-apply.yml @@ -16,73 +16,59 @@ jobs: contents: write pull-requests: write steps: - - id: download-patch - name: Download patch - uses: actions/github-script@v7.0.1 + - name: Download patch + uses: actions/download-artifact@v4.3.0 with: - # this script copied from - # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#using-data-from-the-triggering-workflow - script: | - let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id - }); - let patchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == "patch" - })[0]; - if (!patchArtifact) { - core.info('No patch to apply.'); - return; - } - let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: patchArtifact.id, - archive_format: 'zip' - }); - const fs = require('fs'); - const path = require('path'); - const temp = '${{ runner.temp }}/artifacts'; - if (!fs.existsSync(temp)){ - fs.mkdirSync(temp); - } - fs.writeFileSync(path.join(temp, 'patch.zip'), Buffer.from(download.data)); - core.setOutput("exists", "true"); + run-id: ${{ github.event.workflow_run.id }} + path: ${{ runner.temp }} + merge-multiple: true + github-token: ${{ github.token }} - - id: get-pr-number - name: Get PR number - uses: actions/github-script@v7.0.1 - with: - script: | - const response = await github.request(context.payload.workflow_run.url); - core.setOutput('pr-number', response.data.pull_requests[0].number); - - - name: Unzip patch - if: steps.download-patch.outputs.exists == 'true' - working-directory: ${{ runner.temp }}/artifacts - run: unzip patch.zip + - id: unzip-patch + name: Unzip patch + working-directory: ${{ runner.temp }} + run: | + if [ -f patch ]; then + echo "exists=true" >> $GITHUB_OUTPUT + fi - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - if: steps.download-patch.outputs.exists == 'true' + if: steps.unzip-patch.outputs.exists == 'true' id: otelbot-token with: - app-id: 1295839 + app-id: 1296620 private-key: ${{ secrets.OTELBOT_JAVA_CONTRIB_PRIVATE_KEY }} - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - if: steps.download-patch.outputs.exists == 'true' + if: steps.unzip-patch.outputs.exists == 'true' with: token: ${{ steps.otelbot-token.outputs.token }} + - id: get-pr + if: steps.unzip-patch.outputs.exists == 'true' + name: Get PR + env: + PR_BRANCH: |- + ${{ + (github.event.workflow_run.head_repository.owner.login != github.event.workflow_run.repository.owner.login) + && format('{0}:{1}', github.event.workflow_run.head_repository.owner.login, github.event.workflow_run.head_branch) + || github.event.workflow_run.head_branch + }} + GH_TOKEN: ${{ github.token }} + run: | + echo gh pr view "${PR_BRANCH}" --json number --jq .number + number=$(gh pr view "${PR_BRANCH}" --json number --jq .number) + echo $number + echo "number=$number" >> $GITHUB_OUTPUT + - name: Check out PR branch - if: steps.download-patch.outputs.exists == 'true' + if: steps.unzip-patch.outputs.exists == 'true' env: GH_TOKEN: ${{ github.token }} - run: gh pr checkout ${{ steps.get-pr-number.outputs.pr-number }} + run: gh pr checkout ${{ steps.get-pr.outputs.number }} - name: Use CLA approved github bot - if: steps.download-patch.outputs.exists == 'true' + if: steps.unzip-patch.outputs.exists == 'true' # IMPORTANT do not call the .github/scripts/use-cla-approved-bot.sh # since that script could have been compromised in the PR branch run: | @@ -90,20 +76,20 @@ jobs: git config user.email 197425009+otelbot@users.noreply.github.com - name: Apply patch and push - if: steps.download-patch.outputs.exists == 'true' + if: steps.unzip-patch.outputs.exists == 'true' run: | - git apply "${{ runner.temp }}/artifacts/patch" + git apply "${{ runner.temp }}/patch" git commit -a -m "./gradlew spotlessApply" git push - - if: steps.download-patch.outputs.exists == 'true' && success() + - if: steps.unzip-patch.outputs.exists == 'true' && success() env: GH_TOKEN: ${{ steps.otelbot-token.outputs.token }} run: | - gh pr comment ${{ steps.get-pr-number.outputs.pr-number }} --body "🔧 The result from spotlessApply was committed to the PR branch." + gh pr comment ${{ steps.get-pr.outputs.number }} --body "🔧 The result from spotlessApply was committed to the PR branch." - - if: steps.download-patch.outputs.exists == 'true' && failure() + - if: steps.unzip-patch.outputs.exists == 'true' && failure() env: GH_TOKEN: ${{ steps.otelbot-token.outputs.token }} run: | - gh pr comment ${{ steps.get-pr-number.outputs.pr-number }} --body "❌ The result from spotlessApply could not be committed to the PR branch, see logs: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID." + gh pr comment ${{ steps.get-pr.outputs.number }} --body "❌ The result from spotlessApply could not be committed to the PR branch, see logs: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID." diff --git a/.github/workflows/auto-spotless-check.yml b/.github/workflows/auto-spotless-check.yml index c5dfd9196..8e80f3b62 100644 --- a/.github/workflows/auto-spotless-check.yml +++ b/.github/workflows/auto-spotless-check.yml @@ -37,16 +37,16 @@ jobs: - name: Spotless run: ./gradlew spotlessApply - - id: create-patch-file + - id: create-patch name: Create patch file run: | git diff > patch if [ -s patch ]; then - echo "non-empty=true" >> "$GITHUB_OUTPUT" + echo "exists=true" >> "$GITHUB_OUTPUT" fi - name: Upload patch file - if: steps.create-patch-file.outputs.non-empty == 'true' + if: steps.create-patch.outputs.exists == 'true' uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: path: patch