diff --git a/src/permissions.rs b/src/permissions.rs index 0c8c7d0f3..bab38345a 100644 --- a/src/permissions.rs +++ b/src/permissions.rs @@ -81,6 +81,10 @@ macro_rules! permissions { $(concat!("crates_io_ops_bot.", stringify!($crates_io_ops_app)),)* ]; + pub(crate) const REQUIRES_DISCORD: &'static [&'static str] = &[ + $(concat!("crates_io_ops_bot.", stringify!($crates_io_ops_app)),)* + ]; + pub(crate) fn has(&self, permission: &str) -> bool { self.has_directly(permission) || self.has_indirectly(permission) } diff --git a/src/validate.rs b/src/validate.rs index dd2f2848e..9a0881c47 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -24,6 +24,7 @@ static CHECKS: &[fn(&Data, &mut Vec)] = &[ validate_team_names, validate_github_teams, validate_marker_team, + validate_discord_permissions, ]; static GITHUB_CHECKS: &[fn(&Data, &GitHubApi, &mut Vec)] = &[validate_github_usernames]; @@ -435,6 +436,46 @@ fn validate_marker_team(data: &Data, errors: &mut Vec) { }); } +/// Ensure all users with a Discord permission have a Discord ID. +fn validate_discord_permissions(data: &Data, errors: &mut Vec) { + wrapper( + Permissions::REQUIRES_DISCORD.iter(), + errors, + |permission, errors| { + wrapper(data.people(), errors, |person, _| { + if person.permissions().has(permission) && person.discord_id().is_none() { + bail!( + "person `{}` has a Discord permission (`{}`) but no Discord ID", + person.github(), + permission + ); + } + Ok(()) + }); + wrapper(data.teams(), errors, |team, errors| { + if !team.permissions().has(permission) { + return Ok(()); + } + wrapper(team.members(data)?.iter(), errors, |member, _| { + let person = data + .person(member) + .ok_or_else(|| failure::format_err!("missing person {}", member))?; + if person.discord_id().is_none() { + bail!( + "person `{}` has a Discord permission (`{}`) but no Discord ID", + person.github(), + permission + ); + } + Ok(()) + }); + Ok(()) + }); + Ok(()) + }, + ); +} + fn wrapper(iter: I, errors: &mut Vec, mut func: F) where I: Iterator,