From aab91a4ce0781253c735e2cfa83472f8afe8ab2d Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Fri, 8 Sep 2023 15:29:53 +0300 Subject: [PATCH] Close issues with `status/needs-feedback` that were last updated more than a month ago (#108) * Close issues with `status/needs-feedback` that were last updated more than a month ago We will close issues with the label `status/needs-feedback` if there is no new activity in the past month. Co-authored-by: silverwind --- README.md | 5 +++++ src/feedback.ts | 28 ++++++++++++++++++++++++++++ src/github.ts | 26 ++++++++++++++++++++++++++ src/webhook.ts | 4 +++- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/feedback.ts diff --git a/README.md b/README.md index 12f0acf..da0a52f 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,11 @@ The script will also lock issues and pull requests that have been closed for 3 months. If the issue was commented on in the last two weeks, a comment will be posted suggesting opening a new issue to continue the discussion. +### Feedback + +The script will close issues with the label `status/needs-feedback` if a month +has passed since they were updated. + ### Maintainer commands The script can execute some actions like updating a PR's branch if requested by diff --git a/src/feedback.ts b/src/feedback.ts new file mode 100644 index 0000000..ad8c33c --- /dev/null +++ b/src/feedback.ts @@ -0,0 +1,28 @@ +import { addComment, closeIssue, fetchOpenIssuesWithLabel } from "./github.ts"; + +export const run = async () => { + // get all issues with the label "status/needs-feedback" + const issuesWithStatusNeedsFeedback = await fetchOpenIssuesWithLabel( + "status/needs-feedback", + ); + return Promise.all(issuesWithStatusNeedsFeedback.items.map(handleIssue)); +}; + +// close issue if a month has passed since it was last updated +const handleIssue = async (issue: { + number: number; + updated_at: string; +}) => { + const oneMonthAgo = (new Date(Date.now() - 1000 * 60 * 60 * 24 * 30)) + .getTime(); + if ((new Date(issue.updated_at)).getTime() < oneMonthAgo) { + console.log(`Closing issue #${issue.number} due to feedback timeout`); + await addComment( + issue.number, + `We close issues that need feedback from the author if there were no new comments for a month. :tea:`, + ); + + // close issue + await closeIssue(issue.number); + } +}; diff --git a/src/github.ts b/src/github.ts index 3fe1da6..244cd45 100644 --- a/src/github.ts +++ b/src/github.ts @@ -40,6 +40,19 @@ export const fetchMergedWithLabel = async (label: string) => { return json; }; +// returns a list of open issues with the given label +export const fetchOpenIssuesWithLabel = async (label: string) => { + const response = await fetch( + `${GITHUB_API}/search/issues?q=` + + encodeURIComponent( + `is:issue is:open label:${label} repo:go-gitea/gitea`, + ), + { headers: HEADERS }, + ); + const json = await response.json(); + return json; +}; + // returns a list of PRs pending merge (have the label reviewed/wait-merge) export const fetchPendingMerge = async () => { const response = await fetch( @@ -476,3 +489,16 @@ export const fetchLastComment = async (issueNumber: number) => { if (!json.length) return null; return json[0]; }; + +// closes the given issue +export const closeIssue = async (issueNumber: number) => { + const response = await fetch( + `${GITHUB_API}/repos/go-gitea/gitea/issues/${issueNumber}`, + { + method: "PATCH", + headers: HEADERS, + body: JSON.stringify({ state: "closed" }), + }, + ); + return response.json(); +}; diff --git a/src/webhook.ts b/src/webhook.ts index 7926ffa..91322bd 100644 --- a/src/webhook.ts +++ b/src/webhook.ts @@ -9,6 +9,7 @@ import * as lgtm from "./lgtm.ts"; import * as comments from "./comments.ts"; import * as lock from "./lock.ts"; import * as prActions from "./prActions.ts"; +import * as feedback from "./feedback.ts"; const secret = Deno.env.get("BACKPORTER_GITHUB_SECRET"); @@ -31,10 +32,11 @@ webhook.on("push", ({ payload }) => { backport.run(); } - // we should take this opportunity to run the label, merge queue, and lock maintenance + // we should take this opportunity to run the label, merge queue, lock, and feedback maintenance labels.run(); mergeQueue.run(); lock.run(); + feedback.run(); }); // on pull request labeling events, run the label and merge queue maintenance