Skip to content

Commit df302e6

Browse files
jamietannagpt-4.1
andauthored
ci: auto-lock discussions and auto-close after 30 days (#39311)
As noted in #39212, it would be useful to prevent "bumping" of old Discussions. Because `lock-threads` does not have the ability to perform the closing itself[0], we can write a small `github-script` compatible script. This will loop through all answered but open Discussions, and close them (if it's been 30 days since they were answered). We also make sure that `lock-threads` will then lock the Discussions once they're closed. Closes #39212. [0]: dessant/lock-threads#45 Co-authored-by: gpt-4.1 <[email protected]>
1 parent 28a5417 commit df302e6

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Close answered discussions
2+
3+
permissions:
4+
discussions: write
5+
6+
on:
7+
# run daily
8+
schedule:
9+
- cron: '0 0 * * *'
10+
11+
# allow manual trigger
12+
workflow_dispatch:
13+
14+
jobs:
15+
close-answered-discussions:
16+
runs-on: ubuntu-latest
17+
if: github.repository == 'renovatebot/renovate'
18+
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
22+
with:
23+
show-progress: false
24+
25+
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
26+
with:
27+
script: |
28+
const script = require('.github/workflows/close-answered-discussions/script.js')
29+
console.log(await script({github, context, discussionAnsweredDays: 30}))
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Parses the ISO date string and checks it's past the age window
2+
// Co-authored-by: GPT-4.1 (GitHub Copilot)
3+
function isOlderThanDaysAgo(dateString, daysAgo) {
4+
const parsedDate = new Date(dateString);
5+
const now = new Date();
6+
const thresholdDate = new Date(now.getTime() - daysAgo * 24 * 60 * 60 * 1000);
7+
return parsedDate < thresholdDate;
8+
}
9+
10+
module.exports = async ({ github, context, discussionAnsweredDays }) => {
11+
const owner = context.repo.owner;
12+
const repo = context.repo.repo;
13+
14+
let cursor = null;
15+
16+
const query = `query ($cursor: String) {
17+
repository(owner: "${owner}", name: "${repo}") {
18+
discussions(after: $cursor, states: OPEN, answered: true, first: 50, orderBy: {field: CREATED_AT, direction: ASC}) {
19+
pageInfo {
20+
endCursor
21+
hasNextPage
22+
}
23+
edges {
24+
node {
25+
id
26+
answerChosenAt
27+
}
28+
}
29+
}
30+
}
31+
}`;
32+
33+
while (true) {
34+
console.debug({ cursor }, 'Starting query');
35+
const { repository } = await github.graphql(query, { cursor });
36+
37+
console.debug(
38+
`Found ${repository.discussions.edges.length} discussions in this page of data`,
39+
);
40+
41+
let numMutating = 0;
42+
let mutation = 'mutation {';
43+
for (let i in resp.repository.discussions.edges) {
44+
let edge = resp.repository.discussions.edges[i];
45+
if (
46+
isOlderThanDaysAgo(edge.node.answerChosenAt, discussionAnsweredDays)
47+
) {
48+
mutation += `m${i}: closeDiscussion(input: {discussionId: "${edge.node.id}"}) {
49+
clientMutationId
50+
}\n`;
51+
numMutating++;
52+
}
53+
}
54+
mutation += '}';
55+
56+
if (numMutating > 0) {
57+
console.debug(`Attempting the following mutation:\n${mutation}`);
58+
59+
await github.graphql(mutation);
60+
61+
console.log(`Closed ${numMutating} answered Discussions`);
62+
} else {
63+
console.debug(
64+
`Did not find any Discussions to close in this page of data`,
65+
);
66+
}
67+
68+
if (!resp.repository.discussions.pageInfo.hasNextPage) {
69+
break;
70+
}
71+
72+
cursor = resp.repository.discussions.pageInfo.endCursor;
73+
}
74+
75+
return '';
76+
};

.github/workflows/lock.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
workflow_dispatch:
1010

1111
permissions:
12+
discussions: write
1213
issues: write
1314
pull-requests: write
1415

@@ -24,6 +25,7 @@ jobs:
2425
if: github.repository == 'renovatebot/renovate'
2526
with:
2627
github-token: ${{ github.token }}
28+
discussions-inactive-days: 30
2729
issue-inactive-days: 30
2830
pr-inactive-days: 30
29-
process-only: 'issues, prs'
31+
process-only: 'issues, prs, discussions'

eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default tseslint.config(
3030
'**/.venv/',
3131
'tools/mkdocs/docs',
3232
'tools/mkdocs/site',
33+
'.github/workflows/**/*.js',
3334
'.worktrees/**/*',
3435
],
3536
},

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"tmp",
4040
"tools/mkdocs/docs",
4141
"tools/mkdocs/site",
42+
".github/workflows/**/*.js",
4243
".worktrees/**/*"
4344
],
4445
"ts-node": {

0 commit comments

Comments
 (0)