Skip to content

Commit

Permalink
Merge pull request #801 from rylev/repos
Browse files Browse the repository at this point in the history
Add ability to encode and fetch repo information
  • Loading branch information
rylev authored Aug 15, 2022
2 parents 3cea26a + f1dc320 commit 44bf784
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
**/*.rs.bk
/tests/static-api/_output
/build
8 changes: 8 additions & 0 deletions repos/team.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
org = "rust-lang"
name = "team"
description = "Rust teams structure"
bots = ["bors", "highfive", "rustbot", "rust-timer"]

[access.teams]
core = "admin"
mods = "maintain"
38 changes: 38 additions & 0 deletions rust_team_data/src/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ pub struct Teams {
pub teams: IndexMap<String, Team>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Repos {
#[serde(flatten)]
pub repos: IndexMap<String, Vec<Repo>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct List {
pub address: String,
Expand Down Expand Up @@ -130,3 +136,35 @@ pub struct ZulipMapping {
/// Zulip ID to GitHub ID
pub users: IndexMap<usize, usize>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Repo {
pub org: String,
pub name: String,
pub description: String,
pub bots: Vec<Bot>,
pub teams: Vec<RepoTeam>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum Bot {
Bors,
Highfive,
Rustbot,
RustTimer,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RepoTeam {
pub name: String,
pub permission: RepoPermission,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RepoPermission {
Write,
Admin,
Maintain,
}
19 changes: 17 additions & 2 deletions src/data.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::schema::{Config, List, Person, Team, ZulipGroup};
use crate::schema::{Config, List, Person, Repo, Team, ZulipGroup};
use failure::{Error, ResultExt};
use serde::Deserialize;
use std::collections::{HashMap, HashSet};
Expand All @@ -9,6 +9,7 @@ use std::path::Path;
pub(crate) struct Data {
people: HashMap<String, Person>,
teams: HashMap<String, Team>,
repos: HashMap<(String, String), Repo>,
config: Config,
}

Expand All @@ -17,9 +18,17 @@ impl Data {
let mut data = Data {
people: HashMap::new(),
teams: HashMap::new(),
repos: HashMap::new(),
config: load_file(Path::new("config.toml"))?,
};

data.load_dir("repos", |this, repo: Repo| {
repo.validate()?;
this.repos
.insert((repo.org.clone(), repo.name.clone()), repo);
Ok(())
})?;

data.load_dir("people", |this, person: Person| {
person.validate()?;
this.people.insert(person.github().to_string(), person);
Expand All @@ -39,7 +48,9 @@ impl Data {
T: for<'de> Deserialize<'de>,
F: Fn(&mut Self, T) -> Result<(), Error>,
{
for entry in std::fs::read_dir(dir)? {
for entry in std::fs::read_dir(dir)
.with_context(|e| format!("`load_dir` failed to read directory '{}': {}", dir, e))?
{
let path = entry?.path();

if path.is_file() && path.extension() == Some(OsStr::new("toml")) {
Expand Down Expand Up @@ -107,6 +118,10 @@ impl Data {
}
Ok(result)
}

pub(crate) fn repos(&self) -> impl Iterator<Item = &Repo> {
self.repos.iter().map(|(_, repo)| repo)
}
}

fn load_file<T: for<'de> Deserialize<'de>>(path: &Path) -> Result<T, Error> {
Expand Down
47 changes: 46 additions & 1 deletion src/schema.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::data::Data;
pub(crate) use crate::permissions::Permissions;
use failure::{bail, err_msg, Error};
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};

#[derive(serde_derive::Deserialize, Debug)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
Expand Down Expand Up @@ -633,3 +633,48 @@ fn default_true() -> bool {
fn default_false() -> bool {
false
}

#[derive(serde_derive::Deserialize, Debug)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub(crate) struct Repo {
pub org: String,
pub name: String,
pub description: String,
pub bots: Vec<Bot>,
pub access: RepoAccess,
}

impl Repo {
const VALID_ORGS: &'static [&'static str] = &["rust-lang"];

pub(crate) fn validate(&self) -> Result<(), Error> {
if !Self::VALID_ORGS.contains(&self.org.as_str()) {
bail!("{} is not a valid repo org", self.org);
}

Ok(())
}
}

#[derive(serde_derive::Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
pub(crate) enum Bot {
Bors,
Highfive,
Rustbot,
RustTimer,
}

#[derive(serde_derive::Deserialize, Debug)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub(crate) struct RepoAccess {
pub teams: HashMap<String, RepoPermission>,
}

#[derive(serde_derive::Deserialize, Debug)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub(crate) enum RepoPermission {
Write,
Maintain,
Admin,
}
46 changes: 45 additions & 1 deletion src/static_api.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::data::Data;
use crate::schema::{Permissions, TeamKind, ZulipGroupMember};
use crate::schema::{Bot, Permissions, RepoPermission, TeamKind, ZulipGroupMember};
use failure::Error;
use indexmap::IndexMap;
use log::info;
Expand All @@ -23,6 +23,7 @@ impl<'a> Generator<'a> {

pub(crate) fn generate(&self) -> Result<(), Error> {
self.generate_teams()?;
self.generate_repos()?;
self.generate_lists()?;
self.generate_zulip_groups()?;
self.generate_permissions()?;
Expand All @@ -31,6 +32,49 @@ impl<'a> Generator<'a> {
Ok(())
}

fn generate_repos(&self) -> Result<(), Error> {
let mut repos: IndexMap<String, Vec<v1::Repo>> = IndexMap::new();
for r in self.data.repos() {
let repo = v1::Repo {
org: r.org.clone(),
name: r.name.clone(),
description: r.description.clone(),
bots: r
.bots
.iter()
.map(|b| match b {
Bot::Bors => v1::Bot::Bors,
Bot::Highfive => v1::Bot::Highfive,
Bot::RustTimer => v1::Bot::RustTimer,
Bot::Rustbot => v1::Bot::Rustbot,
})
.collect(),
teams: r
.access
.teams
.iter()
.map(|(name, permission)| {
let permission = match permission {
RepoPermission::Admin => v1::RepoPermission::Admin,
RepoPermission::Write => v1::RepoPermission::Write,
RepoPermission::Maintain => v1::RepoPermission::Maintain,
};
v1::RepoTeam {
name: name.clone(),
permission,
}
})
.collect(),
};

self.add(&format!("v1/repos/{}.json", r.name), &repo)?;
repos.entry(r.org.clone()).or_default().push(repo);
}

self.add("v1/repos.json", &v1::Repos { repos })?;
Ok(())
}

fn generate_teams(&self) -> Result<(), Error> {
let mut teams = IndexMap::new();

Expand Down
18 changes: 18 additions & 0 deletions src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ static CHECKS: &[Check<fn(&Data, &mut Vec<String>)>] = checks![
validate_discord_team_members_have_discord_ids,
validate_zulip_group_ids,
validate_zulip_group_extra_people,
validate_repos,
];

#[allow(clippy::type_complexity)]
Expand Down Expand Up @@ -653,6 +654,23 @@ fn validate_zulip_group_extra_people(data: &Data, errors: &mut Vec<String>) {
});
}

/// Ensure repos reference valid teams
fn validate_repos(data: &Data, errors: &mut Vec<String>) {
wrapper(data.repos(), errors, |repo, _| {
for (team_name, _) in &repo.access.teams {
if data.team(team_name).is_none() {
bail!(
"access for {}/{} is invalid: '{}' is not the name of a team",
repo.org,
repo.name,
team_name
);
}
}
Ok(())
});
}

fn wrapper<T, I, F>(iter: I, errors: &mut Vec<String>, mut func: F)
where
I: Iterator<Item = T>,
Expand Down
16 changes: 16 additions & 0 deletions tests/static-api/_expected/v1/repos.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"rust-lang": [
{
"org": "rust-lang",
"name": "some_repo",
"description": "A repo!",
"bots": [],
"teams": [
{
"name": "foo",
"permission": "admin"
}
]
}
]
}
12 changes: 12 additions & 0 deletions tests/static-api/_expected/v1/repos/some_repo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"org": "rust-lang",
"name": "some_repo",
"description": "A repo!",
"bots": [],
"teams": [
{
"name": "foo",
"permission": "admin"
}
]
}
7 changes: 7 additions & 0 deletions tests/static-api/repos/some_repo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
org = "rust-lang"
name = "some_repo"
description = "A repo!"
bots = []

[access.teams]
foo = "admin"

0 comments on commit 44bf784

Please sign in to comment.