@@ -4,8 +4,9 @@ mod tests;
4
4
5
5
use self :: api:: { BranchProtectionOp , TeamPrivacy , TeamRole } ;
6
6
use crate :: github:: api:: { GithubRead , Login , PushAllowanceActor , RepoPermission , RepoSettings } ;
7
+ use anyhow:: anyhow;
7
8
use log:: debug;
8
- use rust_team_data:: v1:: { Bot , BranchProtectionMode , MergeBot } ;
9
+ use rust_team_data:: v1:: { Bot , BranchProtectionMode , GitHubTeam , MergeBot } ;
9
10
use std:: collections:: { HashMap , HashSet } ;
10
11
use std:: fmt:: { Display , Formatter , Write } ;
11
12
@@ -73,6 +74,7 @@ struct SyncGitHub {
73
74
repos : Vec < rust_team_data:: v1:: Repo > ,
74
75
usernames_cache : HashMap < u64 , String > ,
75
76
org_owners : HashMap < OrgName , HashSet < u64 > > ,
77
+ org_members : HashMap < OrgName , HashSet < u64 > > ,
76
78
org_apps : HashMap < OrgName , Vec < OrgAppInstallation > > ,
77
79
}
78
80
@@ -103,10 +105,12 @@ impl SyncGitHub {
103
105
. collect :: < HashSet < _ > > ( ) ;
104
106
105
107
let mut org_owners = HashMap :: new ( ) ;
108
+ let mut org_members = HashMap :: new ( ) ;
106
109
let mut org_apps = HashMap :: new ( ) ;
107
110
108
111
for org in & orgs {
109
112
org_owners. insert ( ( * org) . to_string ( ) , github. org_owners ( org) ?) ;
113
+ org_members. insert ( ( * org) . to_string ( ) , github. org_members ( org) ?) ;
110
114
111
115
let mut installations: Vec < OrgAppInstallation > = vec ! [ ] ;
112
116
@@ -134,17 +138,21 @@ impl SyncGitHub {
134
138
repos,
135
139
usernames_cache,
136
140
org_owners,
141
+ org_members,
137
142
org_apps,
138
143
} )
139
144
}
140
145
141
146
pub ( crate ) fn diff_all ( & self ) -> anyhow:: Result < Diff > {
142
147
let team_diffs = self . diff_teams ( ) ?;
143
148
let repo_diffs = self . diff_repos ( ) ?;
149
+ let org_team_members = self . map_teams_to_org ( ) ?;
150
+ let toml_github_diffs = self . diff_teams_gh_org ( org_team_members) ?;
144
151
145
152
Ok ( Diff {
146
153
team_diffs,
147
154
repo_diffs,
155
+ toml_github_diffs,
148
156
} )
149
157
}
150
158
@@ -195,6 +203,66 @@ impl SyncGitHub {
195
203
Ok ( diffs)
196
204
}
197
205
206
+ // collect all org and respective teams members in a HashMap
207
+ fn map_teams_to_org ( & self ) -> anyhow:: Result < HashMap < String , HashSet < u64 > > > {
208
+ let mut org_team_members: HashMap < String , HashSet < u64 > > = HashMap :: new ( ) ;
209
+
210
+ for team in & self . teams {
211
+ let team_org;
212
+ // get the team github org through the corresponding github team
213
+ if let Some ( gh) = & team. github {
214
+ let github_teams = & gh. teams ;
215
+ let github_team: & GitHubTeam = github_teams
216
+ . iter ( )
217
+ . find ( |& gt| gt. name == team. name )
218
+ . expect ( "Team Not Found" ) ;
219
+ team_org = github_team. org . clone ( ) ;
220
+ } else {
221
+ return Err ( anyhow ! (
222
+ "TeamGitHub object not found, got {:?}" ,
223
+ & team. github
224
+ ) ) ;
225
+ }
226
+
227
+ let team_members_github_id: HashSet < u64 > =
228
+ team. members . iter ( ) . map ( |member| member. github_id ) . collect ( ) ;
229
+
230
+ org_team_members
231
+ . entry ( team_org)
232
+ . or_default ( )
233
+ . extend ( team_members_github_id) ;
234
+ }
235
+ Ok ( org_team_members)
236
+ }
237
+
238
+ // create diff against github org members against toml team members
239
+ fn diff_teams_gh_org (
240
+ & self ,
241
+ org_team_members : HashMap < String , HashSet < u64 > > ,
242
+ ) -> anyhow:: Result < OrgMembershipDiff > {
243
+ let mut org_with_members_to_be_removed: HashMap < String , HashSet < String > > = HashMap :: new ( ) ;
244
+
245
+ for ( gh_org, toml_members_across_teams) in org_team_members. into_iter ( ) {
246
+ let gh_org_members = self . org_members . get ( & gh_org) . unwrap ( ) ;
247
+
248
+ let mut members_to_be_removed = HashSet :: new ( ) ;
249
+
250
+ for toml_member in toml_members_across_teams {
251
+ if !gh_org_members. contains ( & toml_member. clone ( ) ) {
252
+ members_to_be_removed. insert ( self . usernames_cache [ & toml_member] . clone ( ) ) ;
253
+ }
254
+ }
255
+ org_with_members_to_be_removed
256
+ . entry ( gh_org)
257
+ . or_default ( )
258
+ . extend ( members_to_be_removed) ;
259
+ }
260
+
261
+ Ok ( OrgMembershipDiff :: Delete ( DeleteOrgMembershipDiff {
262
+ org_with_members : org_with_members_to_be_removed,
263
+ } ) )
264
+ }
265
+
198
266
fn diff_team ( & self , github_team : & rust_team_data:: v1:: GitHubTeam ) -> anyhow:: Result < TeamDiff > {
199
267
// Ensure the team exists and is consistent
200
268
let team = match self . github . team ( & github_team. org , & github_team. name ) ? {
@@ -667,6 +735,7 @@ const BOTS_TEAMS: &[&str] = &["bors", "highfive", "rfcbot", "bots"];
667
735
pub ( crate ) struct Diff {
668
736
team_diffs : Vec < TeamDiff > ,
669
737
repo_diffs : Vec < RepoDiff > ,
738
+ toml_github_diffs : OrgMembershipDiff ,
670
739
}
671
740
672
741
impl Diff {
@@ -679,6 +748,8 @@ impl Diff {
679
748
repo_diff. apply ( sync) ?;
680
749
}
681
750
751
+ self . toml_github_diffs . apply ( sync) ?;
752
+
682
753
Ok ( ( ) )
683
754
}
684
755
}
@@ -720,6 +791,55 @@ impl std::fmt::Display for RepoDiff {
720
791
}
721
792
}
722
793
794
+ #[ derive( Debug ) ]
795
+
796
+ enum OrgMembershipDiff {
797
+ Delete ( DeleteOrgMembershipDiff ) ,
798
+ }
799
+
800
+ impl OrgMembershipDiff {
801
+ fn apply ( self , sync : & GitHubWrite ) -> anyhow:: Result < ( ) > {
802
+ match self {
803
+ OrgMembershipDiff :: Delete ( d) => d. apply ( sync) ?,
804
+ }
805
+
806
+ Ok ( ( ) )
807
+ }
808
+ }
809
+
810
+ impl std:: fmt:: Display for OrgMembershipDiff {
811
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
812
+ match self {
813
+ OrgMembershipDiff :: Delete ( d) => write ! ( f, "{d}" ) ,
814
+ }
815
+ }
816
+ }
817
+
818
+ #[ derive( Debug ) ]
819
+
820
+ struct DeleteOrgMembershipDiff {
821
+ org_with_members : HashMap < String , HashSet < String > > ,
822
+ }
823
+
824
+ impl DeleteOrgMembershipDiff {
825
+ fn apply ( self , sync : & GitHubWrite ) -> anyhow:: Result < ( ) > {
826
+ for ( gh_org, members) in self . org_with_members . iter ( ) {
827
+ for member in members {
828
+ sync. remove_gh_member_from_org ( gh_org, member) ?;
829
+ }
830
+ }
831
+
832
+ Ok ( ( ) )
833
+ }
834
+ }
835
+
836
+ impl std:: fmt:: Display for DeleteOrgMembershipDiff {
837
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
838
+ writeln ! ( f, "❌ Deleting members '{:?}'" , self . org_with_members) ?;
839
+ Ok ( ( ) )
840
+ }
841
+ }
842
+
723
843
struct CreateRepoDiff {
724
844
org : String ,
725
845
name : String ,
0 commit comments