summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.toml5
-rw-r--r--docs/toml-schema.md6
-rw-r--r--rust_team_data/src/v1.rs12
-rw-r--r--src/schema.rs26
-rw-r--r--src/static_api.rs13
-rw-r--r--src/validate.rs29
6 files changed, 91 insertions, 0 deletions
diff --git a/config.toml b/config.toml
index e62c24b..5159efb 100644
--- a/config.toml
+++ b/config.toml
@@ -3,3 +3,8 @@ allowed-mailing-lists-domains = [
"crates.io",
"docs.rs",
]
+
+allowed-github-orgs = [
+ "rust-lang",
+ "rust-lang-nursery",
+]
diff --git a/docs/toml-schema.md b/docs/toml-schema.md
index 208ceed..0147d6d 100644
--- a/docs/toml-schema.md
+++ b/docs/toml-schema.md
@@ -45,6 +45,12 @@ members = [
[permissions]
# Optional, see the permissions documentation
+# Configure the GitHub integration
+# This is optional, and if missing the team won't be synchronized with GitHub
+[github]
+name = "overlords-team" # The name of the GitHub team (optional)
+orgs = ["rust-lang"] # Organizations to create the team in (required)
+
# Define the mailing lists used by the team
# It's optional, and there can be more than one
[[lists]]
diff --git a/rust_team_data/src/v1.rs b/rust_team_data/src/v1.rs
index 839c66d..b582f4f 100644
--- a/rust_team_data/src/v1.rs
+++ b/rust_team_data/src/v1.rs
@@ -16,6 +16,7 @@ pub struct Team {
pub kind: TeamKind,
pub subteam_of: Option<String>,
pub members: Vec<TeamMember>,
+ pub github: Option<TeamGitHub>,
pub website_data: Option<TeamWebsite>,
}
@@ -28,6 +29,17 @@ pub struct TeamMember {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TeamGitHub {
+ pub teams: Vec<GitHubTeam>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GitHubTeam {
+ pub org: String,
+ pub name: String,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TeamWebsite {
pub name: String,
pub description: String,
diff --git a/src/schema.rs b/src/schema.rs
index 570b212..779e86c 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -7,12 +7,17 @@ use std::collections::HashSet;
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub(crate) struct Config {
allowed_mailing_lists_domains: HashSet<String>,
+ allowed_github_orgs: HashSet<String>,
}
impl Config {
pub(crate) fn allowed_mailing_lists_domains(&self) -> &HashSet<String> {
&self.allowed_mailing_lists_domains
}
+
+ pub(crate) fn allowed_github_orgs(&self) -> &HashSet<String> {
+ &self.allowed_github_orgs
+ }
}
// This is an enum to allow two kinds of values for the email field:
@@ -108,6 +113,7 @@ pub(crate) struct Team {
people: TeamPeople,
#[serde(default)]
permissions: Permissions,
+ github: Option<GitHubData>,
rfcbot: Option<RfcbotData>,
website: Option<WebsiteData>,
#[serde(default)]
@@ -213,6 +219,19 @@ impl Team {
pub(crate) fn permissions(&self) -> &Permissions {
&self.permissions
}
+
+ pub(crate) fn github_teams(&self) -> Vec<(&str, &str)> {
+ if let Some(github) = &self.github {
+ let name = github
+ .name
+ .as_ref()
+ .map(|n| n.as_str())
+ .unwrap_or(&self.name);
+ github.orgs.iter().map(|org| (org.as_str(), name)).collect()
+ } else {
+ Vec::new()
+ }
+ }
}
#[derive(serde_derive::Deserialize, Debug)]
@@ -228,6 +247,13 @@ struct TeamPeople {
include_all_team_members: bool,
}
+#[derive(serde::Deserialize, Debug)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct GitHubData {
+ name: Option<String>,
+ orgs: Vec<String>,
+}
+
#[derive(serde_derive::Deserialize, Debug)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
pub(crate) struct RfcbotData {
diff --git a/src/static_api.rs b/src/static_api.rs
index 15e1dcd..3760b4e 100644
--- a/src/static_api.rs
+++ b/src/static_api.rs
@@ -48,6 +48,9 @@ impl<'a> Generator<'a> {
members.sort_by_key(|member| member.github.to_lowercase());
members.sort_by_key(|member| !member.is_lead);
+ let mut github_teams = team.github_teams();
+ github_teams.sort();
+
let team_data = v1::Team {
name: team.name().into(),
kind: if team.is_wg() {
@@ -57,6 +60,16 @@ impl<'a> Generator<'a> {
},
subteam_of: team.subteam_of().map(|st| st.into()),
members,
+ github: Some(v1::TeamGitHub {
+ teams: github_teams
+ .iter()
+ .map(|(org, name)| v1::GitHubTeam {
+ org: org.to_string(),
+ name: name.to_string(),
+ })
+ .collect::<Vec<_>>(),
+ })
+ .filter(|gh| !gh.teams.is_empty()),
website_data: team.website_data().map(|ws| v1::TeamWebsite {
name: ws.name().into(),
description: ws.description().into(),
diff --git a/src/validate.rs b/src/validate.rs
index 4c4ebfb..e33f391 100644
--- a/src/validate.rs
+++ b/src/validate.rs
@@ -23,6 +23,7 @@ static CHECKS: &[fn(&Data, &mut Vec<String>)] = &[
validate_rfcbot_labels,
validate_rfcbot_exclude_members,
validate_team_names,
+ validate_github_teams,
];
static GITHUB_CHECKS: &[fn(&Data, &GitHubApi, &mut Vec<String>)] = &[validate_github_usernames];
@@ -381,6 +382,34 @@ fn validate_team_names(data: &Data, errors: &mut Vec<String>) {
});
}
+/// Ensure GitHub teams are unique and in the allowed orgs
+fn validate_github_teams(data: &Data, errors: &mut Vec<String>) {
+ let mut found = HashMap::new();
+ let allowed = data.config().allowed_github_orgs();
+ wrapper(data.teams(), errors, |team, errors| {
+ wrapper(team.github_teams().into_iter(), errors, |(org, name), _| {
+ if !allowed.contains(&*org) {
+ bail!(
+ "GitHub organization `{}` isn't allowed (in team `{}`)",
+ org,
+ team.name()
+ );
+ }
+ if let Some(other) = found.insert((org, name), team.name()) {
+ bail!(
+ "GitHub team `{}/{}` is defined for both the `{}` and `{}` teams",
+ org,
+ name,
+ team.name(),
+ other
+ );
+ }
+ Ok(())
+ });
+ Ok(())
+ });
+}
+
/// Ensure there are no misspelled GitHub account names
fn validate_github_usernames(data: &Data, github: &GitHubApi, errors: &mut Vec<String>) {
let people = data