Skip to content

Commit aa4aaa5

Browse files
committed
feat: add logs and fix tests
1 parent b49faca commit aa4aaa5

File tree

2 files changed

+86
-41
lines changed

2 files changed

+86
-41
lines changed

sync-team/src/github/mod.rs

Lines changed: 85 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod tests;
55
use self::api::{BranchProtectionOp, TeamPrivacy, TeamRole};
66
use crate::Config;
77
use crate::github::api::{GithubRead, Login, PushAllowanceActor, RepoPermission, RepoSettings};
8+
use anyhow::Context;
89
use log::debug;
910
use rust_team_data::v1::{Bot, BranchProtectionMode, MergeBot};
1011
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
@@ -981,6 +982,7 @@ pub(crate) fn construct_bypass_actors(
981982
) -> anyhow::Result<Vec<api::RulesetBypassActor>> {
982983
let mut bypass_actors = Vec::new();
983984

985+
// Resolve team bypass actors
984986
for team_name in &branch_protection.allowed_merge_teams {
985987
match github_write.resolve_team_database_id(org, team_name) {
986988
Ok(Some(actor_id)) => {
@@ -992,40 +994,39 @@ pub(crate) fn construct_bypass_actors(
992994
}
993995
Ok(None) => {
994996
debug!(
995-
"Warning: Could not resolve database ID for team '{}/{}'. \
996-
The team may not exist in the organization.",
997+
"Team '{}/{}' not found; skipping bypass actor. \
998+
Verify the team exists in the organization.",
997999
org, team_name
9981000
);
9991001
}
10001002
Err(e) => {
1001-
anyhow::bail!(
1002-
"Failed to resolve database ID for team '{}/{}': {}",
1003-
org,
1004-
team_name,
1005-
e
1006-
);
1003+
return Err(e).context(format!(
1004+
"Failed to resolve team '{}/{}' for bypass actor",
1005+
org, team_name
1006+
));
10071007
}
10081008
}
10091009
}
10101010

1011-
// Note: GitHub API has limited support for individual user bypass actors.
1012-
// OrganizationAdmin with actor_id=1 grants bypass to all org admins.
1013-
// For individual users, they must be added to a team and use allowed_merge_teams.
1011+
// Add OrganizationAdmin bypass actor if allowed_merge_users is specified.
1012+
// Note: GitHub API limitation - cannot add individual users as bypass actors.
1013+
// OrganizationAdmin with actor_id=1 grants bypass to ALL organization admins.
1014+
// For granular per-user control, use allowed_merge_teams with a team containing specific users.
10141015
if !branch_protection.allowed_merge_users.is_empty() {
10151016
debug!(
1016-
"Warning: Individual user bypass actors (allowed_merge_users) have limited API support. \
1017-
Users: {:?}. Only organization admins can bypass. \
1018-
For granular control, add users to a team and use allowed_merge_teams instead.",
1017+
"Using OrganizationAdmin bypass actor for allowed_merge_users: {:?}. \
1018+
Note: This grants bypass to ALL org admins, not just specified users. \
1019+
For per-user control, use allowed_merge_teams instead.",
10191020
branch_protection.allowed_merge_users
10201021
);
1021-
// Add OrganizationAdmin bypass actor (applies to all org admins)
10221022
bypass_actors.push(api::RulesetBypassActor {
10231023
actor_id: Some(api::ActorId::Id(1)),
10241024
actor_type: api::RulesetActorType::OrganizationAdmin,
10251025
bypass_mode: Some(api::RulesetBypassMode::Always),
10261026
});
10271027
}
10281028

1029+
// Resolve bot integration bypass actors
10291030
for merge_bot in &branch_protection.merge_bots {
10301031
let user_login = match merge_bot {
10311032
MergeBot::Homu => "bors",
@@ -1041,17 +1042,16 @@ pub(crate) fn construct_bypass_actors(
10411042
}
10421043
Ok(None) => {
10431044
debug!(
1044-
"Warning: Could not resolve database ID for bot '{}'. \
1045-
This bot may not be installed in the organization.",
1046-
user_login
1045+
"Bot '{}' not found in organization '{}'; skipping bypass actor. \
1046+
Verify the bot is installed and has access.",
1047+
user_login, org
10471048
);
10481049
}
10491050
Err(e) => {
1050-
anyhow::bail!(
1051-
"Failed to resolve database ID for bot '{}': {}",
1052-
user_login,
1053-
e
1054-
);
1051+
return Err(e).context(format!(
1052+
"Failed to resolve bot '{}' for bypass actor",
1053+
user_login
1054+
));
10551055
}
10561056
}
10571057
}
@@ -1355,21 +1355,9 @@ impl std::fmt::Display for CreateRepoDiff {
13551355

13561356
if !rulesets.is_empty() {
13571357
writeln!(f, " Rulesets:")?;
1358-
for (ruleset, _branch_protection) in rulesets {
1359-
let id_str = ruleset.id.map_or("new".to_string(), |id| id.to_string());
1360-
writeln!(f, " - {} (ID: {})", ruleset.name, id_str)?;
1361-
if let Some(conditions) = &ruleset.conditions
1362-
&& let Some(ref_name) = &conditions.ref_name
1363-
{
1364-
writeln!(f, " Branches: {}", ref_name.include.join(", "))?;
1365-
}
1366-
if ruleset
1367-
.rules
1368-
.iter()
1369-
.any(|r| matches!(r, api::RulesetRule::MergeQueue { .. }))
1370-
{
1371-
writeln!(f, " Merge Queue: Enabled")?;
1372-
}
1358+
for (ruleset, branch_protection) in rulesets {
1359+
writeln!(f, " {}", ruleset.name)?;
1360+
log_ruleset(ruleset, None, Some(branch_protection), &mut f)?;
13731361
}
13741362
}
13751363

@@ -1805,6 +1793,7 @@ fn log_branch_protection(
18051793
fn log_ruleset(
18061794
current: &api::Ruleset,
18071795
new: Option<&api::Ruleset>,
1796+
branch_protection: Option<&rust_team_data::v1::BranchProtection>,
18081797
mut result: impl Write,
18091798
) -> std::fmt::Result {
18101799
macro_rules! log {
@@ -1860,7 +1849,28 @@ fn log_ruleset(
18601849
&& !bypass_actors.is_empty()
18611850
{
18621851
let new_bypass = new.and_then(|n| n.bypass_actors.as_ref());
1863-
log!("Bypass Actors", bypass_actors, new_bypass);
1852+
if new_bypass.is_some() {
1853+
log!("Bypass Actors", bypass_actors, new_bypass);
1854+
} else {
1855+
writeln!(result, " Bypass Actors:")?;
1856+
for actor in bypass_actors {
1857+
let actor_id_str = match &actor.actor_id {
1858+
Some(api::ActorId::Id(id)) => id.to_string(),
1859+
Some(api::ActorId::Null) => "null".to_string(),
1860+
None => "omitted".to_string(),
1861+
};
1862+
let mode_str = actor.bypass_mode.as_ref().map_or("default", |m| match m {
1863+
api::RulesetBypassMode::Always => "always",
1864+
api::RulesetBypassMode::PullRequest => "pull_request",
1865+
api::RulesetBypassMode::Exempt => "exempt",
1866+
});
1867+
writeln!(
1868+
result,
1869+
" - Type: {:?}, ID: {}, Mode: {}",
1870+
actor.actor_type, actor_id_str, mode_str
1871+
)?;
1872+
}
1873+
}
18641874
}
18651875

18661876
// Log individual rules
@@ -1977,6 +1987,36 @@ fn log_ruleset(
19771987
}
19781988
}
19791989

1990+
// Log expected bypass actors if branch protection config is provided
1991+
if let Some(bp) = branch_protection {
1992+
if !bp.allowed_merge_teams.is_empty()
1993+
|| !bp.allowed_merge_users.is_empty()
1994+
|| !bp.merge_bots.is_empty()
1995+
{
1996+
writeln!(result, " Expected Bypass Actors:")?;
1997+
1998+
for team in &bp.allowed_merge_teams {
1999+
writeln!(result, " - Team: {} (Mode: always)", team)?;
2000+
}
2001+
2002+
if !bp.allowed_merge_users.is_empty() {
2003+
writeln!(
2004+
result,
2005+
" - OrganizationAdmin: ID=1 (Mode: always) [Note: Grants bypass to all org admins, requested users: {}]",
2006+
bp.allowed_merge_users.join(", ")
2007+
)?;
2008+
}
2009+
2010+
for bot in &bp.merge_bots {
2011+
let bot_name = match bot {
2012+
MergeBot::Homu => "bors",
2013+
MergeBot::RustTimer => "rust-timer",
2014+
};
2015+
writeln!(result, " - Integration: {} (Mode: always)", bot_name)?;
2016+
}
2017+
}
2018+
}
2019+
19802020
Ok(())
19812021
}
19822022

@@ -2051,8 +2091,12 @@ impl std::fmt::Display for RulesetDiff {
20512091
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20522092
writeln!(f, " {}", self.name)?;
20532093
match &self.operation {
2054-
RulesetDiffOperation::Create(ruleset) => log_ruleset(ruleset, None, f),
2055-
RulesetDiffOperation::Update(_, old, new) => log_ruleset(old, Some(new), f),
2094+
RulesetDiffOperation::Create(ruleset) => {
2095+
log_ruleset(ruleset, None, Some(&self.branch_protection), &mut *f)
2096+
}
2097+
RulesetDiffOperation::Update(_, old, new) => {
2098+
log_ruleset(old, Some(new), Some(&self.branch_protection), &mut *f)
2099+
}
20562100
RulesetDiffOperation::Delete(_) => {
20572101
writeln!(f, " Deleting ruleset")
20582102
}

sync-team/src/github/tests/test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ pub struct BranchProtectionBuilder {
424424
pub dismiss_stale_review: bool,
425425
pub mode: BranchProtectionMode,
426426
pub allowed_merge_teams: Vec<String>,
427+
pub allowed_merge_users: Vec<String>,
427428
pub merge_bots: Vec<MergeBot>,
428429
}
429430

0 commit comments

Comments
 (0)