From 2a9587d4ff38fb285b8cf1f0c498f0b6797286b7 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 6 Jun 2022 10:26:29 +0100 Subject: [PATCH] Clean up closed issues (duplicates and rageshakes) (#22451) --- .github/workflows/issue_closed.yml | 148 +++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 .github/workflows/issue_closed.yml diff --git a/.github/workflows/issue_closed.yml b/.github/workflows/issue_closed.yml new file mode 100644 index 0000000000..9bc4e76a4a --- /dev/null +++ b/.github/workflows/issue_closed.yml @@ -0,0 +1,148 @@ +# For duplicate issues, ensure the close type is right (not planned), update it if not +# For all closed (completed) issues, cascade the closure onto any referenced rageshakes +# For all closed (not planned) issues, comment on rageshakes to move them into the canonical issue if one exists +on: + issues: + types: [ closed ] +jobs: + tidy: + name: Tidy closed issues + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v5 + with: + # PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org) + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + script: | + const variables = { + owner: context.repo.owner, + name: context.repo.repo, + number: context.issue.number, + }; + + const query = `query($owner:String!, $name:String!, $number:Int!) { + repository(owner: $owner, name: $name) { + issue(number: $number) { + stateReason, + timelineItems(first: 100, itemTypes: [MARKED_AS_DUPLICATE_EVENT, UNMARKED_AS_DUPLICATE_EVENT, CROSS_REFERENCED_EVENT]) { + edges { + node { + __typename + ... on MarkedAsDuplicateEvent { + canonical { + ... on Issue { + repository { + nameWithOwner + } + number + } + ... on PullRequest { + repository { + nameWithOwner + } + number + } + } + } + ... on UnmarkedAsDuplicateEvent { + canonical { + ... on Issue { + repository { + nameWithOwner + } + number + } + ... on PullRequest { + repository { + nameWithOwner + } + number + } + } + } + ... on CrossReferencedEvent { + source { + ... on Issue { + repository { + nameWithOwner + } + number + } + ... on PullRequest { + repository { + nameWithOwner + } + number + } + } + } + } + } + } + } + } + }`; + + const result = await github.graphql(query, variables); + const { stateReason, timelineItems: { edges } } = result.repository.issue; + + const RAGESHAKE_OWNER = "matrix-org"; + const RAGESHAKE_REPO = "element-web-rageshakes"; + const rageshakes = new Set(); + const duplicateOf = new Set(); + + console.log("Edges: ", JSON.stringify(edges)); + + for (const { node } of edges) { + switch(node.__typename) { + case "MarkedAsDuplicateEvent": + duplicateOf.add(node.canonical.repository.nameWithOwner + "#" + node.canonical.number); + break; + case "UnmarkedAsDuplicateEvent": + duplicateOf.remove(node.canonical.repository.nameWithOwner + "#" + node.canonical.number); + break; + case "CrossReferencedEvent": + if (node.source.repository.nameWithOwner === (RAGESHAKE_OWNER + "/" + RAGESHAKE_REPO)) { + rageshakes.add(node.source.number); + } + break; + } + } + + console.log("Duplicate of: ", duplicateOf); + console.log("Found rageshakes: ", rageshakes); + + if (duplicateOf.size) { + const body = Array.from(duplicateOf).join("\n"); + + // Comment on all rageshakes to create relationship to the issue this was closed as duplicate of + for (const rageshake of rageshakes) { + github.rest.issues.createComment({ + owner: RAGESHAKE_OWNER, + repo: RAGESHAKE_REPO, + issue_number: rageshake, + body, + }); + } + + // Duplicate was closed with wrong reason, fix it + if (stateReason === "COMPLETED") { + await github.graphql(`mutation($id:ID!) { + closeIssue(input: { issueId:$id, stateReason:NOT_PLANNED }) { + clientMutationId + } + }`, { + id: context.payload.issue.node_id, + }); + } + } else { + // This issue was closed, close all related rageshakes + for (const rageshake of rageshakes) { + github.rest.issues.update({ + owner: RAGESHAKE_OWNER, + repo: RAGESHAKE_REPO, + issue_number: rageshake, + state: "closed", + }); + } + }