1
- use std:: collections:: { HashMap , HashSet } ;
1
+ use std:: collections:: { BTreeSet , HashMap , HashSet } ;
2
2
3
3
use derive_builder:: Builder ;
4
4
use rust_team_data:: v1;
@@ -13,7 +13,7 @@ use crate::github::{
13
13
RepoDiff , SyncGitHub , TeamDiff , api, construct_branch_protection, convert_permission,
14
14
} ;
15
15
16
- const DEFAULT_ORG : & str = "rust-lang" ;
16
+ pub const DEFAULT_ORG : & str = "rust-lang" ;
17
17
18
18
type UserId = u64 ;
19
19
@@ -74,11 +74,12 @@ impl DataModel {
74
74
. map ( |user| ( user. github_id , user. name . clone ( ) ) )
75
75
. collect ( ) ;
76
76
77
- let mut team_memberships : HashMap < String , HashMap < UserId , TeamMember > > = HashMap :: default ( ) ;
78
- let mut teams = vec ! [ ] ;
77
+ let mut orgs : HashMap < String , GithubOrg > = HashMap :: default ( ) ;
78
+
79
79
for team in & self . teams {
80
80
for gh_team in & team. gh_teams {
81
- let res = team_memberships. insert (
81
+ let org = orgs. entry ( gh_team. org . clone ( ) ) . or_default ( ) ;
82
+ let res = org. team_memberships . insert (
82
83
gh_team. name . clone ( ) ,
83
84
gh_team
84
85
. members
@@ -96,27 +97,26 @@ impl DataModel {
96
97
) ;
97
98
assert ! ( res. is_none( ) ) ;
98
99
99
- teams. push ( api:: Team {
100
- id : Some ( teams. len ( ) as u64 ) ,
100
+ org . teams . push ( api:: Team {
101
+ id : Some ( org . teams . len ( ) as u64 ) ,
101
102
name : gh_team. name . clone ( ) ,
102
103
description : Some ( "Managed by the rust-lang/team repository." . to_string ( ) ) ,
103
104
privacy : TeamPrivacy :: Closed ,
104
105
slug : gh_team. name . clone ( ) ,
105
- } )
106
+ } ) ;
107
+
108
+ org. members . extend ( gh_team. members . iter ( ) . copied ( ) ) ;
106
109
}
107
110
}
108
111
109
- let mut repos = HashMap :: default ( ) ;
110
- let mut repo_members: HashMap < String , RepoMembers > = HashMap :: default ( ) ;
111
- let mut branch_protections = HashMap :: new ( ) ;
112
-
113
112
for repo in & self . repos {
114
- repos. insert (
113
+ let org = orgs. entry ( repo. org . clone ( ) ) . or_default ( ) ;
114
+ org. repos . insert (
115
115
repo. name . clone ( ) ,
116
116
Repo {
117
- node_id : repos. len ( ) . to_string ( ) ,
117
+ node_id : org . repos . len ( ) . to_string ( ) ,
118
118
name : repo. name . clone ( ) ,
119
- org : DEFAULT_ORG . to_string ( ) ,
119
+ org : repo . org . clone ( ) ,
120
120
description : repo. description . clone ( ) ,
121
121
homepage : repo. homepage . clone ( ) ,
122
122
archived : false ,
@@ -146,7 +146,8 @@ impl DataModel {
146
146
permission : convert_permission ( & m. permission ) ,
147
147
} )
148
148
. collect ( ) ;
149
- repo_members. insert ( repo. name . clone ( ) , RepoMembers { teams, members } ) ;
149
+ org. repo_members
150
+ . insert ( repo. name . clone ( ) , RepoMembers { teams, members } ) ;
150
151
151
152
let repo_v1: v1:: Repo = repo. clone ( ) . into ( ) ;
152
153
let mut protections = vec ! [ ] ;
@@ -156,19 +157,15 @@ impl DataModel {
156
157
construct_branch_protection ( & repo_v1, protection) ,
157
158
) ) ;
158
159
}
159
- branch_protections. insert ( repo. name . clone ( ) , protections) ;
160
+ org. branch_protections
161
+ . insert ( repo. name . clone ( ) , protections) ;
160
162
}
161
163
162
- GithubMock {
163
- users,
164
- owners : Default :: default ( ) ,
165
- teams,
166
- team_memberships,
167
- team_invitations : Default :: default ( ) ,
168
- repos,
169
- repo_members,
170
- branch_protections,
164
+ if orgs. is_empty ( ) {
165
+ orgs. insert ( DEFAULT_ORG . to_string ( ) , GithubOrg :: default ( ) ) ;
171
166
}
167
+
168
+ GithubMock { users, orgs }
172
169
}
173
170
174
171
pub fn diff_teams ( & self , github : GithubMock ) -> Vec < TeamDiff > {
@@ -249,10 +246,10 @@ impl From<TeamData> for v1::Team {
249
246
}
250
247
251
248
impl TeamDataBuilder {
252
- pub fn gh_team ( mut self , name : & str , members : & [ UserId ] ) -> Self {
249
+ pub fn gh_team ( mut self , org : & str , name : & str , members : & [ UserId ] ) -> Self {
253
250
let mut gh_teams = self . gh_teams . unwrap_or_default ( ) ;
254
251
gh_teams. push ( GitHubTeam {
255
- org : DEFAULT_ORG . to_string ( ) ,
252
+ org : org . to_string ( ) ,
256
253
name : name. to_string ( ) ,
257
254
members : members. to_vec ( ) ,
258
255
} ) ;
@@ -265,6 +262,8 @@ impl TeamDataBuilder {
265
262
#[ builder( pattern = "owned" ) ]
266
263
pub struct RepoData {
267
264
name : String ,
265
+ #[ builder( default = DEFAULT_ORG . to_string( ) ) ]
266
+ org : String ,
268
267
#[ builder( default ) ]
269
268
pub description : String ,
270
269
#[ builder( default ) ]
@@ -307,6 +306,7 @@ impl From<RepoData> for v1::Repo {
307
306
fn from ( value : RepoData ) -> Self {
308
307
let RepoData {
309
308
name,
309
+ org,
310
310
description,
311
311
homepage,
312
312
bots,
@@ -317,7 +317,7 @@ impl From<RepoData> for v1::Repo {
317
317
branch_protections,
318
318
} = value;
319
319
Self {
320
- org : DEFAULT_ORG . to_string ( ) ,
320
+ org,
321
321
name : name. clone ( ) ,
322
322
description,
323
323
homepage,
@@ -411,28 +411,30 @@ impl BranchProtectionBuilder {
411
411
pub struct GithubMock {
412
412
// user ID -> login
413
413
users : HashMap < UserId , String > ,
414
- // org name -> user ID
415
- owners : HashMap < String , Vec < UserId > > ,
416
- teams : Vec < Team > ,
417
- // Team name -> members
418
- team_memberships : HashMap < String , HashMap < UserId , TeamMember > > ,
419
- // Team name -> list of invited users
420
- team_invitations : HashMap < String , Vec < String > > ,
421
- // Repo name -> repo data
422
- repos : HashMap < String , Repo > ,
423
- // Repo name -> (teams, members)
424
- repo_members : HashMap < String , RepoMembers > ,
425
- // Repo name -> Vec<(protection ID, branch protection)>
426
- branch_protections : HashMap < String , Vec < ( String , BranchProtection ) > > ,
414
+ // org name -> organization data
415
+ orgs : HashMap < String , GithubOrg > ,
427
416
}
428
417
429
418
impl GithubMock {
430
- pub fn add_invitation ( & mut self , repo : & str , user : & str ) {
431
- self . team_invitations
419
+ pub fn add_invitation ( & mut self , org : & str , repo : & str , user : & str ) {
420
+ self . get_org_mut ( org)
421
+ . team_invitations
432
422
. entry ( repo. to_string ( ) )
433
423
. or_default ( )
434
424
. push ( user. to_string ( ) ) ;
435
425
}
426
+
427
+ fn get_org ( & self , org : & str ) -> & GithubOrg {
428
+ self . orgs
429
+ . get ( org)
430
+ . unwrap_or_else ( || panic ! ( "Org {org} not found" ) )
431
+ }
432
+
433
+ fn get_org_mut ( & mut self , org : & str ) -> & mut GithubOrg {
434
+ self . orgs
435
+ . get_mut ( org)
436
+ . unwrap_or_else ( || panic ! ( "Org {org} not found" ) )
437
+ }
436
438
}
437
439
438
440
impl GithubRead for GithubMock {
@@ -446,48 +448,47 @@ impl GithubRead for GithubMock {
446
448
}
447
449
448
450
fn org_owners ( & self , org : & str ) -> anyhow:: Result < HashSet < UserId > > {
449
- Ok ( self
450
- . owners
451
- . get ( org)
452
- . cloned ( )
453
- . unwrap_or_default ( )
454
- . into_iter ( )
455
- . collect ( ) )
451
+ Ok ( self . get_org ( org) . owners . iter ( ) . copied ( ) . collect ( ) )
456
452
}
457
453
458
454
fn org_teams ( & self , org : & str ) -> anyhow:: Result < Vec < ( String , String ) > > {
459
- assert_eq ! ( org, DEFAULT_ORG ) ;
460
455
Ok ( self
456
+ . get_org ( org)
461
457
. teams
462
458
. iter ( )
463
459
. map ( |team| ( team. name . clone ( ) , team. slug . clone ( ) ) )
464
460
. collect ( ) )
465
461
}
466
462
467
- fn team ( & self , _org : & str , team : & str ) -> anyhow:: Result < Option < Team > > {
468
- Ok ( self . teams . iter ( ) . find ( |t| t. name == team) . cloned ( ) )
463
+ fn team ( & self , org : & str , team : & str ) -> anyhow:: Result < Option < Team > > {
464
+ Ok ( self
465
+ . get_org ( org)
466
+ . teams
467
+ . iter ( )
468
+ . find ( |t| t. name == team)
469
+ . cloned ( ) )
469
470
}
470
471
471
472
fn team_memberships (
472
473
& self ,
473
474
team : & Team ,
474
- _org : & str ,
475
+ org : & str ,
475
476
) -> anyhow:: Result < HashMap < UserId , TeamMember > > {
476
- let memberships = self
477
+ Ok ( self
478
+ . get_org ( org)
477
479
. team_memberships
478
480
. get ( & team. name )
479
481
. cloned ( )
480
- . unwrap_or_default ( ) ;
481
- Ok ( memberships)
482
+ . unwrap_or_default ( ) )
482
483
}
483
484
484
485
fn team_membership_invitations (
485
486
& self ,
486
487
org : & str ,
487
488
team : & str ,
488
489
) -> anyhow:: Result < HashSet < String > > {
489
- assert_eq ! ( org, DEFAULT_ORG ) ;
490
490
Ok ( self
491
+ . get_org ( org)
491
492
. team_invitations
492
493
. get ( team)
493
494
. cloned ( )
@@ -497,13 +498,15 @@ impl GithubRead for GithubMock {
497
498
}
498
499
499
500
fn repo ( & self , org : & str , repo : & str ) -> anyhow:: Result < Option < Repo > > {
500
- assert_eq ! ( org, DEFAULT_ORG ) ;
501
- Ok ( self . repos . get ( repo) . cloned ( ) )
501
+ Ok ( self
502
+ . orgs
503
+ . get ( org)
504
+ . and_then ( |org| org. repos . get ( repo) . cloned ( ) ) )
502
505
}
503
506
504
507
fn repo_teams ( & self , org : & str , repo : & str ) -> anyhow:: Result < Vec < RepoTeam > > {
505
- assert_eq ! ( org, DEFAULT_ORG ) ;
506
508
Ok ( self
509
+ . get_org ( org)
507
510
. repo_members
508
511
. get ( repo)
509
512
. cloned ( )
@@ -512,9 +515,8 @@ impl GithubRead for GithubMock {
512
515
}
513
516
514
517
fn repo_collaborators ( & self , org : & str , repo : & str ) -> anyhow:: Result < Vec < RepoUser > > {
515
- // The mock currently only supports mocking one GitHub organization.
516
- assert_eq ! ( org, DEFAULT_ORG ) ;
517
518
Ok ( self
519
+ . get_org ( org)
518
520
. repo_members
519
521
. get ( repo)
520
522
. cloned ( )
@@ -527,9 +529,7 @@ impl GithubRead for GithubMock {
527
529
org : & str ,
528
530
repo : & str ,
529
531
) -> anyhow:: Result < HashMap < String , ( String , BranchProtection ) > > {
530
- assert_eq ! ( org, DEFAULT_ORG ) ;
531
-
532
- let Some ( protections) = self . branch_protections . get ( repo) else {
532
+ let Some ( protections) = self . get_org ( org) . branch_protections . get ( repo) else {
533
533
return Ok ( Default :: default ( ) ) ;
534
534
} ;
535
535
let mut result = HashMap :: default ( ) ;
@@ -541,6 +541,23 @@ impl GithubRead for GithubMock {
541
541
}
542
542
}
543
543
544
+ #[ derive( Default ) ]
545
+ struct GithubOrg {
546
+ members : BTreeSet < UserId > ,
547
+ owners : BTreeSet < UserId > ,
548
+ teams : Vec < Team > ,
549
+ // Team name -> list of invited users
550
+ team_invitations : HashMap < String , Vec < String > > ,
551
+ // Team name -> members
552
+ team_memberships : HashMap < String , HashMap < UserId , TeamMember > > ,
553
+ // Repo name -> repo data
554
+ repos : HashMap < String , Repo > ,
555
+ // Repo name -> (teams, members)
556
+ repo_members : HashMap < String , RepoMembers > ,
557
+ // Repo name -> Vec<(protection ID, branch protection)>
558
+ branch_protections : HashMap < String , Vec < ( String , BranchProtection ) > > ,
559
+ }
560
+
544
561
#[ derive( Clone ) ]
545
562
pub struct RepoMembers {
546
563
teams : Vec < RepoTeam > ,
0 commit comments