-
-
Notifications
You must be signed in to change notification settings - Fork 270
156 lines (136 loc) · 6.45 KB
/
weekly-star-check.yml
File metadata and controls
156 lines (136 loc) · 6.45 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
name: Weekly Star Check
on:
schedule:
- cron: '0 0 * * 0' # Every Sunday at midnight UTC
workflow_dispatch: # Allow manual trigger
permissions:
pull-requests: write
contents: read
jobs:
check-all-prs:
runs-on: ubuntu-latest
steps:
- name: Check stars for all open PRs
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const LABEL_AWAITING_STAR = 'awaiting-star';
const LABEL_MERGE_CONFLICT = 'merge-conflict';
const LABEL_READY_TO_MERGE = 'ready-to-merge';
const labels = [
{ name: LABEL_AWAITING_STAR, color: 'fbca04', description: 'PR author has not starred the repository' },
{ name: LABEL_MERGE_CONFLICT, color: 'd93f0b', description: 'PR has merge conflicts' },
{ name: LABEL_READY_TO_MERGE, color: '0e8a16', description: 'PR is ready to be merged' }
];
// Ensure all labels exist
for (const label of labels) {
try {
await github.rest.issues.getLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label.name
});
} catch (e) {
if (e.status === 404) {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
...label
});
}
}
}
// Get all open PRs
const prs = await github.paginate(github.rest.pulls.list, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100
});
console.log(`Found ${prs.length} open PRs`);
// Get all stargazers
const stargazers = await github.paginate(github.rest.activity.listStargazersForRepo, {
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
});
const stargazerLogins = new Set(stargazers.map(s => s.login));
console.log(`Found ${stargazerLogins.size} stargazers`);
// Helper to add/remove labels
async function addLabel(prNumber, labelName) {
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: [labelName]
});
} catch (e) { console.log(`Failed to add label ${labelName}: ${e.message}`); }
}
async function removeLabel(prNumber, labelName) {
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: labelName
});
} catch (e) { /* Label might not exist */ }
}
for (const pr of prs) {
const prAuthor = pr.user.login;
const hasStarred = stargazerLogins.has(prAuthor);
const currentLabels = pr.labels.map(l => l.name);
// Fetch full PR details for mergeable status
const prDetails = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number
});
const mergeable = prDetails.data.mergeable;
const hasConflict = mergeable === false;
// Handle awaiting-star label
if (!hasStarred && !currentLabels.includes(LABEL_AWAITING_STAR)) {
await addLabel(pr.number, LABEL_AWAITING_STAR);
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number
});
const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('please star this repository')
);
if (!botComment) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: `👋 Hey @${prAuthor}, friendly reminder!\n\nIt looks like you haven't starred this repository yet. Please ⭐ **star this repository** before your PR can be merged.\n\nOnce you've starred the repo, comment \`/recheck\` to verify.`
});
}
console.log(`❌ PR #${pr.number} by ${prAuthor} - not starred`);
} else if (hasStarred && currentLabels.includes(LABEL_AWAITING_STAR)) {
await removeLabel(pr.number, LABEL_AWAITING_STAR);
console.log(`✅ PR #${pr.number} by ${prAuthor} - now starred, label removed`);
}
// Handle merge-conflict label
if (hasConflict && !currentLabels.includes(LABEL_MERGE_CONFLICT)) {
await addLabel(pr.number, LABEL_MERGE_CONFLICT);
await removeLabel(pr.number, LABEL_READY_TO_MERGE);
console.log(`⚠️ PR #${pr.number} - has merge conflicts`);
} else if (!hasConflict && currentLabels.includes(LABEL_MERGE_CONFLICT)) {
await removeLabel(pr.number, LABEL_MERGE_CONFLICT);
}
// Handle ready-to-merge label (starred + no conflicts)
if (hasStarred && mergeable === true) {
if (!currentLabels.includes(LABEL_READY_TO_MERGE)) {
await addLabel(pr.number, LABEL_READY_TO_MERGE);
await removeLabel(pr.number, LABEL_MERGE_CONFLICT);
console.log(`🚀 PR #${pr.number} by ${prAuthor} - ready to merge`);
}
} else if (currentLabels.includes(LABEL_READY_TO_MERGE)) {
await removeLabel(pr.number, LABEL_READY_TO_MERGE);
}
}