Skip to content

Commit 9a7cd0a

Browse files
authored
Feat: Add auto formatting bot (#14927)
1 parent 7fc9fd3 commit 9a7cd0a

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed

.github/workflows/auto-format.yml

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
name: Auto Format Bot
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
env:
8+
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
9+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10+
11+
jobs:
12+
format-check:
13+
# Only run on pull requests when the bot is mentioned
14+
if: |
15+
github.event.issue.pull_request &&
16+
contains(github.event.comment.body, '/format-fix apply')
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 30
19+
20+
permissions:
21+
contents: write
22+
pull-requests: write
23+
issues: write
24+
25+
steps:
26+
- name: Check permissions
27+
run: |
28+
PR_AUTHOR=$(gh pr view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json author --jq '.author.login')
29+
30+
PERMISSION=$(gh api repos/${{ github.repository }}/collaborators/${{ github.actor }}/permission --jq '.permission' 2>/dev/null || echo "none")
31+
32+
# only allow if user is PR author OR has admin/write repository access
33+
if [[ "${{ github.actor }}" == "$PR_AUTHOR" ]] || [[ "$PERMISSION" == "admin" ]] || [[ "$PERMISSION" == "write" ]]; then
34+
echo "Permission granted: User @${{ github.actor }} can run the format bot"
35+
if [[ "${{ github.actor }}" == "$PR_AUTHOR" ]]; then
36+
echo " - Reason: PR author"
37+
fi
38+
if [[ "$PERMISSION" == "admin" ]] || [[ "$PERMISSION" == "write" ]]; then
39+
echo " - Reason: Repository $PERMISSION access"
40+
fi
41+
else
42+
echo "Error: User @${{ github.actor }} does not have permission to run the format bot."
43+
echo "Required: Be the PR author OR have admin/write repository access."
44+
exit 1
45+
fi
46+
47+
- name: Add workflow started reaction
48+
run: |
49+
gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
50+
--method POST \
51+
--input - <<< '{"content":"eyes"}'
52+
53+
- name: Get PR details and checkout
54+
run: |
55+
# Get PR details
56+
PR_DATA=$(gh pr view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json headRefName,headRepository,headRepositoryOwner)
57+
HEAD_REF=$(echo "$PR_DATA" | jq -r '.headRefName')
58+
HEAD_REPO=$(echo "$PR_DATA" | jq -r '.headRepository.name')
59+
HEAD_OWNER=$(echo "$PR_DATA" | jq -r '.headRepositoryOwner.login')
60+
61+
echo "head_ref=$HEAD_REF" >> $GITHUB_ENV
62+
echo "head_repo_full=$HEAD_OWNER/$HEAD_REPO" >> $GITHUB_ENV
63+
64+
- name: Detect if PR is from fork
65+
run: |
66+
HEAD_OWNER=$(echo "${{ env.head_repo_full }}" | cut -d'/' -f1)
67+
REPO_OWNER="${{ github.repository_owner }}"
68+
69+
if [[ "$HEAD_OWNER" != "$REPO_OWNER" ]]; then
70+
echo "is_fork=true" >> $GITHUB_ENV
71+
echo "PR is from fork: ${{ env.head_repo_full }}"
72+
else
73+
echo "is_fork=false" >> $GITHUB_ENV
74+
echo "PR is from same repository"
75+
fi
76+
77+
- name: Checkout PR code
78+
uses: actions/checkout@v4
79+
with:
80+
repository: ${{ env.head_repo_full }}
81+
ref: ${{ env.head_ref }}
82+
token: ${{ secrets.GITHUB_TOKEN }}
83+
fetch-depth: 0
84+
85+
- uses: ./.github/actions/prepare-for-build
86+
87+
#this replaces ana06/[email protected] since it doesn't support issue comment triggers
88+
- name: Get changed files
89+
id: changed-files
90+
run: |
91+
echo "Getting changed files for PR #${{ github.event.issue.number }}..."
92+
93+
ALL_FILES=$(gh pr diff ${{ github.event.issue.number }} --name-only --repo ${{ github.repository }})
94+
95+
FILTERED_FILES=$(echo "$ALL_FILES" | grep -E '\.(java|gradle|groovy|md|properties|xml|py|sh|bat|cmd)$' || true)
96+
97+
echo "All changed files:"
98+
echo "$ALL_FILES"
99+
echo
100+
echo "Filtered files for formatting check:"
101+
echo "$FILTERED_FILES"
102+
103+
echo "all<<EOF" >> $GITHUB_OUTPUT
104+
echo "$ALL_FILES" >> $GITHUB_OUTPUT
105+
echo "EOF" >> $GITHUB_OUTPUT
106+
107+
echo "filtered<<EOF" >> $GITHUB_OUTPUT
108+
echo "$FILTERED_FILES" >> $GITHUB_OUTPUT
109+
echo "EOF" >> $GITHUB_OUTPUT
110+
111+
- name: Initial validation
112+
id: initial-validation
113+
continue-on-error: true
114+
run: |
115+
echo "Running initial validation..."
116+
./gradlew check -x test
117+
118+
- name: Fix formatting issues
119+
if: steps.initial-validation.outcome == 'failure'
120+
run: |
121+
echo "Fixing formatting issues..."
122+
./gradlew tidy
123+
124+
- name: Check if formatting fixes were made
125+
if: steps.initial-validation.outcome == 'failure'
126+
id: check_changes
127+
run: |
128+
git add .
129+
if git diff --staged --quiet; then
130+
echo "No formatting changes were made"
131+
echo "changes_made=false" >> $GITHUB_OUTPUT
132+
else
133+
echo "Formatting changes were made"
134+
echo "changes_made=true" >> $GITHUB_OUTPUT
135+
echo "Changed files:"
136+
git diff --staged --name-only
137+
fi
138+
139+
- name: Create fix branch and commit (same-repo)
140+
if: steps.initial-validation.outcome == 'failure' && steps.check_changes.outputs.changes_made == 'true' && env.is_fork == 'false'
141+
id: create_fix_branch
142+
run: |
143+
# Create a new branch for the fixes
144+
fix_branch="format-fixes-${{ env.head_ref }}-$(date +%s)"
145+
echo "fix_branch=$fix_branch" >> $GITHUB_OUTPUT
146+
echo "fix_branch=$fix_branch" >> $GITHUB_ENV
147+
148+
git config --local user.email "[email protected]"
149+
git config --local user.name "Auto Format Bot"
150+
151+
git checkout -b "$fix_branch"
152+
git commit -m "Apply automatic formatting fixes
153+
154+
Fixes applied by @auto-format-bot in response to:
155+
${{ github.event.comment.html_url }}
156+
157+
Original PR: #${{ github.event.issue.number }}
158+
159+
Changes applied:
160+
$(git diff --name-only HEAD~1)"
161+
162+
git push origin "$fix_branch"
163+
164+
- name: Commit directly to fork PR
165+
if: steps.initial-validation.outcome == 'failure' && steps.check_changes.outputs.changes_made == 'true' && env.is_fork == 'true'
166+
id: commit_to_fork
167+
run: |
168+
git config --local user.email "[email protected]"
169+
git config --local user.name "Auto Format Bot"
170+
171+
git commit -m "Apply automatic formatting fixes
172+
173+
Fixes applied by @auto-format-bot in response to:
174+
${{ github.event.comment.html_url }}
175+
176+
Original PR: #${{ github.event.issue.number }}
177+
178+
Changes applied:
179+
$(git diff --name-only HEAD~1)"
180+
181+
git push origin "${{ env.head_ref }}"
182+
183+
- name: Final validation
184+
run: |
185+
echo "Running final validation..."
186+
./gradlew check -x test
187+
188+
- name: Create PR for fixes (same-repo only)
189+
if: steps.initial-validation.outcome == 'failure' && steps.check_changes.outputs.changes_made == 'true' && env.is_fork == 'false'
190+
id: create_pr
191+
run: |
192+
PR_BODY="## Automatic Formatting Fixes
193+
194+
This PR applies automatic formatting fixes to address validation failures in #${{ github.event.issue.number }}.
195+
196+
### 📝 Details
197+
- **Triggered by**: ${{ github.event.comment.html_url }}
198+
- **Original PR**: #${{ github.event.issue.number }}
199+
- **Fix branch**: \`${{ env.fix_branch }}\`
200+
201+
### 🚀 Next Steps
202+
Review and merge this PR to apply the formatting fixes to the original branch.
203+
204+
---
205+
*This PR was created automatically by the Auto Format Bot*"
206+
207+
PR_URL=$(gh pr create \
208+
--repo ${{ github.repository }} \
209+
--title "Apply formatting fixes to #${{ github.event.issue.number }}" \
210+
--body "$PR_BODY" \
211+
--base "${{ env.head_ref }}" \
212+
--head "${{ env.fix_branch }}")
213+
214+
PR_NUMBER=$(echo "$PR_URL" | grep -o '[0-9]*$')
215+
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
216+
echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
217+
218+
- name: Add success reaction
219+
if: success()
220+
run: |
221+
# Add success reaction
222+
gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
223+
--method POST \
224+
--input - <<< '{"content":"+1"}'
225+
226+
- name: Comment on PR with success (fixes applied to same-repo)
227+
if: success() && steps.initial-validation.outcome == 'failure' && steps.check_changes.outputs.changes_made == 'true' && env.is_fork == 'false'
228+
run: |
229+
gh pr comment ${{ github.event.issue.number }} --repo ${{ github.repository }} --body "## Formatting Fixes Applied
230+
231+
The formatting bot has successfully created a PR with formatting fixes!
232+
233+
### 📝 Details
234+
- **Triggered by**: ${{ github.event.comment.html_url }}
235+
- **Fix PR**: #${{ steps.create_pr.outputs.pr_number }}
236+
237+
### 🚀 Next Steps
238+
Review and merge PR #${{ steps.create_pr.outputs.pr_number }} to apply the formatting fixes to this branch.
239+
240+
---
241+
*This was performed automatically by the Auto Format Bot*"
242+
243+
- name: Comment on PR with success (fixes applied to fork)
244+
if: success() && steps.initial-validation.outcome == 'failure' && steps.check_changes.outputs.changes_made == 'true' && env.is_fork == 'true'
245+
run: |
246+
gh pr comment ${{ github.event.issue.number }} --repo ${{ github.repository }} --body "## Formatting Fixes Applied
247+
248+
The formatting bot has commited the formatting fixes to this PR!
249+
250+
### 📝 Details
251+
- **Triggered by**: ${{ github.event.comment.html_url }}
252+
- **Action taken**: Direct commit to this PR branch
253+
254+
---
255+
*This was performed automatically by the Auto Format Bot*"
256+
257+
- name: Comment on PR with success (no fixes needed)
258+
if: success() && steps.initial-validation.outcome == 'success'
259+
run: |
260+
gh pr comment ${{ github.event.issue.number }} --repo ${{ github.repository }} --body "## No Formatting Issues Found
261+
262+
The formatting bot has validated this PR and found no issues!
263+
264+
### 📝 Details
265+
- **Triggered by**: ${{ github.event.comment.html_url }}
266+
267+
The PR is ready for review!
268+
269+
---
270+
*This was performed automatically by the Auto Format Bot*"
271+
272+
- name: Comment on PR with success (fixes made but no changes)
273+
if: success() && steps.initial-validation.outcome == 'failure' && steps.check_changes.outputs.changes_made == 'false'
274+
run: |
275+
gh pr comment ${{ github.event.issue.number }} --repo ${{ github.repository }} --body "## Formatting Issues Detected (No Auto-fixes Available)
276+
277+
The formatting bot found issues but was unable to automatically fix them.
278+
279+
### 📝 Details
280+
- **Triggered by**: ${{ github.event.comment.html_url }}
281+
282+
**Recommendation**: Review the validation failures manually and apply fixes as needed.
283+
284+
---
285+
*This was performed automatically by the Auto Format Bot*"
286+
287+
- name: Add failure reaction
288+
if: failure()
289+
run: |
290+
# Add failure reaction
291+
gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
292+
--method POST \
293+
--input - <<< '{"content":"-1"}'
294+
295+
- name: Comment on PR with failure
296+
if: failure()
297+
run: |
298+
gh pr comment ${{ github.event.issue.number }} --repo ${{ github.repository }} --body "## Formatting Failed
299+
300+
The formatting bot encountered issues while processing this PR.
301+
302+
### Next Steps:
303+
1. Check the workflow logs for specific error details
304+
2. Fix any issues manually if needed
305+
3. Re-trigger the bot with \`/format-fix apply\`
306+
307+
### 📝 Details
308+
- **Triggered by**: ${{ github.event.comment.html_url }}
309+
- **Files processed**: ${{ steps.changed-files.outputs.all || 'None detected' }}
310+
311+
---
312+
*This was performed automatically by the Auto Format Bot*"

0 commit comments

Comments
 (0)