Skip to content

Commit 21ae307

Browse files
authored
pre-commit: enable pushing of auto-fixes for forks (#9036)
1 parent 65abee4 commit 21ae307

2 files changed

Lines changed: 112 additions & 26 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Push pre-commit auto-fixes
2+
on:
3+
workflow_run:
4+
workflows: [ "Halide Presubmit Checks" ]
5+
types: [ completed ]
6+
7+
permissions:
8+
contents: read
9+
actions: read
10+
11+
jobs:
12+
push-fixes:
13+
name: Push auto-fixes to PR branch
14+
runs-on: ubuntu-slim
15+
if: github.event.workflow_run.conclusion == 'failure'
16+
steps:
17+
- name: Download auto-fix artifacts
18+
id: download
19+
uses: actions/download-artifact@v4
20+
with:
21+
name: pre-commit-fixes
22+
path: /tmp/pre-commit-fixes
23+
run-id: ${{ github.event.workflow_run.id }}
24+
github-token: ${{ github.token }}
25+
continue-on-error: true
26+
27+
- name: Read PR metadata
28+
if: steps.download.outcome == 'success'
29+
id: pr
30+
run: |
31+
{
32+
echo "number=$(jq -r '.number' /tmp/pre-commit-fixes/pr-metadata.json)"
33+
echo "head-repo=$(jq -r '.head_repo' /tmp/pre-commit-fixes/pr-metadata.json)"
34+
echo "head-ref=$(jq -r '.head_ref' /tmp/pre-commit-fixes/pr-metadata.json)"
35+
echo "maintainer-can-modify=$(jq -r '.maintainer_can_modify' /tmp/pre-commit-fixes/pr-metadata.json)"
36+
} >> "$GITHUB_OUTPUT"
37+
38+
- name: Abort if maintainer edits not allowed
39+
if: >-
40+
steps.download.outcome == 'success'
41+
&& steps.pr.outputs.head-repo != github.repository
42+
&& steps.pr.outputs.maintainer-can-modify != 'true'
43+
run: |
44+
echo "::warning::PR #${{ steps.pr.outputs.number }} does not allow maintainer edits. Cannot push auto-fixes to fork."
45+
echo "skip=true" >> "$GITHUB_ENV"
46+
47+
- uses: actions/create-github-app-token@v2
48+
if: steps.download.outcome == 'success' && env.skip != 'true'
49+
id: app-token
50+
with:
51+
app-id: ${{ secrets.LLVM_UPDATER_ID }}
52+
private-key: ${{ secrets.LLVM_UPDATER_PRIVATE_KEY }}
53+
54+
- name: Get GitHub App user ID
55+
if: steps.download.outcome == 'success' && env.skip != 'true'
56+
id: get-user-id
57+
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
58+
env:
59+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
60+
61+
- uses: actions/checkout@v4
62+
if: steps.download.outcome == 'success' && env.skip != 'true'
63+
with:
64+
repository: ${{ steps.pr.outputs.head-repo }}
65+
ref: ${{ steps.pr.outputs.head-ref }}
66+
token: ${{ steps.app-token.outputs.token }}
67+
68+
- name: Apply and push fixes
69+
if: steps.download.outcome == 'success' && env.skip != 'true'
70+
run: |
71+
git config user.name "${{ steps.app-token.outputs.app-slug }}[bot]"
72+
git config user.email "${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com"
73+
74+
if [ "$(git log -1 --format='%ae')" = "$(git config user.email)" ]; then
75+
echo "::error::pre-commit auto-fixes were not idempotent. Please fix manually."
76+
exit 1
77+
fi
78+
79+
git apply /tmp/pre-commit-fixes/pre-commit-fixes.patch
80+
git add -A
81+
git commit -m "Apply pre-commit auto-fixes"
82+
git push

.github/workflows/pre-commit.yml

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,9 @@ jobs:
1717
name: Run pre-commit checks
1818
runs-on: ubuntu-slim
1919
steps:
20-
- uses: actions/create-github-app-token@v2
21-
id: app-token
22-
with:
23-
app-id: ${{ secrets.LLVM_UPDATER_ID }}
24-
private-key: ${{ secrets.LLVM_UPDATER_PRIVATE_KEY }}
25-
26-
- name: Get GitHub App user ID
27-
id: get-user-id
28-
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
29-
env:
30-
GH_TOKEN: ${{ steps.app-token.outputs.token }}
31-
32-
- name: Configure git and environment
33-
run: |
34-
echo "GH_TOKEN=${{ steps.app-token.outputs.token }}" >> "$GITHUB_ENV"
35-
git config --global user.name "${{ steps.app-token.outputs.app-slug }}[bot]"
36-
git config --global user.email "${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com"
37-
3820
- uses: actions/checkout@v4
3921
with:
4022
ref: ${{ github.head_ref }}
41-
token: ${{ steps.app-token.outputs.token }}
4223

4324
- uses: actions/setup-python@v5
4425
- uses: astral-sh/setup-uv@v5
@@ -47,19 +28,42 @@ jobs:
4728
id: pre-commit
4829
uses: pre-commit/action@v3.0.1
4930

50-
- name: Push auto-fixes
31+
- name: Create auto-fix diff
32+
id: diff
5133
if: ${{ !cancelled() && steps.pre-commit.outcome == 'failure' }}
5234
run: |
5335
if git diff --quiet; then
54-
echo "::error::no auto-fixable changes; pre-commit failure requires manual attention."
55-
elif [ "$(git log -1 --format='%ae')" = "$(git config user.email)" ]; then
56-
echo "::error::pre-commit auto-fixes were not idempotent. Please fix manually."
36+
echo "has-fixes=false" >> "$GITHUB_OUTPUT"
5737
else
58-
git add -A
59-
git commit -m "Apply pre-commit auto-fixes"
60-
git push
38+
git diff > /tmp/pre-commit-fixes.patch
39+
echo "has-fixes=true" >> "$GITHUB_OUTPUT"
6140
fi
6241
42+
- name: Save PR metadata
43+
if: ${{ !cancelled() && steps.diff.outputs.has-fixes == 'true' }}
44+
run: |
45+
jq -n \
46+
--argjson number "$PR_NUMBER" \
47+
--arg head_repo "$PR_HEAD_REPO" \
48+
--arg head_ref "$PR_HEAD_REF" \
49+
--argjson maintainer_can_modify "$PR_MAINTAINER_CAN_MODIFY" \
50+
'$ARGS.named' | tee /tmp/pr-metadata.json
51+
env:
52+
PR_NUMBER: ${{ github.event.pull_request.number }}
53+
PR_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
54+
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
55+
PR_MAINTAINER_CAN_MODIFY: ${{ github.event.pull_request.maintainer_can_modify }}
56+
57+
- name: Upload auto-fix artifacts
58+
if: ${{ !cancelled() && steps.diff.outputs.has-fixes == 'true' }}
59+
uses: actions/upload-artifact@v4
60+
with:
61+
name: pre-commit-fixes
62+
path: |
63+
/tmp/pre-commit-fixes.patch
64+
/tmp/pr-metadata.json
65+
retention-days: 1
66+
6367
- name: Annotate codespell errors
6468
if: ${{ !cancelled() && steps.pre-commit.outcome == 'failure' }}
6569
run: |

0 commit comments

Comments
 (0)