Skip to content

Commit 02320c0

Browse files
authored
fix(workflow): add 5-day assignment check and protected assignee handling (#386)
* fix: Fixed linting issues * fix(workflow): add 5-day assignment check and protected assignee handling
1 parent 42ee1ac commit 02320c0

1 file changed

Lines changed: 118 additions & 28 deletions

File tree

.github/scripts/unassignIssues.js

Lines changed: 118 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ module.exports = async ({ github, context }) => {
22
const owner = context.repo.owner;
33
const repo = context.repo.repo;
44

5+
const PROTECTED_ASSIGNEES = [
6+
'ShantKhatri',
7+
'Harxhit'
8+
];
9+
510
// Fetch all open issues (excluding PRs)
611
let page = 1;
712
let issues = [];
@@ -15,26 +20,52 @@ module.exports = async ({ github, context }) => {
1520
page,
1621
});
1722

18-
const onlyIssues = data.filter(i => !i.pull_request);
23+
const onlyIssues = data.filter(
24+
item => !item.pull_request
25+
);
26+
1927
issues = issues.concat(onlyIssues);
2028

2129
if (data.length < 100) break;
2230
page++;
2331
}
2432

25-
console.log(`Found ${issues.length} open issue(s) to check.`);
33+
console.log(
34+
`Found ${issues.length} open issue(s) to check.`
35+
);
2636

2737
for (const issue of issues) {
2838
const issueNumber = issue.number;
2939

30-
if (!issue.assignees || issue.assignees.length === 0) {
40+
// Skip if no assignees
41+
if (
42+
!issue.assignees ||
43+
issue.assignees.length === 0
44+
) {
3145
console.log(
3246
`Issue #${issueNumber} has no assignees — skipping.`
3347
);
3448
continue;
3549
}
3650

51+
const assigneeLogins =
52+
issue.assignees.map(a => a.login);
53+
54+
// Skip protected assignees
55+
const hasProtectedAssignee =
56+
assigneeLogins.some(login =>
57+
PROTECTED_ASSIGNEES.includes(login)
58+
);
59+
60+
if (hasProtectedAssignee) {
61+
console.log(
62+
`Issue #${issueNumber} has protected assignee(s) — skipping.`
63+
);
64+
continue;
65+
}
66+
3767
let linkedPRFound = false;
68+
let assignedAt = null;
3869

3970
try {
4071
const timeline =
@@ -45,42 +76,101 @@ module.exports = async ({ github, context }) => {
4576
per_page: 100,
4677
});
4778

48-
linkedPRFound = timeline.data.some(
49-
event =>
79+
// Check linked PR
80+
linkedPRFound = timeline.data.some(event => {
81+
const pr = event.source?.issue;
82+
83+
return (
5084
event.event === 'cross-referenced' &&
51-
event.source?.issue?.pull_request &&
52-
event.source?.issue?.state === 'open'
53-
);
85+
pr?.pull_request &&
86+
pr.state === 'open'
87+
);
88+
});
89+
90+
// Find latest assignment event
91+
const assignEvents =
92+
timeline.data.filter(
93+
event => event.event === 'assigned'
94+
);
95+
96+
if (assignEvents.length > 0) {
97+
assignedAt =
98+
assignEvents[
99+
assignEvents.length - 1
100+
].created_at;
101+
}
54102
} catch (err) {
55103
console.log(
56104
`Could not fetch timeline for issue #${issueNumber}: ${err.message}`
57105
);
106+
continue;
58107
}
59108

60-
if (!linkedPRFound) {
61-
const assigneeLogins =
62-
issue.assignees.map(a => a.login);
109+
// Skip if no assignment timestamp
110+
if (!assignedAt) {
111+
console.log(
112+
`Issue #${issueNumber} has no assignment timestamp — skipping.`
113+
);
114+
continue;
115+
}
63116

64-
await github.rest.issues.removeAssignees({
65-
owner,
66-
repo,
67-
issue_number: issueNumber,
68-
assignees: assigneeLogins,
69-
});
117+
const assignedDate =
118+
new Date(assignedAt);
119+
const now = new Date();
70120

71-
const assigneesMention =
72-
assigneeLogins.map(u => `@${u}`).join(', ');
121+
const daysAssigned =
122+
(now - assignedDate) /
123+
(1000 * 60 * 60 * 24);
73124

74-
await github.rest.issues.createComment({
75-
owner,
76-
repo,
77-
issue_number: issueNumber,
78-
body: `Hey @ShantKhatri (Project Admin) and @Harxhit (Maintainer),
125+
console.log(
126+
`Issue #${issueNumber} assigned for ${daysAssigned.toFixed(
127+
1
128+
)} day(s).`
129+
);
79130

80-
This issue (previously assigned to ${assigneesMention}) has been **automatically unassigned** because no linked pull request was found after the scheduled check.
131+
// Skip if assigned <= 5 days
132+
if (daysAssigned <= 5) {
133+
console.log(
134+
`Issue #${issueNumber} assigned less than 5 days ago — skipping.`
135+
);
136+
continue;
137+
}
81138

82-
If work is in progress, please open a PR and link it to this issue to keep the assignment.`,
83-
});
139+
// Skip if linked PR exists
140+
if (linkedPRFound) {
141+
console.log(
142+
`Issue #${issueNumber} has linked open/draft PR — keeping assignment.`
143+
);
144+
continue;
84145
}
146+
147+
// Remove assignees
148+
await github.rest.issues.removeAssignees({
149+
owner,
150+
repo,
151+
issue_number: issueNumber,
152+
assignees: assigneeLogins,
153+
});
154+
155+
const assigneesMention =
156+
assigneeLogins
157+
.map(user => `@${user}`)
158+
.join(', ');
159+
160+
// Comment
161+
await github.rest.issues.createComment({
162+
owner,
163+
repo,
164+
issue_number: issueNumber,
165+
body: `Hey @ShantKhatri (Project Admin) and @Harxhit (Maintainer),
166+
167+
This issue (previously assigned to ${assigneesMention}) has been **automatically unassigned** because no linked pull request was found within 5 days of assignment.
168+
169+
If work is in progress, please open and link a PR to keep the assignment active.`,
170+
});
171+
172+
console.log(
173+
`Issue #${issueNumber} unassigned successfully.`
174+
);
85175
}
86-
};
176+
};

0 commit comments

Comments
 (0)