3
3
mod tests;
4
4
5
5
use self :: api:: { BranchProtectionOp , TeamPrivacy , TeamRole } ;
6
+ use crate :: Config ;
6
7
use crate :: github:: api:: { GithubRead , Login , PushAllowanceActor , RepoPermission , RepoSettings } ;
7
8
use log:: debug;
8
9
use rust_team_data:: v1:: { Bot , BranchProtectionMode , MergeBot } ;
@@ -18,8 +19,9 @@ pub(crate) fn create_diff(
18
19
github : Box < dyn GithubRead > ,
19
20
teams : Vec < rust_team_data:: v1:: Team > ,
20
21
repos : Vec < rust_team_data:: v1:: Repo > ,
22
+ config : Config ,
21
23
) -> anyhow:: Result < Diff > {
22
- let github = SyncGitHub :: new ( github, teams, repos) ?;
24
+ let github = SyncGitHub :: new ( github, teams, repos, config ) ?;
23
25
github. diff_all ( )
24
26
}
25
27
@@ -29,6 +31,7 @@ struct SyncGitHub {
29
31
github : Box < dyn GithubRead > ,
30
32
teams : Vec < rust_team_data:: v1:: Team > ,
31
33
repos : Vec < rust_team_data:: v1:: Repo > ,
34
+ config : Config ,
32
35
usernames_cache : HashMap < u64 , String > ,
33
36
org_owners : HashMap < OrgName , HashSet < u64 > > ,
34
37
org_members : HashMap < OrgName , HashMap < u64 , String > > ,
@@ -39,6 +42,7 @@ impl SyncGitHub {
39
42
github : Box < dyn GithubRead > ,
40
43
teams : Vec < rust_team_data:: v1:: Team > ,
41
44
repos : Vec < rust_team_data:: v1:: Repo > ,
45
+ config : Config ,
42
46
) -> anyhow:: Result < Self > {
43
47
debug ! ( "caching mapping between user ids and usernames" ) ;
44
48
let users = teams
@@ -72,6 +76,7 @@ impl SyncGitHub {
72
76
github,
73
77
teams,
74
78
repos,
79
+ config,
75
80
usernames_cache,
76
81
org_owners,
77
82
org_members,
@@ -90,7 +95,7 @@ impl SyncGitHub {
90
95
} )
91
96
}
92
97
93
- // Collect all org members from the respective teams
98
+ /// Collect all org members from the respective teams
94
99
fn get_org_members_from_teams ( & self ) -> HashMap < OrgName , HashSet < u64 > > {
95
100
let mut org_team_members: HashMap < OrgName , HashSet < u64 > > = HashMap :: new ( ) ;
96
101
@@ -107,22 +112,24 @@ impl SyncGitHub {
107
112
org_team_members
108
113
}
109
114
110
- // Diff organization memberships between TOML teams and GitHub
115
+ /// Diff organization memberships between TOML teams and GitHub
111
116
fn diff_org_memberships ( & self ) -> anyhow:: Result < Vec < OrgMembershipDiff > > {
112
117
let toml_org_team_members = self . get_org_members_from_teams ( ) ;
113
118
114
119
let mut org_diffs: BTreeMap < String , OrgMembershipDiff > = BTreeMap :: new ( ) ;
115
120
116
121
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
+
117
128
let Some ( gh_org_members) = self . org_members . get ( & org) else {
118
129
panic ! ( "GitHub organization {org} not found" ) ;
119
130
} ;
120
131
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) ;
126
133
127
134
// The rest are members that should be removed
128
135
if !members_to_remove. is_empty ( ) {
@@ -142,6 +149,34 @@ impl SyncGitHub {
142
149
Ok ( org_diffs. into_values ( ) . collect ( ) )
143
150
}
144
151
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
+
145
180
fn diff_teams ( & self ) -> anyhow:: Result < Vec < TeamDiff > > {
146
181
let mut diffs = Vec :: new ( ) ;
147
182
let mut unseen_github_teams = HashMap :: new ( ) ;
@@ -755,7 +790,7 @@ struct OrgMembershipDiff {
755
790
impl OrgMembershipDiff {
756
791
fn apply ( self , sync : & GitHubWrite ) -> anyhow:: Result < ( ) > {
757
792
for member in & self . members_to_remove {
758
- sync. remove_gh_member_from_org ( & self . org , & member) ?;
793
+ sync. remove_gh_member_from_org ( & self . org , member) ?;
759
794
}
760
795
761
796
Ok ( ( ) )
0 commit comments