NuvioMobile/.github/workflows/close-stale-issues.yml
2026-07-15 15:36:32 +05:30

103 lines
3.3 KiB
YAML

name: Close inactive bug issues
on:
schedule:
- cron: "29 6 * * *" # daily
workflow_dispatch:
inputs:
dry_run:
description: Log matching issues without commenting or closing them
required: false
type: boolean
default: false
permissions:
issues: write
jobs:
close_stale:
runs-on: ubuntu-latest
steps:
- name: Close bug issues inactive longer than 30 days
uses: actions/github-script@v7
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const inputs = context.payload.inputs || {};
const dryRun = String(inputs.dry_run || "false").toLowerCase() === "true";
const CLOSE_AFTER_DAYS = 30;
const closeMarker = "<!-- nuvio-bot:close-stale-issue -->";
const cutoff = new Date(Date.now() - CLOSE_AFTER_DAYS * 24 * 60 * 60 * 1000)
.toISOString()
.slice(0, 10);
const items = await github.paginate(github.rest.search.issuesAndPullRequests, {
// Staleness is inactivity, not issue age. Do not close an old issue
// that has had recent discussion or edits.
q: `repo:${owner}/${repo} is:issue is:open label:bug updated:<${cutoff}`,
per_page: 100,
});
core.info(`Found ${items.length} bug issues inactive for ${CLOSE_AFTER_DAYS} days.`);
async function hasBeenReopened(issue_number) {
const events = await github.paginate(github.rest.issues.listEvents, {
owner,
repo,
issue_number,
per_page: 100,
});
return events.some(event => event.event === "reopened");
}
for (const item of items) {
const issue_number = item.number;
if (await hasBeenReopened(issue_number)) {
core.info(`#${issue_number}: skipping because it was manually reopened.`);
continue;
}
if (dryRun) {
core.info(`#${issue_number}: would comment and close.`);
continue;
}
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number,
per_page: 100,
});
const alreadyCommented = comments.some(comment =>
(comment.body || "").includes(closeMarker)
);
if (!alreadyCommented) {
const body =
`${closeMarker}\n` +
`Closing this bug report because it has had no activity for more than 30 days.\n\n` +
`If this is still relevant, please open a fresh issue with the latest details.`;
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}
await github.rest.issues.update({
owner,
repo,
issue_number,
state: "closed",
state_reason: "not_planned",
});
core.info(`#${issue_number}: closed.`);
}