name: Format Command on: issue_comment: types: [created] jobs: format: name: Format if: >- github.event.issue.pull_request && github.event.comment.body == '/format' && ( github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR' ) runs-on: ubuntu-latest timeout-minutes: 10 permissions: contents: write pull-requests: write steps: - name: Generate token id: app-token uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} # Push the formatted commit (contents), comment on the PR # (pull-requests), and react to the triggering comment via the # issues/comments reactions API (issues). Nothing else. permission-contents: write permission-pull-requests: write permission-issues: write - name: Get PR details id: pr uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: ${{ steps.app-token.outputs.token }} script: | const pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, }); const isFork = pr.data.head.repo.fork || pr.data.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`; core.setOutput('ref', pr.data.head.ref); core.setOutput('sha', pr.data.head.sha); core.setOutput('is_fork', isFork.toString()); core.setOutput('full_name', pr.data.head.repo.full_name); - name: React to comment uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: ${{ steps.app-token.outputs.token }} script: | await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: context.payload.comment.id, content: 'eyes', }); - name: Checkout (same-repo) if: steps.pr.outputs.is_fork == 'false' uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ steps.pr.outputs.ref }} token: ${{ steps.app-token.outputs.token }} # Intentional: the same-repo push step below pushes the # formatted changes back to the PR branch using this credential. persist-credentials: true - name: Checkout (fork) if: steps.pr.outputs.is_fork == 'true' uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: repository: ${{ steps.pr.outputs.full_name }} ref: ${{ steps.pr.outputs.sha }} persist-credentials: false - name: Setup Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22 - name: Run formatter run: npx oxfmt@0.58.0 --ignore-path .gitignore - name: Check for changes id: diff run: | git add -A if git diff --staged --quiet; then echo "changed=false" >> "$GITHUB_OUTPUT" else echo "changed=true" >> "$GITHUB_OUTPUT" fi - name: Commit and push (same-repo) if: steps.pr.outputs.is_fork == 'false' && steps.diff.outputs.changed == 'true' run: | git config user.name "emdashbot[bot]" git config user.email "emdashbot[bot]@users.noreply.github.com" git commit -m "style: format" git push - name: Commit and push (fork) if: steps.pr.outputs.is_fork == 'true' && steps.diff.outputs.changed == 'true' id: push-fork run: | git config user.name "emdashbot[bot]" git config user.email "emdashbot[bot]@users.noreply.github.com" git commit -m "style: format" export GIT_ASKPASS="$RUNNER_TEMP/git-askpass.sh" printf '#!/bin/sh\necho "%s"\n' "$APP_TOKEN" > "$GIT_ASKPASS" chmod +x "$GIT_ASKPASS" git remote add fork "https://x-access-token@github.com/$FULL_NAME.git" if git push fork "HEAD:$HEAD_REF"; then echo "push_failed=false" >> "$GITHUB_OUTPUT" else echo "push_failed=true" >> "$GITHUB_OUTPUT" fi rm -f "$GIT_ASKPASS" env: APP_TOKEN: ${{ steps.app-token.outputs.token }} FULL_NAME: ${{ steps.pr.outputs.full_name }} HEAD_REF: ${{ steps.pr.outputs.ref }} - name: Comment on push failure if: steps.push-fork.outputs.push_failed == 'true' uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: github-token: ${{ steps.app-token.outputs.token }} script: | await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: `Could not push formatting changes to this fork. The contributor may have "Allow edits by maintainers" disabled.\n\nPlease run the formatter locally:\n\n\`\`\`\npnpm format\n\`\`\``, }); - name: React to comment (result) uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: CHANGED: ${{ steps.diff.outputs.changed }} with: github-token: ${{ steps.app-token.outputs.token }} script: | const changed = process.env.CHANGED === 'true'; await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: context.payload.comment.id, content: changed ? 'rocket' : '+1', });