|
| 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