You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
10 KiB
278 lines
10 KiB
name: 'Repository Maintenance'
|
|
|
|
on:
|
|
schedule:
|
|
- cron: '0 3 * * *'
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
issues: write
|
|
pull-requests: write
|
|
discussions: write
|
|
|
|
concurrency:
|
|
group: lock
|
|
|
|
jobs:
|
|
stale:
|
|
name: 'Stale'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/stale@v9
|
|
with:
|
|
days-before-stale: 7
|
|
days-before-close: 14
|
|
stale-issue-label: stale
|
|
stale-pr-label: stale
|
|
stale-issue-message: >
|
|
This issue has been automatically marked as stale because it has not had
|
|
recent activity. It will be closed if no further activity occurs. Thank you
|
|
for your contributions.
|
|
lock-threads:
|
|
name: 'Lock Old Threads'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: dessant/lock-threads@v5
|
|
with:
|
|
issue-inactive-days: '30'
|
|
pr-inactive-days: '30'
|
|
discussion-inactive-days: '30'
|
|
log-output: true
|
|
issue-comment: >
|
|
This issue has been automatically locked since there
|
|
has not been any recent activity after it was closed.
|
|
Please open a new discussion for related concerns.
|
|
pr-comment: >
|
|
This pull request has been automatically locked since there
|
|
has not been any recent activity after it was closed.
|
|
Please open a new discussion for related concerns.
|
|
discussion-comment: >
|
|
This discussion has been automatically locked since there
|
|
has not been any recent activity after it was closed.
|
|
Please open a new discussion for related concerns.
|
|
close-answered-discussions:
|
|
name: 'Close Answered Discussions'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
function sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
const query = `query($owner:String!, $name:String!) {
|
|
repository(owner:$owner, name:$name){
|
|
discussions(first:100, answered:true, states:[OPEN]) {
|
|
nodes {
|
|
id,
|
|
number
|
|
}
|
|
}
|
|
}
|
|
}`;
|
|
const variables = {
|
|
owner: context.repo.owner,
|
|
name: context.repo.repo,
|
|
}
|
|
const result = await github.graphql(query, variables)
|
|
|
|
console.log(`Found ${result.repository.discussions.nodes.length} open answered discussions`)
|
|
|
|
for (const discussion of result.repository.discussions.nodes) {
|
|
console.log(`Closing discussion #${discussion.number} (${discussion.id})`)
|
|
|
|
const addCommentMutation = `mutation($discussion:ID!, $body:String!) {
|
|
addDiscussionComment(input:{discussionId:$discussion, body:$body}) {
|
|
clientMutationId
|
|
}
|
|
}`;
|
|
const commentVariables = {
|
|
discussion: discussion.id,
|
|
body: 'This discussion has been automatically closed because it was marked as answered.',
|
|
}
|
|
await github.graphql(addCommentMutation, commentVariables)
|
|
|
|
const closeDiscussionMutation = `mutation($discussion:ID!, $reason:DiscussionCloseReason!) {
|
|
closeDiscussion(input:{discussionId:$discussion, reason:$reason}) {
|
|
clientMutationId
|
|
}
|
|
}`;
|
|
const closeVariables = {
|
|
discussion: discussion.id,
|
|
reason: "RESOLVED",
|
|
}
|
|
await github.graphql(closeDiscussionMutation, closeVariables)
|
|
|
|
await sleep(1000)
|
|
}
|
|
close-outdated-discussions:
|
|
name: 'Close Outdated Discussions'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
function sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
const CUTOFF_DAYS = 180;
|
|
const cutoff = new Date();
|
|
cutoff.setDate(cutoff.getDate() - CUTOFF_DAYS);
|
|
|
|
const query = `query(
|
|
$owner:String!,
|
|
$name:String!,
|
|
$supportCategory:ID!,
|
|
$generalCategory:ID!,
|
|
) {
|
|
supportDiscussions: repository(owner:$owner, name:$name){
|
|
discussions(
|
|
categoryId:$supportCategory,
|
|
last:50,
|
|
answered:false,
|
|
states:[OPEN],
|
|
) {
|
|
nodes {
|
|
id,
|
|
number,
|
|
updatedAt
|
|
}
|
|
},
|
|
},
|
|
generalDiscussions: repository(owner:$owner, name:$name){
|
|
discussions(
|
|
categoryId:$generalCategory,
|
|
last:50,
|
|
states:[OPEN],
|
|
) {
|
|
nodes {
|
|
id,
|
|
number,
|
|
updatedAt
|
|
}
|
|
}
|
|
}
|
|
}`;
|
|
const variables = {
|
|
owner: context.repo.owner,
|
|
name: context.repo.repo,
|
|
supportCategory: "DIC_kwDOH31rQM4CRErR",
|
|
generalCategory: "DIC_kwDOH31rQM4CRErQ"
|
|
}
|
|
const result = await github.graphql(query, variables);
|
|
const combinedDiscussions = [
|
|
...result.supportDiscussions.discussions.nodes,
|
|
...result.generalDiscussions.discussions.nodes,
|
|
]
|
|
|
|
console.log(`Checking ${combinedDiscussions.length} open discussions`);
|
|
|
|
for (const discussion of combinedDiscussions) {
|
|
if (new Date(discussion.updatedAt) < cutoff) {
|
|
console.log(`Closing outdated discussion #${discussion.number} (${discussion.id}), last updated at ${discussion.updatedAt}`);
|
|
const addCommentMutation = `mutation($discussion:ID!, $body:String!) {
|
|
addDiscussionComment(input:{discussionId:$discussion, body:$body}) {
|
|
clientMutationId
|
|
}
|
|
}`;
|
|
const commentVariables = {
|
|
discussion: discussion.id,
|
|
body: 'This discussion has been automatically closed due to inactivity.',
|
|
}
|
|
await github.graphql(addCommentMutation, commentVariables);
|
|
|
|
const closeDiscussionMutation = `mutation($discussion:ID!, $reason:DiscussionCloseReason!) {
|
|
closeDiscussion(input:{discussionId:$discussion, reason:$reason}) {
|
|
clientMutationId
|
|
}
|
|
}`;
|
|
const closeVariables = {
|
|
discussion: discussion.id,
|
|
reason: "OUTDATED",
|
|
}
|
|
await github.graphql(closeDiscussionMutation, closeVariables);
|
|
|
|
await sleep(1000);
|
|
}
|
|
}
|
|
close-unsupported-feature-requests:
|
|
name: 'Close Unsupported Feature Requests'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
function sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
const CUTOFF_1_DAYS = 180;
|
|
const CUTOFF_1_COUNT = 5;
|
|
const CUTOFF_2_DAYS = 365;
|
|
const CUTOFF_2_COUNT = 10;
|
|
|
|
const cutoff1Date = new Date();
|
|
cutoff1Date.setDate(cutoff1Date.getDate() - CUTOFF_1_DAYS);
|
|
const cutoff2Date = new Date();
|
|
cutoff2Date.setDate(cutoff2Date.getDate() - CUTOFF_2_DAYS);
|
|
|
|
const query = `query(
|
|
$owner:String!,
|
|
$name:String!,
|
|
$featureRequestsCategory:ID!,
|
|
) {
|
|
repository(owner:$owner, name:$name){
|
|
discussions(
|
|
categoryId:$featureRequestsCategory,
|
|
last:100,
|
|
states:[OPEN],
|
|
) {
|
|
nodes {
|
|
id,
|
|
number,
|
|
updatedAt,
|
|
upvoteCount,
|
|
}
|
|
},
|
|
}
|
|
}`;
|
|
const variables = {
|
|
owner: context.repo.owner,
|
|
name: context.repo.repo,
|
|
featureRequestsCategory: "DIC_kwDOH31rQM4CRErS"
|
|
}
|
|
const result = await github.graphql(query, variables);
|
|
|
|
for (const discussion of result.repository.discussions.nodes) {
|
|
const discussionDate = new Date(discussion.updatedAt);
|
|
if ((discussionDate < cutoff1Date && discussion.upvoteCount < CUTOFF_1_COUNT) ||
|
|
(discussionDate < cutoff2Date && discussion.upvoteCount < CUTOFF_2_COUNT)) {
|
|
console.log(`Closing discussion #${discussion.number} (${discussion.id}), last updated at ${discussion.updatedAt} with votes ${discussion.upvoteCount}`);
|
|
const addCommentMutation = `mutation($discussion:ID!, $body:String!) {
|
|
addDiscussionComment(input:{discussionId:$discussion, body:$body}) {
|
|
clientMutationId
|
|
}
|
|
}`;
|
|
const commentVariables = {
|
|
discussion: discussion.id,
|
|
body: 'This discussion has been automatically closed due to lack of community interest.',
|
|
}
|
|
await github.graphql(addCommentMutation, commentVariables);
|
|
|
|
const closeDiscussionMutation = `mutation($discussion:ID!, $reason:DiscussionCloseReason!) {
|
|
closeDiscussion(input:{discussionId:$discussion, reason:$reason}) {
|
|
clientMutationId
|
|
}
|
|
}`;
|
|
const closeVariables = {
|
|
discussion: discussion.id,
|
|
reason: "OUTDATED",
|
|
}
|
|
await github.graphql(closeDiscussionMutation, closeVariables);
|
|
|
|
await sleep(1000);
|
|
}
|
|
}
|