From 61ea4f83446ae2621a235a8f968f6376bed8189c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 7 Mar 2024 12:54:17 -0800 Subject: [PATCH] Use suggestion-bot to convert pre-commit errors in PRs with fixes into code review suggestions. (#3746) This can't be done directly from a `pull_request` action, because that's run without write privileges. This is done for security reasons, because it runs in the context of the pull request branch. So instead, we perform this in two steps: - The `pull_request` action runs `pre-commit` and uploads an artifact containing the diffs and the event information (which is only used to extract the pull request number). - A separate `workflow_run` action is triggered when the `pre-commit` action finishes. This action is privileged, and should be able to download the artifact and create corresponding suggestions. Unfortunately, due to the permissions model in play here, the second half of this appears to only be testable live in production. For now, we're splitting the pre-commit action into two actions -- one to run on PRs and one to run when actually merging commits -- so that the suggestions are only triggered in the former case. It might be possible to recombine these using data in the `workflow_run` invocation to tell them apart, but the documentation here isn't very good so I've made this PR dump out that event information so that we can look at it and see if it contains the relevant information. --- .github/workflows/pre_commit.yaml | 14 ++++- .github/workflows/pre_commit_on_merge.yaml | 21 +++++++ .github/workflows/pre_commit_suggestions.yaml | 57 +++++++++++++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/pre_commit_on_merge.yaml create mode 100644 .github/workflows/pre_commit_suggestions.yaml diff --git a/.github/workflows/pre_commit.yaml b/.github/workflows/pre_commit.yaml index 3f3f3ccb0330..c0aaf890efb3 100644 --- a/.github/workflows/pre_commit.yaml +++ b/.github/workflows/pre_commit.yaml @@ -6,9 +6,6 @@ name: pre-commit on: pull_request: - merge_group: - push: - branches: [trunk] jobs: pre-commit: @@ -17,3 +14,14 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 - uses: pre-commit/action@v3.0.0 + - name: Collect pre-commit output + if: ${{ failure() }} + run: | + mkdir -p pre-commit-output + git diff > pre-commit-output/diff + cp $GITHUB_EVENT_PATH pre-commit-output/event + - uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: pre-commit output + path: pre-commit-output/* diff --git a/.github/workflows/pre_commit_on_merge.yaml b/.github/workflows/pre_commit_on_merge.yaml new file mode 100644 index 000000000000..76102eed58e4 --- /dev/null +++ b/.github/workflows/pre_commit_on_merge.yaml @@ -0,0 +1,21 @@ +# Part of the Carbon Language project, under the Apache License v2.0 with LLVM +# Exceptions. See /LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Run pre-commit checks after a commit is merged into trunk. This is like +# pre-commit, but does not trigger adding suggested edits. In principle, this +# should never fail. +name: pre-commit-on-merge + +on: + merge_group: + push: + branches: [trunk] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + - uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/pre_commit_suggestions.yaml b/.github/workflows/pre_commit_suggestions.yaml new file mode 100644 index 000000000000..96dbe828ecd2 --- /dev/null +++ b/.github/workflows/pre_commit_suggestions.yaml @@ -0,0 +1,57 @@ +# Part of the Carbon Language project, under the Apache License v2.0 with LLVM +# Exceptions. See /LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Create PR suggestions based on problems found by pre-commit action. +name: pre-commit-suggestions + +on: + workflow_run: + workflows: [pre-commit] + types: + - completed + +permissions: + pull-requests: write + +jobs: + pull-request-suggestions: + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + runs-on: ubuntu-latest + steps: + - name: Print event + run: cat $GITHUB_EVENT_PATH + + - name: Download pre-commit output + uses: actions/github-script@v6 + with: + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + + let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "pre-commit output" + })[0]; + + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + + let fs = require('fs'); + fs.writeFileSync(`${process.env.HOME}/output.zip`, Buffer.from(download.data)); + + - name: Unzip output + run: | + mkdir -p ~/output + unzip -d ~/output ~/output.zip diff event + + - name: Create suggestions + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: GITHUB_EVENT_PATH=~/output/event npx suggestion-bot ~/output/diff