Skip to content

Commit 8966336

Browse files
committed
Minimize all rustc-timer non-summary comments after a summary is posted
1 parent 8591515 commit 8966336

File tree

4 files changed

+191
-7
lines changed

4 files changed

+191
-7
lines changed

site/src/github.rs

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ use serde::Deserialize;
99
type BoxedError = Box<dyn std::error::Error + Send + Sync>;
1010

1111
pub const RUST_REPO_GITHUB_API_URL: &str = "https://api.github.com/repos/rust-lang/rust";
12+
pub const RUST_REPO_GITHUB_GRAPH_URL: &str = "https://api.github.com/graphql";
13+
14+
/// Comments that are temporary and do not add any value once there has been a new development
15+
/// (a rustc build or a perf. run was finished) are marked with this comment.
16+
///
17+
/// They are removed once a perf. run comparison summary is posted on a PR.
18+
pub const COMMENT_MARK_TEMPORARY: &str = "<!-- rust-timer: temporary -->";
1219

1320
pub use comparison_summary::post_finished;
1421

@@ -236,6 +243,7 @@ pub async fn enqueue_shas(
236243
));
237244
}
238245
}
246+
msg.push_str(&format!("\n{COMMENT_MARK_TEMPORARY}"));
239247
main_client.post_comment(pr_number, msg).await;
240248
Ok(())
241249
}

site/src/github/client.rs

+147
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::Context;
22
use chrono::{DateTime, Utc};
33
use http::header::USER_AGENT;
4+
use serde::de::DeserializeOwned;
45

56
use crate::{api::github::Issue, load::SiteCtxt};
67

@@ -226,6 +227,124 @@ impl Client {
226227
}
227228
}
228229

230+
pub async fn get_comments(&self, pull_request: u32) -> anyhow::Result<Vec<ResponseComment>> {
231+
const QUERY: &str = "query($owner: String!, $repo: String!, $pr: Int!, $cursor: String) {
232+
repository(owner: $owner, name: $repo) {
233+
pullRequest(number: $pr) {
234+
comments(first: 100, after: $cursor) {
235+
nodes {
236+
id
237+
body
238+
isMinimized
239+
viewerDidAuthor
240+
}
241+
pageInfo {
242+
endCursor
243+
}
244+
}
245+
}
246+
}
247+
}";
248+
249+
#[derive(Debug, serde::Deserialize)]
250+
struct Response {
251+
repository: ResponseRepo,
252+
}
253+
#[derive(Debug, serde::Deserialize)]
254+
#[serde(rename_all = "camelCase")]
255+
struct ResponseRepo {
256+
pull_request: ResponsePR,
257+
}
258+
#[derive(Debug, serde::Deserialize)]
259+
struct ResponsePR {
260+
comments: ResponseComments,
261+
}
262+
#[derive(Debug, serde::Deserialize)]
263+
#[serde(rename_all = "camelCase")]
264+
struct ResponseComments {
265+
nodes: Vec<ResponseComment>,
266+
page_info: GraphPageInfo,
267+
}
268+
269+
let owner = "rust-lang";
270+
let repo = "rust";
271+
272+
let mut comments = Vec::new();
273+
let mut cursor = None;
274+
loop {
275+
let mut resp: Response = self
276+
.graphql(
277+
QUERY,
278+
serde_json::json!({
279+
"owner": owner,
280+
"repo": repo,
281+
"pr": pull_request,
282+
"cursor": cursor,
283+
}),
284+
)
285+
.await?;
286+
cursor = resp.repository.pull_request.comments.page_info.end_cursor;
287+
comments.append(&mut resp.repository.pull_request.comments.nodes);
288+
289+
if cursor.is_none() {
290+
break;
291+
}
292+
}
293+
Ok(comments)
294+
}
295+
296+
pub async fn hide_comment(&self, comment_id: &str, reason: &str) -> anyhow::Result<()> {
297+
#[derive(serde::Deserialize)]
298+
struct MinimizeData {}
299+
300+
const MINIMIZE: &str = "mutation($node_id: ID!, $reason: ReportedContentClassifiers!) {
301+
minimizeComment(input: {subjectId: $node_id, classifier: $reason}) {
302+
__typename
303+
}
304+
}";
305+
306+
self.graphql::<Option<MinimizeData>, _>(
307+
MINIMIZE,
308+
serde_json::json!({
309+
"node_id": comment_id,
310+
"reason": reason,
311+
}),
312+
)
313+
.await?;
314+
Ok(())
315+
}
316+
317+
async fn graphql<T: DeserializeOwned, V: serde::Serialize>(
318+
&self,
319+
query: &str,
320+
variables: V,
321+
) -> anyhow::Result<T> {
322+
#[derive(serde::Serialize)]
323+
struct GraphPayload<'a, V> {
324+
query: &'a str,
325+
variables: V,
326+
}
327+
328+
let response: GraphResponse<T> = self
329+
.inner
330+
.post(&self.repository_url)
331+
.json(&GraphPayload { query, variables })
332+
.send()
333+
.await?
334+
.error_for_status()?
335+
.json()
336+
.await?;
337+
338+
if response.errors.is_empty() {
339+
Ok(response.data)
340+
} else {
341+
Err(anyhow::anyhow!(
342+
"GraphQL query failed: {}",
343+
response.errors[0].message
344+
))
345+
}
346+
}
347+
229348
async fn send(
230349
&self,
231350
request: reqwest::RequestBuilder,
@@ -238,6 +357,34 @@ impl Client {
238357
}
239358
}
240359

