Assign and Unassign Issues #8639
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Assign and Unassign Issues | |
on: | |
schedule: | |
- cron: '30 9,21 * * *' | |
issue_comment: | |
types: [created] | |
workflow_dispatch: | |
env: | |
DAYS_UNTIL_STALE: 20 # Number of days before marking as stale | |
ASSIGNED_LABEL: "π Assigned" | |
PINNED_LABEL: "π Pinned" | |
STALE_LABEL: "Stale" | |
jobs: | |
assign_issue: | |
if: github.event_name == 'issue_comment' | |
runs-on: ubuntu-latest | |
steps: | |
- name: Check for /assign-me comment | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const { owner, repo } = context.repo; | |
const issue_number = context.issue.number; | |
const comment = context.payload.comment.body; | |
const totalDays = process.env.DAYS_UNTIL_STALE; | |
const assignedLabel = process.env.ASSIGNED_LABEL; | |
const pinnedLabel = process.env.PINNED_LABEL; | |
async function addComment(body) { | |
await github.rest.issues.createComment({ owner, repo, issue_number, body }); | |
} | |
async function addLabels(labels) { | |
await github.rest.issues.addLabels({ owner, repo, issue_number, labels }); | |
} | |
if (comment.includes('/assign-me')) { | |
try { | |
// Get the current issue details | |
const issue = await github.rest.issues.get({ owner, repo, issue_number }); | |
if (issue.data.assignees.length === 0) { | |
// Issue is not assigned, proceed with assignment | |
await github.rest.issues.addAssignees({ owner, repo, issue_number, assignees: [context.actor] }); | |
// Add the 'π Assigned' label to the issue | |
await addLabels([assignedLabel]); | |
// Add the custom comment to notify the user of the assignment | |
const successMessage = `π Hey @${context.actor}, thanks for your interest in this issue! π\n\n` | |
+ `β Note that this issue will become unassigned if it isn't closed within **${totalDays} days**.\n\n` | |
+ `π§ A maintainer can also add the **${pinnedLabel}** label to prevent it from being unassigned automatically.`; | |
await addComment(successMessage); | |
console.log(`Assigned issue #${issue_number} to ${context.actor}`); | |
} else { | |
// Issue is already assigned | |
const currentAssignee = issue.data.assignees[0].login; | |
const alreadyAssignedMessage = `π Hey @${context.actor}, this issue is already assigned to @${currentAssignee}.\n\n` | |
+ `β οΈ It will become unassigned if it isn't closed within **${totalDays} days**.\n\n` | |
+ `π§ A maintainer can also add you to the list of assignees or swap you with the current assignee.`; | |
await addComment(alreadyAssignedMessage); | |
console.log(`Failed to assign issue #${issue_number} to ${context.actor} as it's already assigned to ${currentAssignee}`); | |
} | |
} catch (error) { | |
console.error(`Error assigning issue #${issue_number}: ${error.message}`); | |
} | |
} | |
unassign_stale: | |
if: github.event_name == 'schedule' | |
runs-on: ubuntu-latest | |
steps: | |
- name: Mark stale issues | |
uses: actions/stale@v9 | |
with: | |
repo-token: ${{ secrets.GITHUB_TOKEN }} | |
stale-issue-message: "This issue has been automatically unassigned due to inactivity." | |
days-before-stale: ${{ env.DAYS_UNTIL_STALE }} # Number of days before marking as stale | |
days-before-close: -1 # Don't close stale issues | |
exempt-issue-labels: ${{ env.PINNED_LABEL }} | |
remove-stale-when-updated: false | |
include-only-assigned: true | |
- name: Unassign stale issues and remove labels | |
uses: actions/github-script@v7 | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
script: | | |
const { owner, repo } = context.repo; | |
const assignedLabel = process.env.ASSIGNED_LABEL; | |
const staleLabel = process.env.STALE_LABEL; | |
async function removeLabel(issue_number, name) { | |
try { | |
await github.rest.issues.removeLabel({ owner, repo, issue_number, name }); | |
} catch (error) { | |
console.log(`Failed to remove ${name} label from issue #${issue_number}: ${error.message}`); | |
} | |
} | |
const staleIssues = await github.paginate(github.rest.issues.listForRepo, { | |
owner, repo, | |
state: 'open', | |
labels: staleLabel | |
}); | |
for (const issue of staleIssues) { | |
try { | |
// Remove assignees | |
await github.rest.issues.removeAssignees({ | |
owner, repo, issue_number: issue.number, | |
assignees: issue.assignees.map(a => a.login) | |
}); | |
// Remove 'Assigned' and 'Stale' labels | |
await removeLabel(issue.number, assignedLabel); | |
await removeLabel(issue.number, staleLabel); | |
console.log(`Unassigned issue #${issue.number}`); | |
} catch (error) { | |
console.error(`Error unassigning issue #${issue.number}: ${error.message}`); | |
} | |
} |