Skip to content

Commit e0aa16b

Browse files
authored
Merge pull request #347 from Kobzol/checks-reenable
Re-enable PR checks
2 parents 524c2f1 + 9c2a983 commit e0aa16b

File tree

11 files changed

+571
-13
lines changed

11 files changed

+571
-13
lines changed

.sqlx/query-33cf1b803a0b658f197ab26d87e2c6c4fe42128cb481a234372626f35392e809.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bors/handlers/refresh.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::time::Duration;
33

44
use anyhow::Context;
55
use chrono::{DateTime, Utc};
6+
use octocrab::params::checks::{CheckRunConclusion, CheckRunStatus};
67
use std::collections::BTreeMap;
78

89
use crate::bors::Comment;
@@ -28,6 +29,22 @@ pub async fn cancel_timed_out_builds(
2829

2930
db.update_build_status(&build, BuildStatus::Cancelled)
3031
.await?;
32+
33+
if let Some(check_run_id) = build.check_run_id {
34+
if let Err(error) = repo
35+
.client
36+
.update_check_run(
37+
check_run_id as u64,
38+
CheckRunStatus::Completed,
39+
Some(CheckRunConclusion::TimedOut),
40+
None,
41+
)
42+
.await
43+
{
44+
tracing::error!("Could not update check run {check_run_id}: {error:?}");
45+
}
46+
}
47+
3148
if let Some(pr) = db.find_pr_by_build(&build).await? {
3249
if let Err(error) = cancel_build_workflows(&repo.client, db, &build).await {
3350
tracing::error!(
@@ -181,11 +198,13 @@ fn elapsed_time(date: DateTime<Utc>) -> Duration {
181198
mod tests {
182199
use crate::bors::PullRequestStatus;
183200
use crate::bors::handlers::refresh::MOCK_TIME;
201+
use crate::bors::handlers::trybuild::TRY_BUILD_CHECK_RUN_NAME;
184202
use crate::database::{MergeableState, OctocrabMergeableState};
185203
use crate::tests::mocks::{
186204
BorsBuilder, GitHubState, default_pr_number, default_repo_name, run_test,
187205
};
188206
use chrono::Utc;
207+
use octocrab::params::checks::{CheckRunConclusion, CheckRunStatus};
189208
use std::future::Future;
190209
use std::time::Duration;
191210
use tokio::runtime::RuntimeFlavor;
@@ -267,6 +286,33 @@ timeout = 3600
267286
.await;
268287
}
269288

289+
#[sqlx::test]
290+
async fn refresh_cancel_build_updates_check_run(pool: sqlx::PgPool) {
291+
BorsBuilder::new(pool)
292+
.github(gh_state_with_long_timeout())
293+
.run_test(|mut tester| async move {
294+
tester.post_comment("@bors try").await?;
295+
tester.expect_comments(1).await;
296+
297+
with_mocked_time(Duration::from_secs(4000), async {
298+
tester.cancel_timed_out_builds().await;
299+
})
300+
.await;
301+
tester.expect_comments(1).await;
302+
303+
tester.expect_check_run(
304+
&tester.default_pr().await.get_gh_pr().head_sha,
305+
TRY_BUILD_CHECK_RUN_NAME,
306+
"Bors try build",
307+
CheckRunStatus::Completed,
308+
Some(CheckRunConclusion::TimedOut),
309+
);
310+
311+
Ok(tester)
312+
})
313+
.await;
314+
}
315+
270316
#[sqlx::test]
271317
async fn refresh_cancel_workflow_after_timeout(pool: sqlx::PgPool) {
272318
let gh = BorsBuilder::new(pool)

src/bors/handlers/trybuild.rs

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use std::sync::Arc;
22

3-
use anyhow::{Context, anyhow};
4-
53
use crate::PgDbClient;
64
use crate::bors::RepositoryState;
75
use crate::bors::command::Parent;
@@ -20,6 +18,10 @@ use crate::github::api::operations::ForcePush;
2018
use crate::github::{CommitSha, GithubUser, LabelTrigger, MergeError, PullRequestNumber};
2119
use crate::permissions::PermissionType;
2220
use crate::utils::text::suppress_github_mentions;
21+
use anyhow::{Context, anyhow};
22+
use octocrab::params::checks::CheckRunOutput;
23+
use octocrab::params::checks::CheckRunStatus;
24+
use tracing::log;
2325

2426
use super::has_permission;
2527
use super::{PullRequestData, deny_request};
@@ -33,6 +35,9 @@ pub(super) const TRY_MERGE_BRANCH_NAME: &str = "automation/bors/try-merge";
3335
// This branch should run CI checks.
3436
pub(super) const TRY_BRANCH_NAME: &str = "automation/bors/try";
3537

38+
// The name of the check run seen in the GitHub UI.
39+
pub(super) const TRY_BUILD_CHECK_RUN_NAME: &str = "Bors try build";
40+
3641
/// Performs a so-called try build - merges the PR branch into a special branch designed
3742
/// for running CI checks.
3843
///
@@ -87,10 +92,41 @@ pub(super) async fn command_try_build(
8792
{
8893
MergeResult::Success(merge_sha) => {
8994
// If the merge was succesful, run CI with merged commit
90-
run_try_build(&repo.client, &db, &pr.db, merge_sha.clone(), base_sha).await?;
95+
let build_id =
96+
run_try_build(&repo.client, &db, &pr.db, merge_sha.clone(), base_sha).await?;
9197

9298
handle_label_trigger(repo, pr.number(), LabelTrigger::TryBuildStarted).await?;
9399

100+
// Create a check run to track the try build status in GitHub's UI.
101+
// This gets added to the PR's head SHA so GitHub shows UI in the checks tab and
102+
// the bottom of the PR.
103+
match repo
104+
.client
105+
.create_check_run(
106+
TRY_BUILD_CHECK_RUN_NAME,
107+
&pr.github.head.sha,
108+
CheckRunStatus::InProgress,
109+
CheckRunOutput {
110+
title: "Bors try build".to_string(),
111+
summary: "".to_string(),
112+
text: None,
113+
annotations: vec![],
114+
images: vec![],
115+
},
116+
&build_id.to_string(),
117+
)
118+
.await
119+
{
120+
Ok(check_run) => {
121+
db.update_build_check_run_id(build_id, check_run.id.into_inner() as i64)
122+
.await?;
123+
}
124+
Err(error) => {
125+
// Check runs aren't critical, don't block progress if they fail
126+
log::error!("Cannot create check run: {error:?}");
127+
}
128+
}
129+
94130
repo.client
95131
.post_comment(
96132
pr.number(),
@@ -176,17 +212,18 @@ async fn run_try_build(
176212
pr: &PullRequestModel,
177213
commit_sha: CommitSha,
178214
parent_sha: CommitSha,
179-
) -> anyhow::Result<()> {
215+
) -> anyhow::Result<i32> {
180216
client
181217
.set_branch_to_sha(TRY_BRANCH_NAME, &commit_sha, ForcePush::Yes)
182218
.await
183219
.map_err(|error| anyhow!("Cannot set try branch to main branch: {error:?}"))?;
184220

185-
db.attach_try_build(pr, TRY_BRANCH_NAME.to_string(), commit_sha, parent_sha)
221+
let build_id = db
222+
.attach_try_build(pr, TRY_BRANCH_NAME.to_string(), commit_sha, parent_sha)
186223
.await?;
187224

188225
tracing::info!("Try build started");
189-
Ok(())
226+
Ok(build_id)
190227
}
191228

192229
enum MergeResult {
@@ -307,13 +344,16 @@ fn auto_merge_commit_message(
307344

308345
#[cfg(test)]
309346
mod tests {
310-
use crate::bors::handlers::trybuild::{TRY_BRANCH_NAME, TRY_MERGE_BRANCH_NAME};
347+
use crate::bors::handlers::trybuild::{
348+
TRY_BRANCH_NAME, TRY_BUILD_CHECK_RUN_NAME, TRY_MERGE_BRANCH_NAME,
349+
};
311350
use crate::database::operations::get_all_workflows;
312351
use crate::github::CommitSha;
313352
use crate::tests::mocks::{
314353
BorsBuilder, Comment, GitHubState, User, Workflow, WorkflowEvent, default_pr_number,
315354
default_repo_name, run_test,
316355
};
356+
use octocrab::params::checks::{CheckRunConclusion, CheckRunStatus};
317357

318358
#[sqlx::test]
319359
async fn try_success(pool: sqlx::PgPool) {
@@ -861,4 +901,70 @@ try_failed = ["+foo", "+bar", "-baz"]
861901
})
862902
.await;
863903
}
904+
905+
#[sqlx::test]
906+
async fn try_build_creates_check_run(pool: sqlx::PgPool) {
907+
run_test(pool.clone(), |mut tester| async {
908+
tester.create_branch(TRY_BRANCH_NAME).expect_suites(1);
909+
tester.post_comment("@bors try").await?;
910+
tester.expect_comments(1).await;
911+
912+
tester.expect_check_run(
913+
&tester.default_pr().await.get_gh_pr().head_sha,
914+
TRY_BUILD_CHECK_RUN_NAME,
915+
"Bors try build",
916+
CheckRunStatus::InProgress,
917+
None,
918+
);
919+
920+
Ok(tester)
921+
})
922+
.await;
923+
}
924+
925+
#[sqlx::test]
926+
async fn try_build_updates_check_run_on_success(pool: sqlx::PgPool) {
927+
run_test(pool.clone(), |mut tester| async {
928+
tester.create_branch(TRY_BRANCH_NAME).expect_suites(1);
929+
tester.post_comment("@bors try").await?;
930+
tester.expect_comments(1).await;
931+
932+
tester.workflow_success(tester.try_branch()).await?;
933+
tester.expect_comments(1).await;
934+
935+
tester.expect_check_run(
936+
&tester.default_pr().await.get_gh_pr().head_sha,
937+
TRY_BUILD_CHECK_RUN_NAME,
938+
"Bors try build",
939+
CheckRunStatus::Completed,
940+
Some(CheckRunConclusion::Success),
941+
);
942+
943+
Ok(tester)
944+
})
945+
.await;
946+
}
947+
948+
#[sqlx::test]
949+
async fn try_build_updates_check_run_on_failure(pool: sqlx::PgPool) {
950+
run_test(pool.clone(), |mut tester| async {
951+
tester.create_branch(TRY_BRANCH_NAME).expect_suites(1);
952+
tester.post_comment("@bors try").await?;
953+
tester.expect_comments(1).await;
954+
955+
tester.workflow_failure(tester.try_branch()).await?;
956+
tester.expect_comments(1).await;
957+
958+
tester.expect_check_run(
959+
&tester.default_pr().await.get_gh_pr().head_sha,
960+
TRY_BUILD_CHECK_RUN_NAME,
961+
"Bors try build",
962+
CheckRunStatus::Completed,
963+
Some(CheckRunConclusion::Failure),
964+
);
965+
966+
Ok(tester)
967+
})
968+
.await;
969+
}
864970
}

src/bors/handlers/workflow.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use std::sync::Arc;
22
use std::time::Duration;
33

4+
use octocrab::params::checks::CheckRunConclusion;
5+
use octocrab::params::checks::CheckRunStatus;
6+
47
use crate::PgDbClient;
58
use crate::bors::CheckSuiteStatus;
69
use crate::bors::RepositoryState;
@@ -193,6 +196,18 @@ async fn try_complete_build(
193196

194197
handle_label_trigger(repo, pr.number, trigger).await?;
195198

199+
if let Some(check_run_id) = build.check_run_id {
200+
let (status, conclusion) = if has_failure {
201+
(CheckRunStatus::Completed, Some(CheckRunConclusion::Failure))
202+
} else {
203+
(CheckRunStatus::Completed, Some(CheckRunConclusion::Success))
204+
};
205+
206+
repo.client
207+
.update_check_run(check_run_id as u64, status, conclusion, None)
208+
.await?;
209+
}
210+
196211
let message = if !has_failure {
197212
tracing::info!("Workflow succeeded");
198213
try_build_succeeded_comment(&workflows, payload.commit_sha, &build)

src/database/client.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use super::operations::{
1515
get_prs_with_unknown_mergeable_state, get_pull_request, get_repository, get_repository_by_name,
1616
get_running_builds, get_workflow_urls_for_build, get_workflows_for_build,
1717
insert_repo_if_not_exists, set_pr_assignees, set_pr_priority, set_pr_rollup, set_pr_status,
18-
unapprove_pull_request, undelegate_pull_request, update_build_status,
19-
update_mergeable_states_by_base_branch, update_pr_mergeable_state, update_pr_try_build_id,
20-
update_workflow_status, upsert_pull_request, upsert_repository,
18+
unapprove_pull_request, undelegate_pull_request, update_build_check_run_id,
19+
update_build_status, update_mergeable_states_by_base_branch, update_pr_mergeable_state,
20+
update_pr_try_build_id, update_workflow_status, upsert_pull_request, upsert_repository,
2121
};
2222
use super::{ApprovalInfo, DelegatedPermission, MergeableState, RunId, UpsertPullRequestParams};
2323

@@ -181,13 +181,13 @@ impl PgDbClient {
181181
branch: String,
182182
commit_sha: CommitSha,
183183
parent: CommitSha,
184-
) -> anyhow::Result<()> {
184+
) -> anyhow::Result<i32> {
185185
let mut tx = self.pool.begin().await?;
186186
let build_id =
187187
create_build(&mut *tx, &pr.repository, &branch, &commit_sha, &parent).await?;
188188
update_pr_try_build_id(&mut *tx, pr.id, build_id).await?;
189189
tx.commit().await?;
190-
Ok(())
190+
Ok(build_id)
191191
}
192192

193193
pub async fn find_build(
@@ -214,6 +214,14 @@ impl PgDbClient {
214214
update_build_status(&self.pool, build.id, status).await
215215
}
216216

217+
pub async fn update_build_check_run_id(
218+
&self,
219+
build_id: i32,
220+
check_run_id: i64,
221+
) -> anyhow::Result<()> {
222+
update_build_check_run_id(&self.pool, build_id, check_run_id).await
223+
}
224+
217225
pub async fn create_workflow(
218226
&self,
219227
build: &BuildModel,

src/database/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ pub struct BuildModel {
315315
/// The base commit SHA that this build is merged with (e.g., main branch HEAD).
316316
pub parent: String,
317317
pub created_at: DateTime<Utc>,
318+
/// The ID of the check run associated with the build.
318319
pub check_run_id: Option<i64>,
319320
}
320321

src/database/operations.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,24 @@ pub(crate) async fn upsert_repository(
946946
.await
947947
}
948948

949+
pub(crate) async fn update_build_check_run_id(
950+
executor: impl PgExecutor<'_>,
951+
build_id: i32,
952+
check_run_id: i64,
953+
) -> anyhow::Result<()> {
954+
measure_db_query("update_build_check_run_id", || async {
955+
sqlx::query!(
956+
"UPDATE build SET check_run_id = $1 WHERE id = $2",
957+
check_run_id,
958+
build_id
959+
)
960+
.execute(executor)
961+
.await?;
962+
Ok(())
963+
})
964+
.await
965+
}
966+
949967
/// Removes the auto build associated with a PR and deletes the build record (if one exists).
950968
pub(crate) async fn delete_auto_build(
951969
executor: impl PgExecutor<'_>,

0 commit comments

Comments
 (0)