From 2d74486818354b15849961a0a0dc3e4468191aaf Mon Sep 17 00:00:00 2001 From: Daniel Hegberg Date: Thu, 7 May 2026 15:25:14 -0700 Subject: [PATCH] ci(workflows): Add issue management automations Add stale issue cleanup, closed issue message with lock, unlock on reopen, and regression labeler workflows. These automations keep the issue tracker healthy by closing unresponsive issues, preventing thread hijacking on closed issues, and auto-labeling regressions for priority escalation. --- .github/workflows/close-stale-issues.yml | 26 ++++++++++ .github/workflows/closed-issue-message.yml | 39 +++++++++++++++ .../workflows/issue-regression-labeler.yml | 49 +++++++++++++++++++ .github/workflows/unlock-reopened-issue.yml | 21 ++++++++ 4 files changed, 135 insertions(+) create mode 100644 .github/workflows/close-stale-issues.yml create mode 100644 .github/workflows/closed-issue-message.yml create mode 100644 .github/workflows/issue-regression-labeler.yml create mode 100644 .github/workflows/unlock-reopened-issue.yml diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml new file mode 100644 index 00000000..a1d4aef2 --- /dev/null +++ b/.github/workflows/close-stale-issues.yml @@ -0,0 +1,26 @@ +name: Close Stale Issues + +on: + schedule: + - cron: "0 */6 * * *" + +permissions: + issues: write + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - uses: aws-actions/stale-issue-cleanup@v6 + with: + response-requested-label: response-requested + days-before-stale: 7 + days-before-close: 5 + stale-issue-label: closing-soon + stale-issue-message: | + This issue has not received a response in 7 days. If no further activity occurs within the next 5 days, it will be automatically closed. + close-issue-message: | + Closing this issue due to inactivity. If you believe this is still relevant, please open a new issue with updated information. + minimum-upvotes-to-exempt: 5 + exempt-issue-labels: "bug,feature-request,p1" + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/closed-issue-message.yml b/.github/workflows/closed-issue-message.yml new file mode 100644 index 00000000..94c735b2 --- /dev/null +++ b/.github/workflows/closed-issue-message.yml @@ -0,0 +1,39 @@ +name: Closed Issue Message + +on: + issues: + types: [closed] + pull_request_target: + types: [closed] + +permissions: + issues: write + pull-requests: write + +jobs: + post-message-and-lock: + runs-on: ubuntu-latest + steps: + - uses: aws-actions/closed-issue-message@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: | + ⚠️ This issue has been closed. If you have a similar problem, please [open a new issue](../../issues/new/choose) and include relevant details so we can investigate properly. + + Comments on closed issues are hard for our team to track. A new issue ensures you get the attention you need. + pr-message: | + ⚠️ This pull request has been closed. If you'd like to continue this work, please open a new PR referencing this one for context. + + - uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const number = context.issue?.number || context.payload.pull_request?.number; + if (number) { + await github.rest.issues.lock({ + owner, + repo, + issue_number: number, + lock_reason: 'resolved' + }); + } diff --git a/.github/workflows/issue-regression-labeler.yml b/.github/workflows/issue-regression-labeler.yml new file mode 100644 index 00000000..301c40e3 --- /dev/null +++ b/.github/workflows/issue-regression-labeler.yml @@ -0,0 +1,49 @@ +name: Issue Regression Labeler + +on: + issues: + types: [opened, edited] + +permissions: + issues: write + +jobs: + label-regression: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: | + const body = context.payload.issue.body || ''; + const issueNumber = context.issue.number; + const { owner, repo } = context.repo; + + // Detect regression from checkbox format or dropdown format + const checkboxChecked = /- \[x\].*regression/i.test(body); + const dropdownYes = /### Is this a regression\?\s*\n\s*Yes/i.test(body); + const regressionChecked = checkboxChecked || dropdownYes; + + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number: issueNumber + }); + const hasRegressionLabel = labels.some(l => l.name === 'regression'); + + if (regressionChecked && !hasRegressionLabel) { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: issueNumber, + labels: ['regression', 'p1'] + }); + core.info(`Labeled issue #${issueNumber} as regression + p1`); + } else if (!regressionChecked && hasRegressionLabel) { + await github.rest.issues.removeLabel({ + owner, + repo, + issue_number: issueNumber, + name: 'regression' + }); + core.info(`Removed regression label from issue #${issueNumber}`); + } diff --git a/.github/workflows/unlock-reopened-issue.yml b/.github/workflows/unlock-reopened-issue.yml new file mode 100644 index 00000000..619cf60c --- /dev/null +++ b/.github/workflows/unlock-reopened-issue.yml @@ -0,0 +1,21 @@ +name: Unlock Reopened Issues + +on: + issues: + types: [reopened] + +permissions: + issues: write + +jobs: + unlock: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.unlock({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + });