diff --git a/.github/workflows/close-needs-author-feedback.yml b/.github/workflows/close-needs-author-feedback.yml new file mode 100644 index 00000000..547acf6d --- /dev/null +++ b/.github/workflows/close-needs-author-feedback.yml @@ -0,0 +1,63 @@ +name: Close inactive author feedback issues + +on: + schedule: + - cron: "0 9 * * *" + workflow_dispatch: + +permissions: + contents: read + issues: write + +jobs: + close-inactive: + runs-on: ubuntu-latest + steps: + - name: Close issues waiting on author feedback + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const label = "Needs Author Feedback"; + const daysInactive = 7; + const cutoff = new Date(Date.now() - daysInactive * 24 * 60 * 60 * 1000); + + const { owner, repo } = context.repo; + const issues = await github.paginate(github.rest.issues.listForRepo, { + owner, + repo, + state: "open", + labels: label, + per_page: 100, + sort: "updated", + direction: "asc", + }); + + for (const issue of issues) { + if (issue.pull_request) { + continue; + } + + const updatedAt = new Date(issue.updated_at); + if (updatedAt > cutoff) { + continue; + } + + const body = [ + "We haven't heard back in 7 days, so we're automatically closing this issue.", + "If you still need help, please reply and we can reopen it." + ].join("\n\n"); + + try { + await github.rest.issues.createComment({ owner, repo, issue_number: issue.number, body }); + } catch (error) { + console.warn(`Skipping issue #${issue.number} because of an error while adding the notice: ${error}`); + continue; + } + + try { + await github.rest.issues.update({ owner, repo, issue_number: issue.number, state: "closed" }); + } catch (error) { + console.warn(`Skipping issue #${issue.number} because of an error while processing closure: ${error}`); + } + }