Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,10 @@ impl Team {
self.people.alumni.as_ref().map_or(&[], Vec::as_slice)
}

pub(crate) fn explicit_leads(&self) -> &[String] {
&self.people.leads
}

pub(crate) fn contains_person(&self, data: &Data, person: &Person) -> Result<bool, Error> {
let members = self.members(data)?;
Ok(members.contains(person.github()))
Expand Down
62 changes: 62 additions & 0 deletions src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static CHECKS: &[Check<fn(&Data, &mut Vec<String>)>] = checks![
validate_subteam_of,
validate_team_leads,
validate_team_members,
validate_duplicate_team_entries,
validate_alumni,
validate_archived_teams,
validate_inactive_members,
Expand Down Expand Up @@ -236,6 +237,67 @@ fn validate_team_members(data: &Data, errors: &mut Vec<String>) {
});
}

/// Helper for checking duplicates in a list
fn check_duplicates<'a, I>(team_name: &str, label: &str, items: I) -> Result<(), Error>
where
I: IntoIterator<Item = &'a str>,
{
let mut seen = HashSet::new();
let mut duplicates = HashSet::new();

for item in items {
if !seen.insert(item) {
duplicates.insert(item);
}
}

if !duplicates.is_empty() {
let dup_list: Vec<&str> = duplicates.into_iter().collect();
bail!(
"team `{}` has duplicate {}: {}",
team_name,
label,
dup_list.join(", ")
);
}

Ok(())
}

/// Ensure no duplicate entries in team leads, members and alumni
fn validate_duplicate_team_entries(data: &Data, errors: &mut Vec<String>) {
wrapper(data.teams(), errors, |team, errors| {
// Check leads for duplicates
if let Err(e) = check_duplicates(
team.name(),
"leads",
team.explicit_leads().iter().map(|s| s.as_str()),
) {
errors.push(e.to_string());
}

// Check members for duplicates
if let Err(e) = check_duplicates(
team.name(),
"members",
team.explicit_members().iter().map(|m| m.github.as_str()),
) {
errors.push(e.to_string());
}

// Check alumni for duplicates
if let Err(e) = check_duplicates(
team.name(),
"alumni",
team.explicit_alumni().iter().map(|a| a.github.as_str()),
) {
errors.push(e.to_string());
}

Ok(())
});
}

/// Alumni team must consist only of automatically populated alumni from the other teams
fn validate_alumni(data: &Data, errors: &mut Vec<String>) {
let Some(alumni_team) = data.team("alumni") else {
Expand Down