diff --git a/.github/scripts/unassignIssues.js b/.github/scripts/unassignIssues.js index 9795c554..017d641c 100644 --- a/.github/scripts/unassignIssues.js +++ b/.github/scripts/unassignIssues.js @@ -2,6 +2,11 @@ module.exports = async ({ github, context }) => { const owner = context.repo.owner; const repo = context.repo.repo; + const PROTECTED_ASSIGNEES = [ + 'ShantKhatri', + 'Harxhit' + ]; + // Fetch all open issues (excluding PRs) let page = 1; let issues = []; @@ -15,26 +20,52 @@ module.exports = async ({ github, context }) => { page, }); - const onlyIssues = data.filter(i => !i.pull_request); + const onlyIssues = data.filter( + item => !item.pull_request + ); + issues = issues.concat(onlyIssues); if (data.length < 100) break; page++; } - console.log(`Found ${issues.length} open issue(s) to check.`); + console.log( + `Found ${issues.length} open issue(s) to check.` + ); for (const issue of issues) { const issueNumber = issue.number; - if (!issue.assignees || issue.assignees.length === 0) { + // Skip if no assignees + if ( + !issue.assignees || + issue.assignees.length === 0 + ) { console.log( `Issue #${issueNumber} has no assignees — skipping.` ); continue; } + const assigneeLogins = + issue.assignees.map(a => a.login); + + // Skip protected assignees + const hasProtectedAssignee = + assigneeLogins.some(login => + PROTECTED_ASSIGNEES.includes(login) + ); + + if (hasProtectedAssignee) { + console.log( + `Issue #${issueNumber} has protected assignee(s) — skipping.` + ); + continue; + } + let linkedPRFound = false; + let assignedAt = null; try { const timeline = @@ -45,42 +76,101 @@ module.exports = async ({ github, context }) => { per_page: 100, }); - linkedPRFound = timeline.data.some( - event => + // Check linked PR + linkedPRFound = timeline.data.some(event => { + const pr = event.source?.issue; + + return ( event.event === 'cross-referenced' && - event.source?.issue?.pull_request && - event.source?.issue?.state === 'open' - ); + pr?.pull_request && + pr.state === 'open' + ); + }); + + // Find latest assignment event + const assignEvents = + timeline.data.filter( + event => event.event === 'assigned' + ); + + if (assignEvents.length > 0) { + assignedAt = + assignEvents[ + assignEvents.length - 1 + ].created_at; + } } catch (err) { console.log( `Could not fetch timeline for issue #${issueNumber}: ${err.message}` ); + continue; } - if (!linkedPRFound) { - const assigneeLogins = - issue.assignees.map(a => a.login); + // Skip if no assignment timestamp + if (!assignedAt) { + console.log( + `Issue #${issueNumber} has no assignment timestamp — skipping.` + ); + continue; + } - await github.rest.issues.removeAssignees({ - owner, - repo, - issue_number: issueNumber, - assignees: assigneeLogins, - }); + const assignedDate = + new Date(assignedAt); + const now = new Date(); - const assigneesMention = - assigneeLogins.map(u => `@${u}`).join(', '); + const daysAssigned = + (now - assignedDate) / + (1000 * 60 * 60 * 24); - await github.rest.issues.createComment({ - owner, - repo, - issue_number: issueNumber, - body: `Hey @ShantKhatri (Project Admin) and @Harxhit (Maintainer), + console.log( + `Issue #${issueNumber} assigned for ${daysAssigned.toFixed( + 1 + )} day(s).` + ); -This issue (previously assigned to ${assigneesMention}) has been **automatically unassigned** because no linked pull request was found after the scheduled check. + // Skip if assigned <= 5 days + if (daysAssigned <= 5) { + console.log( + `Issue #${issueNumber} assigned less than 5 days ago — skipping.` + ); + continue; + } -If work is in progress, please open a PR and link it to this issue to keep the assignment.`, - }); + // Skip if linked PR exists + if (linkedPRFound) { + console.log( + `Issue #${issueNumber} has linked open/draft PR — keeping assignment.` + ); + continue; } + + // Remove assignees + await github.rest.issues.removeAssignees({ + owner, + repo, + issue_number: issueNumber, + assignees: assigneeLogins, + }); + + const assigneesMention = + assigneeLogins + .map(user => `@${user}`) + .join(', '); + + // Comment + await github.rest.issues.createComment({ + owner, + repo, + issue_number: issueNumber, + body: `Hey @ShantKhatri (Project Admin) and @Harxhit (Maintainer), + +This issue (previously assigned to ${assigneesMention}) has been **automatically unassigned** because no linked pull request was found within 5 days of assignment. + +If work is in progress, please open and link a PR to keep the assignment active.`, + }); + + console.log( + `Issue #${issueNumber} unassigned successfully.` + ); } -}; \ No newline at end of file +};