name: Approve Contributor on: issue_comment: types: [created, edited] jobs: approve: if: ${{ !github.event.issue.pull_request && github.event.comment.user.login != 'kangal-bot' }} runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ github.event.repository.default_branch }} persist-credentials: false - name: Add contributor to approved list id: update uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: github-token: ${{ secrets.KANGAL_GITHUB_TOKEN }} script: | const fs = require('fs'); const issueAuthor = context.payload.issue.user.login; const commenter = context.payload.comment.user.login; const commentBody = context.payload.comment.body || ''; const action = context.payload.action; const approvedFile = '.github/APPROVED_CONTRIBUTORS'; const approveMatch = commentBody.match(/(^|\s)\/approve(?:\s+@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?))?(?=$|\s)/i); const maintainerPermissions = ['admin', 'maintain', 'write']; if (!approveMatch) { console.log('Comment does not contain /approve'); core.setOutput('status', 'skipped'); return; } const approvedUser = approveMatch[2] || issueAuthor; core.setOutput('approved_user', approvedUser); try { const { data: permissionLevel } = await github.rest.repos.getCollaboratorPermissionLevel({ owner: context.repo.owner, repo: context.repo.repo, username: commenter, }); if (!maintainerPermissions.includes(permissionLevel.permission)) { console.log(`${commenter} does not have maintainer access`); core.setOutput('status', 'skipped'); return; } } catch (error) { console.log(`${commenter} does not have collaborator access`); core.setOutput('status', 'skipped'); return; } let content = fs.readFileSync(approvedFile, 'utf8'); const approvedList = content .split('\n') .map(line => line.trim().toLowerCase()) .filter(line => line && !line.startsWith('#')); if (approvedList.includes(approvedUser.toLowerCase())) { console.log(`${approvedUser} is already approved`); if (action === 'edited') { core.setOutput('status', 'skipped'); return; } core.setOutput('status', 'already'); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: `@${approvedUser} is already in the approved contributors list.`, }); return; } content = content.trimEnd() + '\n' + approvedUser + '\n'; fs.writeFileSync(approvedFile, content); console.log(`Added ${approvedUser} to approved contributors`); core.setOutput('status', 'added'); - name: Commit and push if: steps.update.outputs.status == 'added' env: KANGAL_GITHUB_TOKEN: ${{ secrets.KANGAL_GITHUB_TOKEN }} run: | git config user.name "kangal-bot" git config user.email "285672167+kangal-bot@users.noreply.github.com" git add .github/APPROVED_CONTRIBUTORS git diff --staged --quiet || git commit -m "chore: approve contributor ${{ steps.update.outputs.approved_user }}" git push "https://x-access-token:${KANGAL_GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" HEAD:${{ github.event.repository.default_branch }} - name: Comment on issue if: steps.update.outputs.status == 'added' uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: github-token: ${{ secrets.KANGAL_GITHUB_TOKEN }} script: | const approvedUser = '${{ steps.update.outputs.approved_user }}'; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: `@${approvedUser} has been added to the approved contributors list. You can now submit PRs for maintainer-approved work. Thanks for contributing!`, });