33mod tests;
44
55use self :: api:: { BranchProtectionOp , TeamPrivacy , TeamRole } ;
6+ use crate :: Config ;
67use crate :: github:: api:: { GithubRead , Login , PushAllowanceActor , RepoPermission , RepoSettings } ;
78use log:: debug;
89use rust_team_data:: v1:: { Bot , BranchProtectionMode , MergeBot } ;
@@ -18,8 +19,9 @@ pub(crate) fn create_diff(
1819 github : Box < dyn GithubRead > ,
1920 teams : Vec < rust_team_data:: v1:: Team > ,
2021 repos : Vec < rust_team_data:: v1:: Repo > ,
22+ config : Config ,
2123) -> anyhow:: Result < Diff > {
22- let github = SyncGitHub :: new ( github, teams, repos) ?;
24+ let github = SyncGitHub :: new ( github, teams, repos, config ) ?;
2325 github. diff_all ( )
2426}
2527
@@ -29,6 +31,7 @@ struct SyncGitHub {
2931 github : Box < dyn GithubRead > ,
3032 teams : Vec < rust_team_data:: v1:: Team > ,
3133 repos : Vec < rust_team_data:: v1:: Repo > ,
34+ config : Config ,
3235 usernames_cache : HashMap < u64 , String > ,
3336 org_owners : HashMap < OrgName , HashSet < u64 > > ,
3437 org_members : HashMap < OrgName , HashMap < u64 , String > > ,
@@ -39,6 +42,7 @@ impl SyncGitHub {
3942 github : Box < dyn GithubRead > ,
4043 teams : Vec < rust_team_data:: v1:: Team > ,
4144 repos : Vec < rust_team_data:: v1:: Repo > ,
45+ config : Config ,
4246 ) -> anyhow:: Result < Self > {
4347 debug ! ( "caching mapping between user ids and usernames" ) ;
4448 let users = teams
@@ -72,6 +76,7 @@ impl SyncGitHub {
7276 github,
7377 teams,
7478 repos,
79+ config,
7580 usernames_cache,
7681 org_owners,
7782 org_members,
@@ -90,7 +95,7 @@ impl SyncGitHub {
9095 } )
9196 }
9297
93- // Collect all org members from the respective teams
98+ /// Collect all org members from the respective teams
9499 fn get_org_members_from_teams ( & self ) -> HashMap < OrgName , HashSet < u64 > > {
95100 let mut org_team_members: HashMap < OrgName , HashSet < u64 > > = HashMap :: new ( ) ;
96101
@@ -107,22 +112,24 @@ impl SyncGitHub {
107112 org_team_members
108113 }
109114
110- // Diff organization memberships between TOML teams and GitHub
115+ /// Diff organization memberships between TOML teams and GitHub
111116 fn diff_org_memberships ( & self ) -> anyhow:: Result < Vec < OrgMembershipDiff > > {
112117 let toml_org_team_members = self . get_org_members_from_teams ( ) ;
113118
114119 let mut org_diffs: BTreeMap < String , OrgMembershipDiff > = BTreeMap :: new ( ) ;
115120
116121 for ( org, toml_members) in toml_org_team_members {
122+ // Skip independent organizations - they manage their own members
123+ if self . config . independent_github_orgs . contains ( & org) {
124+ debug ! ( "Skipping member sync for independent organization: {}" , org) ;
125+ continue ;
126+ }
127+
117128 let Some ( gh_org_members) = self . org_members . get ( & org) else {
118129 panic ! ( "GitHub organization {org} not found" ) ;
119130 } ;
120131
121- // Remove all members that are in TOML teams
122- let mut members_to_remove = gh_org_members. clone ( ) ;
123- for member in toml_members {
124- members_to_remove. remove ( & member) ;
125- }
132+ let members_to_remove = self . members_to_remove ( toml_members, gh_org_members) ;
126133
127134 // The rest are members that should be removed
128135 if !members_to_remove. is_empty ( ) {
@@ -142,6 +149,34 @@ impl SyncGitHub {
142149 Ok ( org_diffs. into_values ( ) . collect ( ) )
143150 }
144151
152+ /// Return GitHub members that should be removed from the organization.
153+ fn members_to_remove (
154+ & self ,
155+ toml_members : HashSet < u64 > ,
156+ gh_org_members : & HashMap < u64 , String > ,
157+ ) -> HashMap < u64 , String > {
158+ // Initialize `members_to_remove` to all GitHub members in the org.
159+ // Next, we'll delete members from `members_to_remove` that don't respect certain criteria.
160+ let mut members_to_remove = gh_org_members. clone ( ) ;
161+
162+ // People who belong to a team should stay in the org.
163+ for member in toml_members {
164+ members_to_remove. remove ( & member) ;
165+ }
166+
167+ // Members that are explicitly allowed in the `config.toml` file should stay in the org.
168+ for allowed_member in & self . config . special_org_members {
169+ if let Some ( member_to_retain) = members_to_remove
170+ . iter ( )
171+ . find ( |( _, username) | username == & allowed_member)
172+ . map ( |( id, _) | * id)
173+ {
174+ members_to_remove. remove ( & member_to_retain) ;
175+ }
176+ }
177+ members_to_remove
178+ }
179+
145180 fn diff_teams ( & self ) -> anyhow:: Result < Vec < TeamDiff > > {
146181 let mut diffs = Vec :: new ( ) ;
147182 let mut unseen_github_teams = HashMap :: new ( ) ;
@@ -735,7 +770,7 @@ struct OrgMembershipDiff {
735770impl OrgMembershipDiff {
736771 fn apply ( self , sync : & GitHubWrite ) -> anyhow:: Result < ( ) > {
737772 for member in & self . members_to_remove {
738- sync. remove_gh_member_from_org ( & self . org , & member) ?;
773+ sync. remove_gh_member_from_org ( & self . org , member) ?;
739774 }
740775
741776 Ok ( ( ) )
0 commit comments