forked from keyshade-xyz/keyshade
-
Notifications
You must be signed in to change notification settings - Fork 0
172 lines (138 loc) · 7.13 KB
/
issue-pr-reminder.yaml
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
171
172
name: Issue PR Reminder
on:
schedule:
- cron: '0 * * * *' # Runs every hour
jobs:
issue-pr-reminder:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
env:
CREATE_ISSUE_PR_REMINDER_ENABLED: ${{ vars.CREATE_ISSUE_PR_REMINDER_ENABLED }}
CREATE_ISSUE_PR_REMINDER_AFTER_ISSUE_ASSIGNED_DAYS: ${{ vars.CREATE_ISSUE_PR_REMINDER_AFTER_ISSUE_ASSIGNED_DAYS }}
CREATE_ISSUE_PR_REMINDER_BEFORE_ISSUE_UNASSIGNED_DAYS: ${{ vars.CREATE_ISSUE_PR_REMINDER_BEFORE_ISSUE_UNASSIGNED_DAYS }}
UNASSIGN_ISSUE_AFTER_DAYS: ${{ vars.UNASSIGN_ISSUE_AFTER_DAYS }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const owner = 'keyshade-xyz';
const repo = 'keyshade';
const createPrReminderEnabled = process.env.CREATE_ISSUE_PR_REMINDER_ENABLED || false;
const createPrReminderAfterIssueAssignedDays = process.env.CREATE_ISSUE_PR_REMINDER_AFTER_ISSUE_ASSIGNED_DAYS || 2;
const createPrReminderBeforeIssueUnassignedDays = process.env.CREATE_ISSUE_PR_REMINDER_BEFORE_ISSUE_UNASSIGNED_DAYS || 2;
const unassignIssueAfterDays = process.env.UNASSIGN_ISSUE_AFTER_DAYS || 14;
const createPrReminderAfterIssueAssignedMilliseconds = createPrReminderAfterIssueAssignedDays * 24 * 60 * 60 * 1000;
const createPrReminderBeforeIssueUnassignedMilliseconds = createPrReminderBeforeIssueUnassignedDays * 24 * 60 * 60 * 1000;
const unassignIssueAfterMilliseconds = unassignIssueAfterDays * 24 * 60 * 60 * 1000;
const now = Date.now();
if(!createPrReminderEnabled) {
console.log('!!! Dry run, there are no changes made !!!');
}
async function listOpenIssues() {
const issues = [];
let page = 1;
let hasNextPage = true;
while (hasNextPage) {
const issuesResponse = await github.rest.issues.listForRepo({
owner,
repo,
state: 'open',
per_page: 100,
page
});
issues.push(...issuesResponse.data);
hasNextPage = issuesResponse.headers.link && issuesResponse.headers.link.includes('rel="next"');
page++;
}
return issues;
}
async function listIssueEvents(issue) {
const events = [];
let page = 1;
let hasNextPage = true;
while (hasNextPage) {
const eventsResponse = await github.rest.issues.listEventsForTimeline({
owner,
repo,
issue_number: issue.number,
per_page: 100,
page
});
events.push(...eventsResponse.data);
hasNextPage = eventsResponse.headers.link && eventsResponse.headers.link.includes('rel="next"');
page++;
}
return events.sort((a, b) => a.id > b.id);
}
async function listIssueComments(issue) {
const comments = [];
let page = 1;
let hasNextPage = true;
while (hasNextPage) {
const commentsResponse = await github.rest.issues.listComments({
owner,
repo,
issue_number: issue.number,
per_page: 100,
page
});
comments.push(...commentsResponse.data);
hasNextPage = commentsResponse.headers.link && commentsResponse.headers.link.includes('rel="next"');
page++;
}
return comments;
}
async function createPrReminder(assignee, issueNumber, comments, createPrReminderAfter, prReminder) {
// Check if it is time to create PR reminder
if (now < createPrReminderAfter) {
return false;
}
// Check if PR reminder has already been created
if (comments.some(comment => comment.body === prReminder)) {
return false;
}
// Create PR reminder
if(createPrReminderEnabled) {
await github.rest.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: prReminder
});
}
console.log(`Issue '${issueNumber}' PR reminder created for: ${assignee.login}`);
return true;
}
async function createPrReminders() {
const issues = await listOpenIssues();
for (const issue of issues) {
const events = await listIssueEvents(issue);
const pullRequests = events
.filter(event => event.event === 'cross-referenced')
.map(event => event.source.issue)
.filter(issue => issue && issue.pull_request);
const comments = await listIssueComments(issue);
for (const assignee of issue.assignees) {
const assignedEvent = events.find(event => event.event === 'assigned' && event.assignee.login === assignee.login);
const issueAssignedAt = new Date(assignedEvent.created_at);
// Check if assignee has already opened a PR
const assigneePullRequest = pullRequests.find(pullRequest => pullRequest.user.login === assignee.login);
if(assigneePullRequest) {
continue;
}
// Create first PR reminder
const createFirstPrReminderAfter = new Date(issueAssignedAt.getTime() + createPrReminderAfterIssueAssignedMilliseconds);
const firstPrReminder = `@${assignee.login}, please open a draft PR linking this issue!`;
const isFirstPrReminderCreated = await createPrReminder(assignee, issue.number, comments, createFirstPrReminderAfter, firstPrReminder);
if(isFirstPrReminderCreated) {
continue;
}
// Create final PR reminder
const unassignIssueAfter = new Date(issueAssignedAt.getTime() + unassignIssueAfterMilliseconds);
const createFinalPrReminderAfter = new Date(issueAssignedAt.getTime() + unassignIssueAfterMilliseconds - createPrReminderBeforeIssueUnassignedMilliseconds);
const finalPrReminder = `@${assignee.login}, please open a draft PR linking this issue; otherwise you will be unassigned from this issue after ${unassignIssueAfter}!`;
await createPrReminder(assignee, issue.number, comments, createFinalPrReminderAfter, finalPrReminder);
}
}
}
await createPrReminders();