Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read branch protection push allowances from rust_team_data #66

Merged
merged 4 commits into from
Jan 24, 2024
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions src/github/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ where

/// An object with a `login` field
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
struct Login {
login: String,
pub(crate) struct Login {
pub(crate) login: String,
}

#[derive(serde::Serialize, serde::Deserialize, Debug, Eq, PartialEq, Copy, Clone)]
Expand Down Expand Up @@ -365,8 +365,8 @@ pub(crate) struct UserPushAllowanceActor {
/// Team that can be allowed to push to a branch in a repo
#[derive(Clone, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct TeamPushAllowanceActor {
organization: Login,
name: String,
pub(crate) organization: Login,
pub(crate) name: String,
}

pub(crate) enum BranchProtectionOp {
Expand Down
50 changes: 34 additions & 16 deletions src/github/api/write.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use anyhow::Context;
use log::debug;
use reqwest::Method;
use std::rc::Rc;

use crate::github::api::read::GithubRead;
use crate::github::api::{
allow_not_found, BranchProtection, BranchProtectionOp, HttpClient, Login, PushAllowanceActor,
Repo, RepoPermission, Team, TeamPrivacy, TeamPushAllowanceActor, TeamRole,
Expand All @@ -14,19 +11,13 @@ use crate::utils::ResponseExt;
pub(crate) struct GitHubWrite {
client: HttpClient,
dry_run: bool,
read: Rc<dyn GithubRead>,
}

impl GitHubWrite {
pub(crate) fn new(
client: HttpClient,
read: Rc<dyn GithubRead>,
dry_run: bool,
) -> anyhow::Result<Self> {
pub(crate) fn new(client: HttpClient, dry_run: bool) -> anyhow::Result<Self> {
Ok(Self {
client: client.clone(),
dry_run,
read,
})
}

Expand Down Expand Up @@ -55,6 +46,38 @@ impl GitHubWrite {
Ok(data.user.id)
}

fn team_id(&self, org: &str, name: &str) -> anyhow::Result<String> {
#[derive(serde::Serialize)]
struct Params<'a> {
org: &'a str,
team: &'a str,
}
let query = "
query($org: String!, $team: String!) {
organization(login: $org) {
team(slug: $team) {
id
}
}
}
";
#[derive(serde::Deserialize)]
struct Data {
organization: Organization,
}
#[derive(serde::Deserialize)]
struct Organization {
team: Team,
}
#[derive(serde::Deserialize)]
struct Team {
id: String,
}

let data: Data = self.client.graphql(query, Params { org, team: name })?;
Ok(data.organization.team.id)
}

/// Create a team in a org
pub(crate) fn create_team(
&self,
Expand Down Expand Up @@ -377,12 +400,7 @@ impl GitHubWrite {
PushAllowanceActor::Team(TeamPushAllowanceActor {
organization: Login { login: org },
name,
}) => push_actor_ids.push(
self.read
.team(org, name)?
.with_context(|| format!("could not find team: {org}/{name}"))?
.name,
),
}) => push_actor_ids.push(self.team_id(org, name)?),
}
}

Expand Down
37 changes: 23 additions & 14 deletions src/github/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ mod api;
mod tests;

use self::api::{BranchProtectionOp, TeamPrivacy, TeamRole};
use crate::github::api::{GithubRead, RepoPermission};
use crate::github::api::{GithubRead, Login, PushAllowanceActor, RepoPermission};
use log::debug;
use rust_team_data::v1::Bot;
use std::collections::{HashMap, HashSet};
use std::fmt::Write;
use std::rc::Rc;

pub(crate) use self::api::{GitHubApiRead, GitHubWrite, HttpClient};

static DEFAULT_DESCRIPTION: &str = "Managed by the rust-lang/team repository.";
static DEFAULT_PRIVACY: TeamPrivacy = TeamPrivacy::Closed;

pub(crate) fn create_diff(
github: Rc<dyn GithubRead>,
github: Box<dyn GithubRead>,
teams: Vec<rust_team_data::v1::Team>,
repos: Vec<rust_team_data::v1::Repo>,
) -> anyhow::Result<Diff> {
Expand All @@ -25,7 +24,7 @@ pub(crate) fn create_diff(
}

struct SyncGitHub {
github: Rc<dyn GithubRead>,
github: Box<dyn GithubRead>,
teams: Vec<rust_team_data::v1::Team>,
repos: Vec<rust_team_data::v1::Repo>,
usernames_cache: HashMap<usize, String>,
Expand All @@ -34,7 +33,7 @@ struct SyncGitHub {

impl SyncGitHub {
pub(crate) fn new(
github: Rc<dyn GithubRead>,
github: Box<dyn GithubRead>,
teams: Vec<rust_team_data::v1::Team>,
repos: Vec<rust_team_data::v1::Repo>,
) -> anyhow::Result<Self> {
Expand Down Expand Up @@ -454,23 +453,33 @@ fn construct_branch_protection(
expected_repo: &rust_team_data::v1::Repo,
branch_protection: &rust_team_data::v1::BranchProtection,
) -> api::BranchProtection {
let required_approving_review_count: u8 = if expected_repo.bots.contains(&Bot::Bors) {
let uses_bors = expected_repo.bots.contains(&Bot::Bors);
let required_approving_review_count: u8 = if uses_bors {
0
} else {
branch_protection
.required_approvals
.try_into()
.expect("Too large required approval count")
};
let push_allowances = expected_repo
.bots
.contains(&Bot::Bors)
.then(|| {
vec![api::PushAllowanceActor::User(api::UserPushAllowanceActor {
login: "bors".to_owned(),
})]
let mut push_allowances: Vec<PushAllowanceActor> = branch_protection
.allowed_merge_teams
.iter()
.map(|team| {
api::PushAllowanceActor::Team(api::TeamPushAllowanceActor {
organization: Login {
login: expected_repo.org.clone(),
},
name: team.to_string(),
})
})
.unwrap_or_default();
.collect();

if uses_bors {
push_allowances.push(PushAllowanceActor::User(api::UserPushAllowanceActor {
login: "bors".to_owned(),
}));
}
api::BranchProtection {
pattern: branch_protection.pattern.clone(),
is_admin_enforced: true,
Expand Down
4 changes: 2 additions & 2 deletions src/github/tests/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use derive_builder::Builder;
use rust_team_data::v1::{GitHubTeam, Person, TeamGitHub, TeamKind};
Expand Down Expand Up @@ -66,7 +65,7 @@ impl DataModel {
let teams = self.teams.iter().map(|r| r.to_data()).collect();
let repos = vec![];

let read = Rc::new(github);
let read = Box::new(github);
let sync = SyncGitHub::new(read, teams, repos).expect("Cannot create SyncGitHub");
sync.diff_teams().expect("Cannot diff teams")
}
Expand Down Expand Up @@ -101,6 +100,7 @@ impl TeamData {
alumni: vec![],
github: (!gh_teams.is_empty()).then(|| TeamGitHub { teams: gh_teams }),
website_data: None,
roles: vec![],
discord: vec![],
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::team_api::TeamApi;
use crate::zulip::SyncZulip;
use anyhow::Context;
use log::{error, info, warn};
use std::rc::Rc;

const AVAILABLE_SERVICES: &[&str] = &["github", "mailgun", "zulip"];
const USER_AGENT: &str = "rust-lang teams sync (https://github.com/rust-lang/sync-team)";
Expand Down Expand Up @@ -85,13 +84,13 @@ fn app() -> anyhow::Result<()> {
let token = get_env("GITHUB_TOKEN")?;
let client =
HttpClient::from_url_and_token("https://api.github.com/".to_string(), token)?;
let gh_read = Rc::new(GitHubApiRead::from_client(client.clone())?);
let gh_read = Box::new(GitHubApiRead::from_client(client.clone())?);
let teams = team_api.get_teams()?;
let repos = team_api.get_repos()?;
let diff = create_diff(gh_read.clone(), teams, repos)?;
let diff = create_diff(gh_read, teams, repos)?;
info!("{}", diff);
if !only_print_plan {
let gh_write = GitHubWrite::new(client, gh_read, dry_run)?;
let gh_write = GitHubWrite::new(client, dry_run)?;
diff.apply(&gh_write)?;
}
}
Expand Down
Loading