Skip to content

Commit f2be2eb

Browse files
authored
fix: block landing until exact-head checks settle (#10669)
* fix: wait for exact-head PR checks before landing * docs: refresh CLI waiver reference * docs: preserve generated CLI reference EOF
1 parent 521a716 commit f2be2eb

6 files changed

Lines changed: 505 additions & 37 deletions

File tree

crates/homeboy-cli/src/commands/git/args.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,14 @@ pub(super) enum PrCommand {
434434
/// Retry merge after this many base-branch-modified races.
435435
#[arg(long, default_value_t = 1)]
436436
max_base_retries: usize,
437+
438+
/// Maximum seconds to wait for all checks on the exact PR head to become terminal.
439+
#[arg(long, default_value_t = 900)]
440+
max_check_wait_seconds: u64,
441+
442+
/// Waive one non-required failed check as HEAD_SHA|CHECK_NAME|APPROVER.
443+
#[arg(long = "check-waiver", value_name = "HEAD_SHA|CHECK_NAME|APPROVER")]
444+
check_waivers: Vec<String>,
437445
},
438446
}
439447

crates/homeboy-cli/src/commands/git/pr.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use homeboy::core::git::{
44
PrPolicyMergeOptions, PrPolicyOpenOptions, PrPolicyTargetRefs, PrRefreshOptions,
55
PrRefreshStrategy,
66
};
7+
use std::time::Duration;
78

89
use super::args::{ComponentPathArgs, PrArgs, PrCommand, PrPolicyArgs, PrPolicyCommand};
910
use super::helpers::{parse_pr_state, read_lines_file, resolve_body};
@@ -226,7 +227,13 @@ pub(super) fn run_pr(args: PrArgs) -> CmdResult<GitCommandOutput> {
226227
refresh_helper,
227228
refresh_helper_args,
228229
max_base_retries,
230+
max_check_wait_seconds,
231+
check_waivers,
229232
} => {
233+
let check_waivers = check_waivers
234+
.iter()
235+
.map(|raw| parse_check_waiver(raw))
236+
.collect::<homeboy::core::Result<Vec<_>>>()?;
230237
let output = git::land_prs(PrLandOptions {
231238
repo,
232239
prs,
@@ -238,13 +245,43 @@ pub(super) fn run_pr(args: PrArgs) -> CmdResult<GitCommandOutput> {
238245
args: refresh_helper_args,
239246
}),
240247
max_base_retries,
248+
check_wait_timeout: Duration::from_secs(max_check_wait_seconds),
249+
check_poll_interval: Duration::from_secs(5),
250+
check_waivers,
241251
})?;
242252
let exit = if output.summary.blocked > 0 { 1 } else { 0 };
243253
Ok((GitCommandOutput::Land(output), exit))
244254
}
245255
}
246256
}
247257

258+
fn parse_check_waiver(raw: &str) -> homeboy::core::Result<git::PrCheckWaiver> {
259+
let mut parts = raw.splitn(3, '|');
260+
let (Some(head_sha), Some(name), Some(approved_by)) =
261+
(parts.next(), parts.next(), parts.next())
262+
else {
263+
return Err(homeboy::core::Error::validation_invalid_argument(
264+
"check-waiver",
265+
"expected HEAD_SHA|CHECK_NAME|APPROVER",
266+
Some(raw.to_string()),
267+
None,
268+
));
269+
};
270+
if head_sha.trim().is_empty() || name.trim().is_empty() || approved_by.trim().is_empty() {
271+
return Err(homeboy::core::Error::validation_invalid_argument(
272+
"check-waiver",
273+
"head SHA, check name, and approver must all be non-empty",
274+
Some(raw.to_string()),
275+
None,
276+
));
277+
}
278+
Ok(git::PrCheckWaiver {
279+
head_sha: head_sha.to_string(),
280+
name: name.to_string(),
281+
approved_by: approved_by.to_string(),
282+
})
283+
}
284+
248285
fn parse_pr_refresh_strategy(value: &str) -> homeboy::core::Result<PrRefreshStrategy> {
249286
match value {
250287
"auto" => Ok(PrRefreshStrategy::Auto),

crates/homeboy-core/src/git/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub use operations_tags::{
7272
is_ancestor, remote_branch_commit, remote_tag_commit, short_head_revision_at, tag, tag_at,
7373
tag_exists_locally, tag_exists_on_remote,
7474
};
75-
pub use pr_land::{land_prs, PrLandOptions, PrLandOutput, PrLandRefreshHelper};
75+
pub use pr_land::{land_prs, PrCheckWaiver, PrLandOptions, PrLandOutput, PrLandRefreshHelper};
7676
pub use pr_policy::{
7777
evaluate_merge_policy, evaluate_open_policy, PrPolicyContext, PrPolicyDecision, PrPolicyFile,
7878
PrPolicyMergeOptions, PrPolicyMode, PrPolicyOpenOptions, PrPolicyRules, PrPolicyTargetRefs,

0 commit comments

Comments
 (0)