@@ -28,6 +28,7 @@ static CHECKS: &[Check<fn(&Data, &mut Vec<String>)>] = checks![
2828 validate_subteam_of,
2929 validate_team_leads,
3030 validate_team_members,
31+ validate_duplicate_team_entries,
3132 validate_alumni,
3233 validate_archived_teams,
3334 validate_inactive_members,
@@ -236,6 +237,37 @@ fn validate_team_members(data: &Data, errors: &mut Vec<String>) {
236237 } ) ;
237238}
238239
240+ /// Ensure no duplicate entries in team members or alumni
241+ fn validate_duplicate_team_entries ( data : & Data , errors : & mut Vec < String > ) {
242+ wrapper ( data. teams ( ) , errors, |team, errors| {
243+ // Check for duplicate members
244+ let mut seen_members = HashSet :: new ( ) ;
245+ for member in team. explicit_members ( ) {
246+ if !seen_members. insert ( & member. github ) {
247+ errors. push ( format ! (
248+ "team `{}` has duplicate members: {}" ,
249+ team. name( ) ,
250+ member. github
251+ ) ) ;
252+ }
253+ }
254+
255+ // Check for duplicate alumni
256+ let mut seen_alumni = HashSet :: new ( ) ;
257+ for alum in team. explicit_alumni ( ) {
258+ if !seen_alumni. insert ( & alum. github ) {
259+ errors. push ( format ! (
260+ "team `{}` has duplicate alumni: {}" ,
261+ team. name( ) ,
262+ alum. github
263+ ) ) ;
264+ }
265+ }
266+
267+ Ok ( ( ) )
268+ } ) ;
269+ }
270+
239271/// Alumni team must consist only of automatically populated alumni from the other teams
240272fn validate_alumni ( data : & Data , errors : & mut Vec < String > ) {
241273 let Some ( alumni_team) = data. team ( "alumni" ) else {
0 commit comments