commands.yml 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. name: Trigger actions on PR comments
  2. on:
  3. issue_comment:
  4. types: [created]
  5. permissions:
  6. contents: write
  7. pull-requests: write
  8. issues: write
  9. jobs:
  10. fix-all:
  11. if: |
  12. github.event.issue.pull_request != null &&
  13. github.event.comment.body == '/fix-all' &&
  14. (
  15. github.event.comment.author_association == 'OWNER' ||
  16. github.event.comment.author_association == 'MEMBER' ||
  17. (github.event.comment.user != null && github.event.comment.user.login == github.event.issue.user.login)
  18. )
  19. runs-on: ubuntu-latest
  20. steps:
  21. - name: Post acknowledgment comment
  22. uses: actions/github-script@v8
  23. with:
  24. script: |
  25. await github.rest.issues.createComment({
  26. owner: context.repo.owner,
  27. repo: context.repo.repo,
  28. issue_number: context.issue.number,
  29. body: '🤖 Command `/fix-all` received. Running…'
  30. });
  31. - name: Get PR details
  32. uses: actions/github-script@v8
  33. id: pr
  34. with:
  35. script: |
  36. const pr = await github.rest.pulls.get({
  37. owner: context.repo.owner,
  38. repo: context.repo.repo,
  39. pull_number: context.issue.number
  40. });
  41. if (pr.data.state !== 'open') {
  42. await github.rest.issues.createComment({
  43. owner: context.repo.owner,
  44. repo: context.repo.repo,
  45. issue_number: context.issue.number,
  46. body: '⚠️ Command `/fix-all` can only be run on open pull requests.'
  47. });
  48. core.setFailed('PR is not open');
  49. return;
  50. }
  51. return pr.data.head;
  52. - name: Checkout PR branch
  53. uses: actions/checkout@v5
  54. with:
  55. token: ${{ secrets.GITHUB_TOKEN }}
  56. repository: ${{ fromJSON(steps.pr.outputs.result).repo.full_name }}
  57. ref: ${{ fromJSON(steps.pr.outputs.result).ref }}
  58. - name: Use Composer cache
  59. id: composer-cache
  60. uses: actions/cache@v4
  61. with:
  62. path: vendor
  63. key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
  64. restore-keys: |
  65. ${{ runner.os }}-php-
  66. - name: Run Composer install
  67. run: composer install --prefer-dist --no-progress
  68. if: steps.composer-cache.outputs.cache-hit != 'true'
  69. - name: Uses Node.js
  70. uses: actions/setup-node@v5
  71. with:
  72. node-version: lts/*
  73. cache: npm
  74. - run: npm ci
  75. - name: Run make fix-all
  76. id: fix
  77. run: |
  78. set -e
  79. make fix-all || {
  80. echo "make_failed=true" >> $GITHUB_OUTPUT
  81. exit 1
  82. }
  83. echo "make_failed=false" >> $GITHUB_OUTPUT
  84. - name: Commit and push changes
  85. id: commit
  86. if: success()
  87. env:
  88. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  89. run: |
  90. git add -A
  91. if git diff --cached --quiet; then
  92. echo "no_changes=true" >> $GITHUB_OUTPUT
  93. echo "No changes to commit."
  94. else
  95. echo "no_changes=false" >> $GITHUB_OUTPUT
  96. git config user.name "github-actions[bot]"
  97. git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
  98. # Get PR info from the base repository
  99. PR_JSON=$(gh pr view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json headRepository,headRefName,maintainerCanModify)
  100. HEAD_REPO=$(echo "$PR_JSON" | jq -r '.headRepository.nameWithOwner')
  101. HEAD_BRANCH=$(echo "$PR_JSON" | jq -r '.headRefName')
  102. CAN_MODIFY=$(echo "$PR_JSON" | jq -r '.maintainerCanModify')
  103. echo "Head repo: $HEAD_REPO"
  104. echo "Head branch: $HEAD_BRANCH"
  105. echo "Maintainer can modify: $CAN_MODIFY"
  106. # Create commit
  107. git commit -m "chore: make fix-all"
  108. COMMIT_SHA=$(git rev-parse HEAD)
  109. echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT
  110. # Try to push
  111. if git push https://x-access-token:${GH_TOKEN}@github.com/${HEAD_REPO}.git HEAD:${HEAD_BRANCH}; then
  112. echo "pushed=true" >> $GITHUB_OUTPUT
  113. echo "Successfully pushed to $HEAD_REPO"
  114. else
  115. echo "pushed=false" >> $GITHUB_OUTPUT
  116. echo "Failed to push!"
  117. exit 1
  118. fi
  119. fi
  120. - name: Post completion comment
  121. uses: actions/github-script@v8
  122. if: always()
  123. with:
  124. script: |
  125. const makeFailed = '${{ steps.fix.outputs.make_failed }}' === 'true';
  126. const noChanges = '${{ steps.commit.outputs.no_changes || 'false' }}' === 'true';
  127. const pushed = '${{ steps.commit.outputs.pushed || 'false' }}' === 'true';
  128. const commitSha = '${{ steps.commit.outputs.commit_sha }}';
  129. const jobStatus = '${{ job.status }}';
  130. let message;
  131. if (jobStatus === 'success') {
  132. if (noChanges) {
  133. message = '✅ Command `/fix-all` completed with no change.';
  134. } else if (pushed) {
  135. message = `🔧 Command \`/fix-all\` made some fixes and committed as ${commitSha}`;
  136. } else {
  137. // Should not happen
  138. message = 'ℹ️ Command `/fix-all` completed, but strangely.';
  139. }
  140. } else if (makeFailed) {
  141. message = `❌ Command \`/fix-all\` failed. Check the [workflow run](${context.payload.repository.html_url}/actions/runs/${context.runId}) for details.`;
  142. } else {
  143. message = `⚠️ Command \`/fix-all\` ran successfully, but changes could not be pushed.\n\n`;
  144. message += `* Please check that your PR settings “Allow edits from maintainers” is enabled.\n`;
  145. message += `* Or run \`make fix-all\` locally and push to your branch.`;
  146. }
  147. await github.rest.issues.createComment({
  148. owner: context.repo.owner,
  149. repo: context.repo.repo,
  150. issue_number: context.issue.number,
  151. body: message
  152. });