From f1127fc9e7628bef3769369f0030e0e195c59cc8 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Mon, 19 Jan 2026 08:52:31 +0900 Subject: [PATCH] Include build duration in success comment --- src/bors/comment.rs | 29 +++++++++++++ src/bors/handlers/refresh.rs | 2 + src/bors/merge_queue.rs | 80 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/src/bors/comment.rs b/src/bors/comment.rs index a2cd65ba..ec0efab6 100644 --- a/src/bors/comment.rs +++ b/src/bors/comment.rs @@ -409,6 +409,7 @@ pub fn auto_build_succeeded_comment( approved_by: &str, merge_sha: &CommitSha, base_ref: &str, + duration: Option, ) -> Comment { workflows.sort_by(|a, b| a.name.cmp(&b.name)); let urls = workflows @@ -417,10 +418,17 @@ pub fn auto_build_succeeded_comment( .collect::>() .join(", "); + let duration = if let Some(dur) = duration { + format_duration(dur) + } else { + "Unknown duration".to_string() + }; + Comment { text: format!( r#":sunny: Test successful - {urls} Approved by: `{approved_by}` +Duration: `{duration}` Pushing {merge_sha} to `{base_ref}`..."# ), metadata: Some(CommentMetadata::BuildCompleted { @@ -431,6 +439,27 @@ Pushing {merge_sha} to `{base_ref}`..."# } } +fn format_duration(duration: Duration) -> String { + let total_secs = duration.as_secs(); + let hours = total_secs / 3600; + let minutes = (total_secs % 3600) / 60; + let seconds = total_secs % 60; + + let mut res = String::new(); + + if hours > 0 { + res.push_str(&format!("{hours}h ")); + } + if minutes > 0 { + res.push_str(&format!("{minutes}m ")); + } + if seconds > 0 { + res.push_str(&format!("{seconds}s")); + } + + res.trim().to_string() +} + pub fn auto_build_push_failed_comment(error: &str) -> Comment { Comment::new(format!( ":eyes: Test was successful, but fast-forwarding failed: {error}" diff --git a/src/bors/handlers/refresh.rs b/src/bors/handlers/refresh.rs index 16eaa004..6f96151d 100644 --- a/src/bors/handlers/refresh.rs +++ b/src/bors/handlers/refresh.rs @@ -475,6 +475,7 @@ auto_build_failed = ["+failed"] insta::assert_snapshot!(comment, @r#" :sunny: Test successful - [Workflow1](https://github.com/rust-lang/borstest/actions/runs/1) Approved by: `default-user` + Duration: `1h` Pushing merge-0-pr-1-d7d45f1f-reauthored-to-bors to `main`... "#); @@ -506,6 +507,7 @@ auto_build_failed = ["+failed"] insta::assert_snapshot!(comment, @r#" :sunny: Test successful - [Workflow1](https://github.com/rust-lang/borstest/actions/runs/1) Approved by: `default-user` + Duration: `1h` Pushing merge-0-pr-1-d7d45f1f-reauthored-to-bors to `main`... "#); diff --git a/src/bors/merge_queue.rs b/src/bors/merge_queue.rs index cfbaff94..2a7a98f4 100644 --- a/src/bors/merge_queue.rs +++ b/src/bors/merge_queue.rs @@ -244,6 +244,7 @@ async fn handle_successful_build( &approval_info.approver, &commit_sha, &pr.base_branch, + auto_build.duration.map(|d| d.inner()), ); if let Err(error) = repo @@ -793,6 +794,7 @@ merge_queue_enabled = false @r#" :sunny: Test successful - [Workflow1](https://github.com/rust-lang/borstest/actions/runs/1) Approved by: `default-user` + Duration: `1h` Pushing merge-0-pr-1-d7d45f1f-reauthored-to-bors to `main`... "# @@ -802,6 +804,84 @@ merge_queue_enabled = false .await; } + #[sqlx::test] + async fn auto_build_success_comment_duration_hours_minutes(pool: sqlx::PgPool) { + // Test with hours and minutes (4800 seconds = 1h 20m) + run_test(pool, async |ctx: &mut BorsTester| { + ctx.approve(()).await?; + ctx.start_auto_build(()).await?; + let w1 = ctx.auto_workflow(); + ctx.modify_workflow(w1, |w| w.set_duration(Duration::from_secs(4800))); + ctx.workflow_full_success(w1).await?; + ctx.run_merge_queue_until_merge_attempt().await; + + insta::assert_snapshot!( + ctx.get_next_comment_text(()).await?, + @r#" + :sunny: Test successful - [Workflow1](https://github.com/rust-lang/borstest/actions/runs/1) + Approved by: `default-user` + Duration: `1h 20m` + Pushing merge-0-pr-1-d7d45f1f-reauthored-to-bors to `main`... + + "# + ); + Ok(()) + }) + .await; + } + + #[sqlx::test] + async fn auto_build_success_comment_duration_all_units(pool: sqlx::PgPool) { + // Test with hours, minutes and seconds (12345 seconds = 3h 25m 45s) + run_test(pool, async |ctx: &mut BorsTester| { + ctx.approve(()).await?; + ctx.start_auto_build(()).await?; + let w1 = ctx.auto_workflow(); + ctx.modify_workflow(w1, |w| w.set_duration(Duration::from_secs(12345))); + ctx.workflow_full_success(w1).await?; + ctx.run_merge_queue_until_merge_attempt().await; + + insta::assert_snapshot!( + ctx.get_next_comment_text(()).await?, + @r#" + :sunny: Test successful - [Workflow1](https://github.com/rust-lang/borstest/actions/runs/1) + Approved by: `default-user` + Duration: `3h 25m 45s` + Pushing merge-0-pr-1-d7d45f1f-reauthored-to-bors to `main`... + + "# + ); + Ok(()) + }) + .await; + } + + #[sqlx::test] + async fn auto_build_success_comment_duration_seconds_only(pool: sqlx::PgPool) { + // Test with just seconds (45 seconds) + run_test(pool, async |ctx: &mut BorsTester| { + ctx.approve(()).await?; + ctx.start_auto_build(()).await?; + let w1 = ctx.auto_workflow(); + ctx.modify_workflow(w1, |w| w.set_duration(Duration::from_secs(45))); + ctx.workflow_full_success(w1).await?; + ctx.run_merge_queue_until_merge_attempt().await; + + insta::assert_snapshot!( + ctx.get_next_comment_text(()).await?, + @r#" + :sunny: Test successful - [Workflow1](https://github.com/rust-lang/borstest/actions/runs/1) + Approved by: `default-user` + Duration: `45s` + Pushing merge-0-pr-1-d7d45f1f-reauthored-to-bors to `main`... + + "# + ); + Ok(()) + }) + .await; + } + #[sqlx::test] async fn auto_build_failure_comment(pool: sqlx::PgPool) { run_test(pool, async |ctx: &mut BorsTester| {