Skip to content

Commit 2b00a8a

Browse files
authored
Merge pull request #2 from kirti/master
Master
2 parents 8f5cb24 + 086d20b commit 2b00a8a

4 files changed

Lines changed: 239 additions & 1 deletion

File tree

.github/CODEOWNERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# kirti owns everything
2+
* @kirti
3+
4+
# Specific ownership
5+
/.github/workflows/ @kirti
6+
/src/ @kirti
7+
*.md @kirti
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
name: PR Automation
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
jobs:
8+
# Job 1: Auto-label based on files changed
9+
auto-label:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: read
13+
pull-requests: write
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Label based on files changed
20+
uses: actions/github-script@v7
21+
with:
22+
script: |
23+
const { data: files } = await github.rest.pulls.listFiles({
24+
owner: context.repo.owner,
25+
repo: context.repo.repo,
26+
pull_number: context.issue.number,
27+
});
28+
29+
const labels = new Set();
30+
31+
for (const file of files) {
32+
const path = file.filename;
33+
34+
if (path.includes('.github/workflows/')) {
35+
labels.add('workflows');
36+
}
37+
38+
if (path.startsWith('src/')) {
39+
labels.add('source-code');
40+
}
41+
42+
if (path.includes('.test.') || path.includes('.spec.')) {
43+
labels.add('tests');
44+
}
45+
46+
if (path.endsWith('.md')) {
47+
labels.add('documentation');
48+
}
49+
50+
if (path === 'package.json' || path === 'package-lock.json') {
51+
labels.add('dependencies');
52+
}
53+
54+
if (path.endsWith('.css') || path.endsWith('.scss')) {
55+
labels.add('styles');
56+
}
57+
58+
if (path.includes('components/')) {
59+
labels.add('components');
60+
}
61+
}
62+
63+
if (labels.size > 0) {
64+
await github.rest.issues.addLabels({
65+
owner: context.repo.owner,
66+
repo: context.repo.repo,
67+
issue_number: context.issue.number,
68+
labels: Array.from(labels)
69+
});
70+
}
71+
72+
# Job 2: Check PR size and add size label
73+
size-label:
74+
runs-on: ubuntu-latest
75+
permissions:
76+
pull-requests: write
77+
78+
steps:
79+
- name: Check PR size
80+
uses: actions/github-script@v7
81+
with:
82+
script: |
83+
const { data: pr } = await github.rest.pulls.get({
84+
owner: context.repo.owner,
85+
repo: context.repo.repo,
86+
pull_number: context.issue.number,
87+
});
88+
89+
const additions = pr.additions;
90+
const deletions = pr.deletions;
91+
const totalChanges = additions + deletions;
92+
93+
let sizeLabel = 'size/XS';
94+
95+
if (totalChanges >= 1000) {
96+
sizeLabel = 'size/XL';
97+
} else if (totalChanges >= 500) {
98+
sizeLabel = 'size/L';
99+
} else if (totalChanges >= 200) {
100+
sizeLabel = 'size/M';
101+
} else if (totalChanges >= 50) {
102+
sizeLabel = 'size/S';
103+
}
104+
105+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
106+
owner: context.repo.owner,
107+
repo: context.repo.repo,
108+
issue_number: context.issue.number,
109+
});
110+
111+
for (const label of labels) {
112+
if (label.name.startsWith('size/')) {
113+
await github.rest.issues.removeLabel({
114+
owner: context.repo.owner,
115+
repo: context.repo.repo,
116+
issue_number: context.issue.number,
117+
name: label.name
118+
}).catch(() => {});
119+
}
120+
}
121+
122+
await github.rest.issues.addLabels({
123+
owner: context.repo.owner,
124+
repo: context.repo.repo,
125+
issue_number: context.issue.number,
126+
labels: [sizeLabel]
127+
}).catch(() => {});
128+
129+
# Job 3: Comment with PR statistics
130+
pr-stats:
131+
runs-on: ubuntu-latest
132+
needs: size-label
133+
permissions:
134+
pull-requests: write
135+
136+
steps:
137+
- name: Comment PR with stats
138+
uses: actions/github-script@v7
139+
with:
140+
script: |
141+
const { data: pr } = await github.rest.pulls.get({
142+
owner: context.repo.owner,
143+
repo: context.repo.repo,
144+
pull_number: context.issue.number,
145+
});
146+
147+
const { data: files } = await github.rest.pulls.listFiles({
148+
owner: context.repo.owner,
149+
repo: context.repo.repo,
150+
pull_number: context.issue.number,
151+
});
152+
153+
const additions = pr.additions;
154+
const deletions = pr.deletions;
155+
const changedFiles = pr.changed_files;
156+
const totalChanges = additions + deletions;
157+
158+
let size = 'XS';
159+
if (totalChanges >= 1000) {
160+
size = 'XL';
161+
} else if (totalChanges >= 500) {
162+
size = 'L';
163+
} else if (totalChanges >= 200) {
164+
size = 'M';
165+
} else if (totalChanges >= 50) {
166+
size = 'S';
167+
}
168+
169+
const fileTypes = {};
170+
for (const file of files) {
171+
const ext = file.filename.split('.').pop();
172+
fileTypes[ext] = (fileTypes[ext] || 0) + 1;
173+
}
174+
175+
const fileTypesStr = Object.entries(fileTypes)
176+
.sort((a, b) => b[1] - a[1])
177+
.slice(0, 5)
178+
.map(([ext, count]) => `- ${ext}: ${count} files`)
179+
.join('\n');
180+
181+
let recommendation = 'Great! This PR is easy to review.';
182+
if (totalChanges >= 500) {
183+
recommendation = 'Large PR! Consider splitting into smaller PRs for easier review.';
184+
} else if (totalChanges >= 200) {
185+
recommendation = 'Medium-sized PR. Consider breaking it down if possible.';
186+
}
187+
188+
const commentBody = '## PR Statistics - Size: ' + size + '\n\n' +
189+
'**Total Changes:** ' + totalChanges + ' lines\n\n' +
190+
'### Changes\n' +
191+
'- Additions: ' + additions + ' lines\n' +
192+
'- Deletions: ' + deletions + ' lines\n' +
193+
'- Files changed: ' + changedFiles + '\n\n' +
194+
'### File Types\n' +
195+
fileTypesStr + '\n\n' +
196+
'### Review Recommendations\n' +
197+
recommendation + '\n\n' +
198+
'---\n' +
199+
'*Automated by PR Automation*';
200+
201+
const { data: comments } = await github.rest.issues.listComments({
202+
owner: context.repo.owner,
203+
repo: context.repo.repo,
204+
issue_number: context.issue.number,
205+
});
206+
207+
const botComment = comments.find(comment =>
208+
comment.user.type === 'Bot' &&
209+
comment.body.includes('PR Statistics')
210+
);
211+
212+
if (botComment) {
213+
await github.rest.issues.updateComment({
214+
owner: context.repo.owner,
215+
repo: context.repo.repo,
216+
comment_id: botComment.id,
217+
body: commentBody
218+
});
219+
} else {
220+
await github.rest.issues.createComment({
221+
owner: context.repo.owner,
222+
repo: context.repo.repo,
223+
issue_number: context.issue.number,
224+
body: commentBody
225+
});
226+
}

Simple-Node.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,4 @@ Steps execute sequentially within a job:
9898

9999
If any step fails, subsequent steps are skipped and the workflow fails.
100100

101-
---
101+
---

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
"version": "0.1.0",
44
"private": true,
55
"homepage": "https://kirti.github.io/github-actions-practice",
6+
"author": "Kirti",
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/kirti/github-actions-practice.git"
10+
},
611
"dependencies": {
712
"@testing-library/dom": "^10.4.1",
813
"@testing-library/jest-dom": "^6.9.1",

0 commit comments

Comments
 (0)