-
Notifications
You must be signed in to change notification settings - Fork 0
170 lines (145 loc) · 6.95 KB
/
Copy pathgssoc-labels.yml
File metadata and controls
170 lines (145 loc) · 6.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
name: GSSoC Label Automation
on:
pull_request_target:
types: [opened, reopened, synchronize]
pull_request_review:
types: [submitted]
permissions:
pull-requests: write
contents: read
issues: write
jobs:
auto-type-label:
name: Auto-apply type labels
runs-on: ubuntu-latest
if: github.event_name == 'pull_request_target'
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Detect and apply type labels
uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
const { owner, repo } = context.repo;
const prNumber = pr.number;
const title = pr.title.toLowerCase();
const body = (pr.body || '').toLowerCase();
// Fetch changed files
const filesRes = await github.rest.pulls.listFiles({
owner, repo, pull_number: prNumber, per_page: 100
});
const files = filesRes.data.map(f => f.filename.toLowerCase());
const labelsToAdd = new Set();
// --- Type detection from title ---
if (/^fix|^bug|hotfix/.test(title)) labelsToAdd.add('type:bug');
if (/^feat|^feature|add |implement/.test(title)) labelsToAdd.add('type:feature');
if (/^docs|^doc|readme|changelog|contributing/.test(title)) labelsToAdd.add('type:docs');
if (/^refactor|cleanup|clean up|reorgani/.test(title)) labelsToAdd.add('type:refactor');
if (/test|spec|coverage/.test(title)) labelsToAdd.add('type:testing');
if (/perf|performance|optimi|speed|latency/.test(title)) labelsToAdd.add('type:performance');
if (/a11y|accessibility|aria|wcag|screen.?reader/.test(title)) labelsToAdd.add('type:accessibility');
if (/security|auth|cve|xss|injection|csrf/.test(title)) labelsToAdd.add('type:security');
if (/ci|cd|deploy|docker|kubernetes|workflow|pipeline|devops/.test(title)) labelsToAdd.add('type:devops');
if (/design|ui|ux|theme|style|layout|responsive|dark.?mode/.test(title)) labelsToAdd.add('type:design');
// --- Type detection from files changed ---
const hasMarkdown = files.some(f => f.endsWith('.md') || f.endsWith('.mdx'));
const hasTests = files.some(f =>
f.includes('.test.') || f.includes('.spec.') ||
f.includes('__tests__') || f.includes('/tests/')
);
const hasWorkflow = files.some(f => f.includes('.github/workflows'));
const hasSecurity = files.some(f =>
f.includes('auth') || f.includes('middleware') || f.includes('security')
);
const hasStyle = files.some(f =>
f.endsWith('.css') || f.endsWith('.scss') ||
f.includes('globals') || f.includes('tailwind')
);
if (hasMarkdown) labelsToAdd.add('type:docs');
if (hasTests) labelsToAdd.add('type:testing');
if (hasWorkflow) labelsToAdd.add('type:devops');
if (hasSecurity && !labelsToAdd.has('type:bug') && !labelsToAdd.has('type:feature')) {
labelsToAdd.add('type:security');
}
if (hasStyle && !labelsToAdd.has('type:bug')) labelsToAdd.add('type:design');
// Fetch current labels
const currentLabels = pr.labels.map(l => l.name);
// Always add gssoc26 to every PR
if (!currentLabels.includes('gssoc26')) labelsToAdd.add('gssoc26');
// Only add labels not already present
const newLabels = [...labelsToAdd].filter(l => !currentLabels.includes(l));
if (newLabels.length > 0) {
await github.rest.issues.addLabels({
owner, repo, issue_number: prNumber, labels: newLabels
});
console.log(`Added labels: ${newLabels.join(', ')}`);
}
// Auto-assign PR author to PR
const creator = pr.user.login;
const currentAssignees = pr.assignees.map(a => a.login);
if (!currentAssignees.includes(creator)) {
await github.rest.issues.addAssignees({
owner,
repo,
issue_number: prNumber,
assignees: [creator]
});
console.log(`Assigned PR #${prNumber} to author @${creator}`);
}
- name: Post admin checklist comment
uses: actions/github-script@v9
if: github.event.action == 'opened'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
const { owner, repo } = context.repo;
const body = `## GSSoC Label Checklist 🏷️
@${context.repo.owner} — please apply the appropriate labels before merging:
**Difficulty** (pick one):
- [ ] \`level:beginner\` — 20 pts
- [ ] \`level:intermediate\` — 35 pts
- [ ] \`level:advanced\` — 55 pts
- [ ] \`level:critical\` — 80 pts
**Quality** (optional):
- [ ] \`quality:clean\` — ×1.2 multiplier
- [ ] \`quality:exceptional\` — ×1.5 multiplier
**Validation** (required to score):
- [ ] \`gssoc:approved\` — counts for points
- [ ] \`gssoc:invalid\` / \`gssoc:spam\` / \`gssoc:ai-slop\` — does not score
> Type labels (\`type:*\`) are auto-detected from files and title. Review and adjust if needed.
> Points formula: \`(difficulty × quality_multiplier) + type_bonus\``;
await github.rest.issues.createComment({
owner, repo, issue_number: pr.number, body
});
notify-on-approve:
name: Remind admin to add gssoc:approved
runs-on: ubuntu-latest
if: |
github.event_name == 'pull_request_review' &&
github.event.review.state == 'approved'
steps:
- name: Check for gssoc:approved label
uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
const { owner, repo } = context.repo;
const hasApproved = pr.labels.some(l => l.name === 'gssoc:approved');
const hasDifficulty = pr.labels.some(l => l.name.startsWith('level:'));
if (!hasApproved || !hasDifficulty) {
const missing = [];
if (!hasDifficulty) missing.push('a `level:*` difficulty label');
if (!hasApproved) missing.push('`gssoc:approved`');
await github.rest.issues.createComment({
owner,
repo,
issue_number: pr.number,
body: `PR is approved but missing ${missing.join(' and ')} — add before merging so it scores in GSSoC. 🏷️`
});
}