From d4b080b40b8b4857d907baee3c5f3eb0640fa540 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 15 Oct 2024 17:57:29 +0200 Subject: [PATCH 1/3] Parse the returned comment from the GitHub API https://docs.github.com/en/rest/issues/comments?apiVersion=2022-11-28#create-an-issue-comment --- src/github.rs | 18 ++++++++++-------- src/interactions.rs | 6 ++++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/github.rs b/src/github.rs index 6be878aa..a509f645 100644 --- a/src/github.rs +++ b/src/github.rs @@ -391,6 +391,8 @@ impl ZulipGitHubReference { #[derive(Debug, serde::Deserialize)] pub struct Comment { + pub id: u64, + pub node_id: String, #[serde(deserialize_with = "opt_string")] pub body: String, pub html_url: String, @@ -581,24 +583,24 @@ impl Issue { client: &GithubClient, id: u64, new_body: &str, - ) -> anyhow::Result<()> { + ) -> anyhow::Result { let comment_url = format!("{}/issues/comments/{}", self.repository().url(client), id); #[derive(serde::Serialize)] struct NewComment<'a> { body: &'a str, } - client - .send_req( + let comment = client + .json( client .patch(&comment_url) .json(&NewComment { body: new_body }), ) .await .context("failed to edit comment")?; - Ok(()) + Ok(comment) } - pub async fn post_comment(&self, client: &GithubClient, body: &str) -> anyhow::Result<()> { + pub async fn post_comment(&self, client: &GithubClient, body: &str) -> anyhow::Result { #[derive(serde::Serialize)] struct PostComment<'a> { body: &'a str, @@ -608,11 +610,11 @@ impl Issue { .strip_prefix("https://api.github.com") .expect("expected api host"); let comments_url = format!("{}{comments_path}", client.api_url); - client - .send_req(client.post(&comments_url).json(&PostComment { body })) + let comment = client + .json(client.post(&comments_url).json(&PostComment { body })) .await .context("failed to post comment")?; - Ok(()) + Ok(comment) } pub async fn remove_label(&self, client: &GithubClient, label: &str) -> anyhow::Result<()> { diff --git a/src/interactions.rs b/src/interactions.rs index f3d6a115..0abce1d9 100644 --- a/src/interactions.rs +++ b/src/interactions.rs @@ -26,7 +26,8 @@ impl<'a> ErrorComment<'a> { "Please file an issue on GitHub at [triagebot](https://github.com/rust-lang/triagebot) if there's \ a problem with this bot, or reach out on [#t-infra](https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra) on Zulip." )?; - self.issue.post_comment(client, &body).await + self.issue.post_comment(client, &body).await?; + Ok(()) } } @@ -45,7 +46,8 @@ impl<'a> PingComment<'a> { for user in self.users { write!(body, "@{} ", user)?; } - self.issue.post_comment(client, &body).await + self.issue.post_comment(client, &body).await?; + Ok(()) } } From 2d280a190902f741da5c8e5efd9016a778a3203c Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 15 Oct 2024 18:16:01 +0200 Subject: [PATCH 2/3] Add API call to hide a comment Heavily inspired by the one in rust-log-analyzer https://github.com/rust-lang/rust-log-analyzer/blob/104ccd0e653c12342608bc41c520a37352b680fd/src/github.rs#L328-L348 Enum from https://docs.github.com/en/graphql/reference/enums#reportedcontentclassifiers --- src/github.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/github.rs b/src/github.rs index a509f645..d6a92688 100644 --- a/src/github.rs +++ b/src/github.rs @@ -405,6 +405,17 @@ pub struct Comment { pub pr_review_state: Option, } +#[derive(Debug, serde::Deserialize, serde::Serialize, Eq, PartialEq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum ReportedContentClassifiers { + Abuse, + Duplicate, + OffTopic, + Outdated, + Resolved, + Spam, +} + #[derive(Debug, serde::Deserialize, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub enum PullRequestReviewState { @@ -617,6 +628,28 @@ impl Issue { Ok(comment) } + pub async fn hide_comment( + &self, + client: &GithubClient, + node_id: &str, + reason: ReportedContentClassifiers, + ) -> anyhow::Result<()> { + client + .graphql_query( + "mutation($node_id: ID!, $reason: ReportedContentClassifiers!) { + minimizeComment(input: {subjectId: $node_id, classifier: $reason}) { + __typename + } + }", + serde_json::json!({ + "node_id": node_id, + "reason": reason, + }), + ) + .await?; + Ok(()) + } + pub async fn remove_label(&self, client: &GithubClient, label: &str) -> anyhow::Result<()> { log::info!("remove_label from {}: {:?}", self.global_id(), label); // DELETE /repos/:owner/:repo/issues/:number/labels/{name} From 9921cb09e0d442290f35541161b9080937c15b32 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 15 Oct 2024 18:38:41 +0200 Subject: [PATCH 3/3] Hide no-merge comments once merge commits removed --- src/handlers/no_merges.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/handlers/no_merges.rs b/src/handlers/no_merges.rs index c1d87271..e94b26f0 100644 --- a/src/handlers/no_merges.rs +++ b/src/handlers/no_merges.rs @@ -4,7 +4,7 @@ use crate::{ config::NoMergesConfig, db::issue_data::IssueData, - github::{IssuesAction, IssuesEvent, Label}, + github::{IssuesAction, IssuesEvent, Label, ReportedContentClassifiers}, handlers::Context, }; use anyhow::Context as _; @@ -24,6 +24,9 @@ pub(super) struct NoMergesInput { struct NoMergesState { /// Hashes of merge commits that have already been mentioned by triagebot in a comment. mentioned_merge_commits: HashSet, + /// List of all the no_merge comments as GitHub GraphQL NodeId. + #[serde(default)] + no_merge_comments: Vec, /// Labels that the bot added as part of the no-merges check. #[serde(default)] added_labels: Vec, @@ -124,10 +127,22 @@ pub(super) async fn handle_input( .context("failed to remove label")?; } - // FIXME: Minimize prior no_merges comments. + // Minimize prior no_merges comments. + for node_id in state.data.no_merge_comments.iter() { + event + .issue + .hide_comment( + &ctx.github, + node_id.as_str(), + ReportedContentClassifiers::Resolved, + ) + .await + .context("failed to hide previous merge commit comment")?; + } // Clear from state. state.data.mentioned_merge_commits.clear(); + state.data.no_merge_comments.clear(); state.data.added_labels.clear(); state.save().await?; return Ok(()); @@ -202,11 +217,13 @@ pub(super) async fn handle_input( .context("failed to set no_merges labels")?; // Post comment - event + let comment = event .issue .post_comment(&ctx.github, &message) .await .context("failed to post no_merges comment")?; + + state.data.no_merge_comments.push(comment.node_id); state.save().await?; } Ok(())