diff --git a/linera-summary/src/github.rs b/linera-summary/src/github.rs index 2c744e0adb9..5b2326edc14 100644 --- a/linera-summary/src/github.rs +++ b/linera-summary/src/github.rs @@ -12,6 +12,8 @@ use octocrab::{ }; use tracing::info; +use crate::performance_summary::PR_COMMENT_HEADER; + const API_REQUEST_DELAY_MS: u64 = 100; const IGNORED_JOB_PREFIXES: &[&str] = &["lint-", "check-outdated-cli-md"]; @@ -164,18 +166,57 @@ impl Github { &self.context } - pub async fn comment_on_pr(&self, body: String) -> Result<()> { + // Updates an existing comment or creates a new one in the PR. + pub async fn upsert_pr_comment(&self, body: String) -> Result<()> { + let issue_handler = self.octocrab.issues( + self.context.repository.owner.clone(), + self.context.repository.name.clone(), + ); + let existing_comment_id = issue_handler + .list_comments(self.context.pr_number) + .send() + .await? + .items + .into_iter() + .find_map(|comment| { + if comment.user.login == "github-actions[bot]" + && comment + .body + .is_some_and(|body| body.starts_with(PR_COMMENT_HEADER)) + { + Some(comment.id) + } else { + None + } + }); + // Always print the summary to stdout, as we'll use it to set the job summary in CI. info!("Printing summary to stdout..."); println!("{}", body); - if !self.is_local { + if let Some(existing_comment_id) = existing_comment_id { + if self.is_local { + info!( + "Would have updated comment {} on PR {}, but is local", + existing_comment_id, self.context.pr_number + ); + } else { + info!( + "Updating existing comment {} on PR {}", + existing_comment_id, self.context.pr_number + ); + issue_handler + .update_comment(existing_comment_id, body) + .await?; + } + } else if self.is_local { + info!( + "Would have commented on PR {}, but is local", + self.context.pr_number + ); + } else { info!("Commenting on PR {}", self.context.pr_number); - self.octocrab - .issues( - self.context.repository.owner.clone(), - self.context.repository.name.clone(), - ) + issue_handler .create_comment(self.context.pr_number, body) .await?; } diff --git a/linera-summary/src/main.rs b/linera-summary/src/main.rs index fa2cac6e7df..319a54386ae 100644 --- a/linera-summary/src/main.rs +++ b/linera-summary/src/main.rs @@ -13,7 +13,7 @@ async fn run(options: SummaryOptions) -> Result<()> { let tracked_workflows = options.workflows(); let github = Github::new(options.is_local(), options.pr_number())?; let summary = PerformanceSummary::init(github, tracked_workflows).await?; - summary.comment_on_pr().await?; + summary.upsert_pr_comment().await?; Ok(()) } diff --git a/linera-summary/src/performance_summary.rs b/linera-summary/src/performance_summary.rs index f9ec49f5d57..bbb0674a120 100644 --- a/linera-summary/src/performance_summary.rs +++ b/linera-summary/src/performance_summary.rs @@ -9,6 +9,8 @@ use serde::Serialize; use crate::{ci_runtime_comparison::CiRuntimeComparison, github::Github}; +pub const PR_COMMENT_HEADER: &str = "## Performance Summary for commit"; + #[derive(Serialize)] pub struct PerformanceSummary { #[serde(skip_serializing)] @@ -65,8 +67,8 @@ impl PerformanceSummary { ); let mut markdown_content = format!( - "## Performance Summary for commit [{}]({})\n\n", - short_commit_hash, commit_url + "{} [{}]({})\n\n", + PR_COMMENT_HEADER, short_commit_hash, commit_url ); markdown_content.push_str("### CI Runtime Comparison\n\n"); @@ -97,10 +99,10 @@ impl PerformanceSummary { markdown_content } - pub async fn comment_on_pr(&self) -> Result<()> { + // Updates an existing comment or creates a new one in the PR. + pub async fn upsert_pr_comment(&self) -> Result<()> { self.github - .comment_on_pr(self.format_comment_body()) - .await?; - Ok(()) + .upsert_pr_comment(self.format_comment_body()) + .await } }