Update README.md #7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Automation | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| jobs: | |
| # Job 1: Auto-label based on files changed | |
| auto-label: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Label based on files changed | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const { data: files } = await github.rest.pulls.listFiles({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| }); | |
| const labels = new Set(); | |
| for (const file of files) { | |
| const path = file.filename; | |
| if (path.includes('.github/workflows/')) { | |
| labels.add('workflows'); | |
| } | |
| if (path.startsWith('src/')) { | |
| labels.add('source-code'); | |
| } | |
| if (path.includes('.test.') || path.includes('.spec.')) { | |
| labels.add('tests'); | |
| } | |
| if (path.endsWith('.md')) { | |
| labels.add('documentation'); | |
| } | |
| if (path === 'package.json' || path === 'package-lock.json') { | |
| labels.add('dependencies'); | |
| } | |
| if (path.endsWith('.css') || path.endsWith('.scss')) { | |
| labels.add('styles'); | |
| } | |
| if (path.includes('components/')) { | |
| labels.add('components'); | |
| } | |
| } | |
| if (labels.size > 0) { | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| labels: Array.from(labels) | |
| }); | |
| } | |
| # Job 2: Check PR size and add size label | |
| size-label: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - name: Check PR size | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const { data: pr } = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| }); | |
| const additions = pr.additions; | |
| const deletions = pr.deletions; | |
| const totalChanges = additions + deletions; | |
| let sizeLabel = 'size/XS'; | |
| if (totalChanges >= 1000) { | |
| sizeLabel = 'size/XL'; | |
| } else if (totalChanges >= 500) { | |
| sizeLabel = 'size/L'; | |
| } else if (totalChanges >= 200) { | |
| sizeLabel = 'size/M'; | |
| } else if (totalChanges >= 50) { | |
| sizeLabel = 'size/S'; | |
| } | |
| const { data: labels } = await github.rest.issues.listLabelsOnIssue({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| for (const label of labels) { | |
| if (label.name.startsWith('size/')) { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| name: label.name | |
| }).catch(() => {}); | |
| } | |
| } | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| labels: [sizeLabel] | |
| }).catch(() => {}); | |
| # Job 3: Comment with PR statistics | |
| pr-stats: | |
| runs-on: ubuntu-latest | |
| needs: size-label | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - name: Comment PR with stats | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const { data: pr } = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| }); | |
| const { data: files } = await github.rest.pulls.listFiles({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| }); | |
| const additions = pr.additions; | |
| const deletions = pr.deletions; | |
| const changedFiles = pr.changed_files; | |
| const totalChanges = additions + deletions; | |
| let size = 'XS'; | |
| if (totalChanges >= 1000) { | |
| size = 'XL'; | |
| } else if (totalChanges >= 500) { | |
| size = 'L'; | |
| } else if (totalChanges >= 200) { | |
| size = 'M'; | |
| } else if (totalChanges >= 50) { | |
| size = 'S'; | |
| } | |
| const fileTypes = {}; | |
| for (const file of files) { | |
| const ext = file.filename.split('.').pop(); | |
| fileTypes[ext] = (fileTypes[ext] || 0) + 1; | |
| } | |
| const fileTypesStr = Object.entries(fileTypes) | |
| .sort((a, b) => b[1] - a[1]) | |
| .slice(0, 5) | |
| .map(([ext, count]) => `- ${ext}: ${count} files`) | |
| .join('\n'); | |
| let recommendation = 'Great! This PR is easy to review.'; | |
| if (totalChanges >= 500) { | |
| recommendation = 'Large PR! Consider splitting into smaller PRs for easier review.'; | |
| } else if (totalChanges >= 200) { | |
| recommendation = 'Medium-sized PR. Consider breaking it down if possible.'; | |
| } | |
| const commentBody = '## PR Statistics - Size: ' + size + '\n\n' + | |
| '**Total Changes:** ' + totalChanges + ' lines\n\n' + | |
| '### Changes\n' + | |
| '- Additions: ' + additions + ' lines\n' + | |
| '- Deletions: ' + deletions + ' lines\n' + | |
| '- Files changed: ' + changedFiles + '\n\n' + | |
| '### File Types\n' + | |
| fileTypesStr + '\n\n' + | |
| '### Review Recommendations\n' + | |
| recommendation + '\n\n' + | |
| '---\n' + | |
| '*Automated by PR Automation*'; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('PR Statistics') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: commentBody | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: commentBody | |
| }); | |
| } |