360+
#[derive(serde::Deserialize)]
361+
struct GraphResponse<T> {
362+
data: T,
363+
#[serde(default)]
364+
errors: Vec<GraphError>,
365+
}
366+
367+
#[derive(Debug, serde::Deserialize)]
368+
struct GraphError {
369+
message: String,
370+
}
371+
372+
#[derive(Debug, serde::Deserialize)]
373+
#[serde(rename_all = "camelCase")]
374+
struct GraphPageInfo {
375+
end_cursor: Option<String>,
376+
}
377+
378+
#[derive(Debug, serde::Deserialize)]
379+
#[serde(rename_all = "camelCase")]
380+
pub struct ResponseComment {
381+
pub id: String,
382+
pub body: String,
383+
pub is_minimized: bool,
384+
// Is the account that fetches this comment also the original author of the comment?
385+
pub viewer_did_author: bool,
386+
}
387+
241388
#[derive(Debug, serde::Deserialize)]
242389
pub struct CreatePrResponse {
243390
pub number: u32,

site/src/github/comparison_summary.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::load::SiteCtxt;
66

77
use database::{ArtifactId, QueuedCommit};
88

9-
use crate::github::RUST_REPO_GITHUB_API_URL;
9+
use crate::github::{COMMENT_MARK_TEMPORARY, RUST_REPO_GITHUB_API_URL, RUST_REPO_GITHUB_GRAPH_URL};
1010
use std::collections::HashSet;
1111
use std::fmt::Write;
1212

@@ -58,15 +58,22 @@ pub async fn post_finished(ctxt: &SiteCtxt) {
5858
assert_eq!(completed, queued_commit);
5959

6060
let is_master_commit = master_commits.contains(&queued_commit.sha);
61-
post_comparison_comment(ctxt, queued_commit, is_master_commit).await;
61+
if let Err(error) = post_comparison_comment(ctxt, queued_commit, is_master_commit).await
62+
{
63+
log::error!("Cannot post comparison comment: {error:?}");
64+
}
6265
}
6366
}
6467
}
6568

6669
/// Posts a comment to GitHub summarizing the comparison of the queued commit with its parent
6770
///
6871
/// `is_master_commit` is used to differentiate messages for try runs and post-merge runs.
69-
async fn post_comparison_comment(ctxt: &SiteCtxt, commit: QueuedCommit, is_master_commit: bool) {
72+
async fn post_comparison_comment(
73+
ctxt: &SiteCtxt,
74+
commit: QueuedCommit,
75+
is_master_commit: bool,
76+
) -> anyhow::Result<()> {
7077
let client = super::client::Client::from_ctxt(ctxt, RUST_REPO_GITHUB_API_URL.to_owned());
7178
let pr = commit.pr;
7279
let body = match summarize_run(ctxt, commit, is_master_commit).await {
@@ -75,6 +82,21 @@ async fn post_comparison_comment(ctxt: &SiteCtxt, commit: QueuedCommit, is_maste
7582
};
7683

7784
client.post_comment(pr, body).await;
85+
86+
let graph_client =
87+
super::client::Client::from_ctxt(ctxt, RUST_REPO_GITHUB_GRAPH_URL.to_owned());
88+
for comment in graph_client.get_comments(pr).await? {
89+
// If this bot is the author of the comment, the comment is not yet minimized and it is
90+
// a temporary comment, minimize it.
91+
if comment.viewer_did_author
92+
&& !comment.is_minimized
93+
&& comment.body.contains(COMMENT_MARK_TEMPORARY)
94+
{
95+
log::debug!("Hiding comment {}", comment.id);
96+
graph_client.hide_comment(&comment.id, "OUTDATED").await?;
97+
}
98+
}
99+
Ok(())
78100
}
79101

80102
fn make_comparison_url(commit: &QueuedCommit, stat: Metric) -> String {

site/src/request_handlers/github.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::api::{github, ServerResult};
22
use crate::github::{
33
client, enqueue_shas, parse_homu_comment, rollup_pr_number, unroll_rollup,
4-
RUST_REPO_GITHUB_API_URL,
4+
COMMENT_MARK_TEMPORARY, RUST_REPO_GITHUB_API_URL,
55
};
66
use crate::load::SiteCtxt;
77

@@ -109,7 +109,10 @@ async fn handle_rust_timer(
109109
main_client
110110
.post_comment(
111111
issue.number,
112-
"Insufficient permissions to issue commands to rust-timer.",
112+
format!(
113+
"Insufficient permissions to issue commands to rust-timer.
114+
{COMMENT_MARK_TEMPORARY}"
115+
),
113116
)
114117
.await;
115118
return Ok(github::Response);
@@ -126,9 +129,13 @@ async fn handle_rust_timer(
126129
main_client
127130
.post_comment(
128131
issue.number,
129-
"Awaiting bors try build completion.
132+
format!(
133+
"Awaiting bors try build completion.
130134
131-
@rustbot label: +S-waiting-on-perf",
135+
@rustbot label: +S-waiting-on-perf
136+
137+
{COMMENT_MARK_TEMPORARY}"
138+
),
132139
)
133140
.await;
134141
return Ok(github::Response);

0 commit comments

Comments
 (0)