Skip to content

Unassign Issues with No PR After 7 Days #101

Unassign Issues with No PR After 7 Days

Unassign Issues with No PR After 7 Days #101

name: Unassign Issues with No PR After 7 Days
on:
schedule:
- cron: '0 2 * * *' # Runs daily at 2 AM UTC
workflow_dispatch: # Manual trigger support
jobs:
unassign-stale-issues:
runs-on: ubuntu-latest
steps:
- name: Check for stale assigned issues
uses: actions/github-script@v7
with:
github-token: ${{ secrets.PAT }}
script: |
const daysBeforeUnassign = 7;
const now = new Date();
// Get all open issues with assignees
const issues = await github.paginate(github.rest.issues.listForRepo, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
assignee: '*'
});
for (const issue of issues) {
if (issue.pull_request) continue; // Skip PRs
// Get timeline events to find assignment and PR link events
const timeline = await github.paginate(github.rest.issues.listEventsForTimeline, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
mediaType: { previews: ["mockingbird"] }
});
// Find the first assignment event date
const assignedEvent = timeline.filter(e => e.event === 'assigned').at(-1);// latest
if (!assignedEvent) {
// No assignment event found, skip issue
continue;
}
const assignedAt = new Date(assignedEvent.created_at);
// Find the first PR linked event date
const prLinkedEvent = timeline
.filter(
e =>
['connected', 'cross-referenced'].includes(e.event) &&
new Date(e.created_at) >= assignedAt
)
.at(0); // earliest link *after* assignment
const prLinkedAt = prLinkedEvent ? new Date(prLinkedEvent.created_at) : null;
// Calculate days since assignment
const daysSinceAssignment = (now - assignedAt) / (1000 * 60 * 60 * 24);
// Check if issue is still assigned (in case assignees changed later)
const currentlyAssigned = issue.assignees.length > 0;
if (currentlyAssigned && daysSinceAssignment >= daysBeforeUnassign) {
// If PR not linked or linked after 7 days
if (!prLinkedAt || prLinkedAt > new Date(assignedAt.getTime() + daysBeforeUnassign * 24 * 60 * 60 * 1000)) {
console.log(`Unassigning issue #${issue.number} - no PR linked within ${daysBeforeUnassign} days of assignment.`);
// Remove assignees
await github.rest.issues.removeAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
assignees: issue.assignees.map(user => user.login)
});
// Post comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `⏰ This issue was automatically unassigned because no pull request was linked within ${daysBeforeUnassign} days of assignment. Please request reassignment if you are still working on it.`
});
}
}
}