Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 118 additions & 28 deletions .github/scripts/unassignIssues.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand All @@ -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 =
Expand All @@ -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.`
);
}
};
};