@@ -73,6 +73,7 @@ struct SyncGitHub {
7373 repos : Vec < rust_team_data:: v1:: Repo > ,
7474 usernames_cache : HashMap < u64 , String > ,
7575 org_owners : HashMap < OrgName , HashSet < u64 > > ,
76+ org_members : HashMap < OrgName , HashSet < u64 > > ,
7677 org_apps : HashMap < OrgName , Vec < OrgAppInstallation > > ,
7778}
7879
@@ -103,10 +104,12 @@ impl SyncGitHub {
103104 . collect :: < HashSet < _ > > ( ) ;
104105
105106 let mut org_owners = HashMap :: new ( ) ;
107+ let mut org_members = HashMap :: new ( ) ;
106108 let mut org_apps = HashMap :: new ( ) ;
107109
108110 for org in & orgs {
109111 org_owners. insert ( ( * org) . to_string ( ) , github. org_owners ( org) ?) ;
112+ org_members. insert ( ( * org) . to_string ( ) , github. org_members ( org) ?) ;
110113
111114 let mut installations: Vec < OrgAppInstallation > = vec ! [ ] ;
112115
@@ -134,17 +137,21 @@ impl SyncGitHub {
134137 repos,
135138 usernames_cache,
136139 org_owners,
140+ org_members,
137141 org_apps,
138142 } )
139143 }
140144
141145 pub ( crate ) fn diff_all ( & self ) -> anyhow:: Result < Diff > {
142146 let team_diffs = self . diff_teams ( ) ?;
143147 let repo_diffs = self . diff_repos ( ) ?;
148+ let org_team_members = self . map_teams_to_org ( ) ?;
149+ let toml_github_diffs = self . diff_teams_gh_org ( org_team_members) ?;
144150
145151 Ok ( Diff {
146152 team_diffs,
147153 repo_diffs,
154+ toml_github_diffs,
148155 } )
149156 }
150157
@@ -195,6 +202,55 @@ impl SyncGitHub {
195202 Ok ( diffs)
196203 }
197204
205+ // collect all org and respective teams members in a HashMap
206+ fn map_teams_to_org ( & self ) -> anyhow:: Result < HashMap < String , HashSet < u64 > > > {
207+ let mut org_team_members: HashMap < String , HashSet < u64 > > = HashMap :: new ( ) ;
208+
209+ for team in & self . teams {
210+ let mut team_org;
211+
212+ if let Some ( gh) = & team. github {
213+ for toml_gh_team in & gh. teams {
214+ team_org = toml_gh_team. org . clone ( ) ;
215+ let toml_team_mems_gh_id: HashSet < u64 > =
216+ toml_gh_team. members . iter ( ) . copied ( ) . collect ( ) ;
217+
218+ org_team_members
219+ . entry ( team_org)
220+ . or_default ( )
221+ . extend ( toml_team_mems_gh_id) ;
222+ }
223+ }
224+ }
225+ Ok ( org_team_members)
226+ }
227+
228+ // create diff against github org members against toml team members
229+ fn diff_teams_gh_org (
230+ & self ,
231+ org_team_members : HashMap < String , HashSet < u64 > > ,
232+ ) -> anyhow:: Result < OrgMembershipDiff > {
233+ let mut org_with_members_to_be_removed: HashMap < String , HashSet < String > > = HashMap :: new ( ) ;
234+
235+ for ( gh_org, toml_members_across_teams) in org_team_members. into_iter ( ) {
236+ let gh_org_members = self . org_members . get ( & gh_org) . unwrap ( ) ;
237+
238+ let members_to_be_removed = ( & toml_members_across_teams - gh_org_members)
239+ . into_iter ( )
240+ . map ( |user| self . usernames_cache [ & user] . clone ( ) )
241+ . collect :: < HashSet < String > > ( ) ;
242+
243+ org_with_members_to_be_removed
244+ . entry ( gh_org)
245+ . or_default ( )
246+ . extend ( members_to_be_removed) ;
247+ }
248+
249+ Ok ( OrgMembershipDiff :: Delete ( DeleteOrgMembershipDiff {
250+ org_with_members : org_with_members_to_be_removed,
251+ } ) )
252+ }
253+
198254 fn diff_team ( & self , github_team : & rust_team_data:: v1:: GitHubTeam ) -> anyhow:: Result < TeamDiff > {
199255 // Ensure the team exists and is consistent
200256 let team = match self . github . team ( & github_team. org , & github_team. name ) ? {
@@ -667,6 +723,7 @@ const BOTS_TEAMS: &[&str] = &["bors", "highfive", "rfcbot", "bots"];
667723pub ( crate ) struct Diff {
668724 team_diffs : Vec < TeamDiff > ,
669725 repo_diffs : Vec < RepoDiff > ,
726+ toml_github_diffs : OrgMembershipDiff ,
670727}
671728
672729impl Diff {
@@ -679,6 +736,8 @@ impl Diff {
679736 repo_diff. apply ( sync) ?;
680737 }
681738
739+ self . toml_github_diffs . apply ( sync) ?;
740+
682741 Ok ( ( ) )
683742 }
684743}
@@ -720,6 +779,55 @@ impl std::fmt::Display for RepoDiff {
720779 }
721780}
722781
782+ #[ derive( Debug ) ]
783+
784+ enum OrgMembershipDiff {
785+ Delete ( DeleteOrgMembershipDiff ) ,
786+ }
787+
788+ impl OrgMembershipDiff {
789+ fn apply ( self , sync : & GitHubWrite ) -> anyhow:: Result < ( ) > {
790+ match self {
791+ OrgMembershipDiff :: Delete ( d) => d. apply ( sync) ?,
792+ }
793+
794+ Ok ( ( ) )
795+ }
796+ }
797+
798+ impl std:: fmt:: Display for OrgMembershipDiff {
799+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
800+ match self {
801+ OrgMembershipDiff :: Delete ( d) => write ! ( f, "{d}" ) ,
802+ }
803+ }
804+ }
805+
806+ #[ derive( Debug ) ]
807+
808+ struct DeleteOrgMembershipDiff {
809+ org_with_members : HashMap < String , HashSet < String > > ,
810+ }
811+
812+ impl DeleteOrgMembershipDiff {
813+ fn apply ( self , sync : & GitHubWrite ) -> anyhow:: Result < ( ) > {
814+ for ( gh_org, members) in self . org_with_members . iter ( ) {
815+ for member in members {
816+ sync. remove_gh_member_from_org ( gh_org, member) ?;
817+ }
818+ }
819+
820+ Ok ( ( ) )
821+ }
822+ }
823+
824+ impl std:: fmt:: Display for DeleteOrgMembershipDiff {
825+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
826+ writeln ! ( f, "❌ Deleting members '{:?}'" , self . org_with_members) ?;
827+ Ok ( ( ) )
828+ }
829+ }
830+
723831struct CreateRepoDiff {
724832 org : String ,
725833 name : String ,
0 commit comments