1+ name : Close stale PRs with failed workflows
2+
3+ on :
4+ schedule :
5+ - cron : ' 0 3 * * *' # runs daily at 03:00 UTC
6+ workflow_dispatch :
7+
8+ permissions :
9+ contents : read
10+ issues : write
11+ pull-requests : write
12+
13+ jobs :
14+ close-stale :
15+ runs-on : ubuntu-latest
16+ steps :
17+ - name : Close stale PRs
18+ uses : actions/github-script@v7
19+ with :
20+ github-token : ${{ secrets.GITHUB_TOKEN }}
21+ script : |
22+ const mainBranches = ['main', 'master'];
23+ const cutoffDays = 14;
24+ const cutoff = new Date();
25+ cutoff.setDate(cutoff.getDate() - cutoffDays);
26+
27+ const { data: prs } = await github.rest.pulls.list({
28+ owner: context.repo.owner,
29+ repo: context.repo.repo,
30+ state: 'open',
31+ per_page: 100
32+ });
33+
34+ for (const pr of prs) {
35+ const updated = new Date(pr.updated_at);
36+ if (updated > cutoff) continue;
37+
38+ const commits = await github.paginate(github.rest.pulls.listCommits, {
39+ owner: context.repo.owner,
40+ repo: context.repo.repo,
41+ pull_number: pr.number,
42+ per_page: 100
43+ });
44+
45+ const meaningfulCommits = commits.filter(c => {
46+ const msg = c.commit.message.toLowerCase();
47+ const isMergeFromMain = mainBranches.some(branch =>
48+ msg.startsWith(`merge branch '${branch}'`) ||
49+ msg.includes(`merge remote-tracking branch '${branch}'`)
50+ );
51+ return !isMergeFromMain;
52+ });
53+
54+ const { data: checks } = await github.rest.checks.listForRef({
55+ owner: context.repo.owner,
56+ repo: context.repo.repo,
57+ ref: pr.head.sha
58+ });
59+
60+ const hasFailed = checks.check_runs.some(c => c.conclusion === 'failure');
61+ const allCompleted = checks.check_runs.every(c => c.status === 'completed');
62+
63+ if (meaningfulCommits.length === 0 && hasFailed && allCompleted) {
64+ console.log(`Closing PR #${pr.number} (${pr.title})`);
65+
66+ await github.rest.issues.createComment({
67+ owner: context.repo.owner,
68+ repo: context.repo.repo,
69+ issue_number: pr.number,
70+ body: `This pull request has been automatically closed because its workflows failed and it has been inactive for more than ${cutoffDays} days. Please fix the workflows and reopen if you'd like to continue. Merging from main/master alone does not count as activity.`
71+ });
72+
73+ await github.rest.pulls.update({
74+ owner: context.repo.owner,
75+ repo: context.repo.repo,
76+ pull_number: pr.number,
77+ state: 'closed'
78+ });
79+ }
80+ }
0 commit comments