Skip to content

Unassign Inactive Contributors #1227

Unassign Inactive Contributors

Unassign Inactive Contributors #1227

name: Unassign Inactive Contributors
on:
schedule:
# Runs every hour
- cron: "0 * * * *"
workflow_dispatch: # Allow manual trigger for testing
permissions:
issues: write
jobs:
unassign-inactive:
runs-on: ubuntu-latest
steps:
- name: Check and unassign inactive contributors
uses: actions/github-script@v7
with:
script: |
const now = new Date();
const WARNING_HOURS = 15;
const UNASSIGN_HOURS = 30;
console.log('🔍 Checking for inactive assigned issues...');
const issues = await github.paginate(
github.rest.issues.listForRepo,
{
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100,
}
);
for (const issue of issues) {
// Skip PRs
if (issue.pull_request) continue;
// Skip unassigned issues
if (!issue.assignees || issue.assignees.length === 0) continue;
const assignedAt = new Date(issue.updated_at);
const hoursInactive = (now - assignedAt) / (1000 * 60 * 60);
console.log(`Issue #${issue.number}: ${hoursInactive.toFixed(1)} hours inactive`);
// Get comments to check for warning
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
});
const hasWarning = comments.some(c =>
c.body && c.body.includes('⏰ Inactivity Warning')
);
const assigneeNames = issue.assignees.map(a => `@${a.login}`).join(', ');
const assigneeLogins = issue.assignees.map(a => a.login);
// Send warning after 15 hours (if not already warned)
if (hoursInactive >= WARNING_HOURS && hoursInactive < UNASSIGN_HOURS && !hasWarning) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `⏰ **Inactivity Warning**
Hi ${assigneeNames}! 👋
This issue has been inactive for **${Math.floor(hoursInactive)} hours**.
Please provide an update within the next **15 hours**, or you may be **automatically unassigned** to give others a chance to contribute.
💡 *If you need more time, just leave a comment to reset the timer!*`
});
console.log(`⚠️ Warning sent for issue #${issue.number}`);
}
// Unassign after 30 hours (only if warning was sent)
if (hoursInactive >= UNASSIGN_HOURS && hasWarning) {
await github.rest.issues.removeAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
assignees: assigneeLogins,
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `🔓 **Unassigned Due to Inactivity**
This issue has been unassigned after **30+ hours of inactivity**.
The issue is now open for others to work on! 🙌
*If you'd like to continue working on this, feel free to comment and request reassignment.*`
});
console.log(`🚫 Unassigned issue #${issue.number}`);
}
}
console.log('✅ Inactivity check complete!');