diff --git a/Cargo.lock b/Cargo.lock index caa7c3b..fda6b0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -464,7 +464,7 @@ dependencies = [ [[package]] name = "ghctl" -version = "0.2.0" +version = "0.2.1" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 5fb3a08..2974455 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghctl" -version = "0.2.0" +version = "0.2.1" edition = "2021" description = "A GitHub command line utility" documentation = "https://docs.rs/ghctl" diff --git a/src/ghctl/repo/config.rs b/src/ghctl/repo/config.rs index 904de20..93f4f9d 100644 --- a/src/ghctl/repo/config.rs +++ b/src/ghctl/repo/config.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use crate::github; +use crate::utils::split_some_repo_full_name; use github::AddRepositoryCollaboratorResult; /// A struct that represents the ghctl configuration for a GitHub repository @@ -27,7 +28,7 @@ pub struct RepoEnvironment { #[derive(Debug, Serialize, Deserialize)] pub struct BranchProtectionRule { pub require_pull_request: Option, - pub required_status_checks: Option>, + pub required_status_checks: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -42,9 +43,36 @@ pub struct RequirePullRequestSettings { pub required_approving_review_count: Option, } +#[derive(Debug, Serialize, Deserialize)] +pub struct RequiredStatusChecks { + pub strict: Option, + pub contexts: Option>, +} + /// The `repo config get` command -pub async fn get(_context: &crate::ghctl::Context, repo_full_name: &String) -> Result<()> { - error!("Not yet implemented: repo config get {}", repo_full_name); +pub async fn get(context: &crate::ghctl::Context, repo_full_name: &String) -> Result<()> { + let (owner, repo) = split_some_repo_full_name(repo_full_name)?; + + let octocrab = OctocrabBuilder::default() + .personal_token(context.access_token.to_owned()) + .add_header( + HeaderName::from_static("accept"), + "application/vnd.github.v3.repository+json".to_string(), + ) + .add_header( + HeaderName::from_static("x-github-api-version"), + "2022-11-28".to_string(), + ) + .build()?; + + match octocrab.repos(owner, repo).get().await { + Ok(repo) => { + println!("{}", serde_json::to_string_pretty(&repo).unwrap()); + } + Err(e) => { + error!("Error: {}", e); + } + } Ok(()) } @@ -577,7 +605,7 @@ async fn apply_branch_protection_rule( branch: &str, branch_protection_rule: &BranchProtectionRule, ) -> Result<()> { - let mut repository_branch_protection = github::RepositoryBranchProtection::new(); + let mut repository_branch_protection = github::RepositoryBranchProtectionRequest::new(); if let Some(require_pull_request) = &branch_protection_rule.require_pull_request { repository_branch_protection.required_pull_request_reviews = match require_pull_request { @@ -604,8 +632,11 @@ async fn apply_branch_protection_rule( if let Some(required_status_checks) = &branch_protection_rule.required_status_checks { repository_branch_protection.required_status_checks = Some(github::RequiredStatusChecks { - strict: false, - contexts: required_status_checks.clone(), + strict: required_status_checks.strict.unwrap_or(false), + contexts: match required_status_checks.contexts.as_ref() { + Some(contexts) => contexts.clone(), + None => Vec::new(), + }, enforcement_level: None, }); } @@ -617,8 +648,18 @@ async fn apply_branch_protection_rule( branch, &repository_branch_protection, ) - .await?; - println!("{:?}", result); + .await; + + match result { + Ok(repository_branch_protection) => debug!("{:?}", repository_branch_protection), + Err(e) => { + debug!( + "{}", + serde_json::to_string_pretty(&repository_branch_protection)? + ); + error!("{:?}", e); + } + } Ok(()) } @@ -736,6 +777,9 @@ mod tests { - gitsudo-io/a-team branch_protection_rules: main: + required_status_checks: + contexts: + - "mix/test" require_pull_request: required_approving_review_count: 1 "#, diff --git a/src/github.rs b/src/github.rs index c16d1ae..c5751c3 100644 --- a/src/github.rs +++ b/src/github.rs @@ -163,12 +163,28 @@ pub struct RepositoryBranchProtection { pub required_signatures: Option, } -impl RepositoryBranchProtection { - pub fn new() -> RepositoryBranchProtection { - RepositoryBranchProtection { +#[derive(Debug, Serialize, Deserialize)] +pub struct RepositoryBranchProtectionRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub required_status_checks: Option, + pub enforce_admins: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub required_pull_request_reviews: Option, + pub restrictions: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub required_linear_history: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub required_signatures: Option, +} + +impl RepositoryBranchProtectionRequest { + pub fn new() -> RepositoryBranchProtectionRequest { + RepositoryBranchProtectionRequest { name: None, required_status_checks: None, - enforce_admins: None, + enforce_admins: false, required_pull_request_reviews: None, restrictions: None, required_linear_history: None, @@ -181,6 +197,7 @@ impl RepositoryBranchProtection { pub struct RequiredStatusChecks { pub strict: bool, pub contexts: Vec, + #[serde(skip_serializing_if = "Option::is_none")] pub enforcement_level: Option, } @@ -243,18 +260,15 @@ pub async fn update_branch_protection( owner: &str, repo: &str, branch: &str, - repository_branch_protection: &RepositoryBranchProtection, + repository_branch_protection_request: &RepositoryBranchProtectionRequest, ) -> Result { let route = format!("/repos/{owner}/{repo}/branches/{branch}/protection"); match octocrab - .put(route, Some(repository_branch_protection)) + .put(route, Some(repository_branch_protection_request)) .await { Ok(repository_branch_protection) => Ok(repository_branch_protection), - Err(e) => { - error!("Error: {}", e); - Err(anyhow::anyhow!(e)) - } + Err(e) => Err(anyhow::anyhow!(e)), } } @@ -339,10 +353,10 @@ mod tests { enforcement_level: None, }; - let repository_branch_protection = RepositoryBranchProtection { + let repository_branch_protection_request = RepositoryBranchProtectionRequest { name: Some(branch.to_owned()), required_status_checks: Some(required_status_checks), - enforce_admins: None, + enforce_admins: false, required_pull_request_reviews: None, restrictions: None, required_linear_history: None, @@ -354,7 +368,7 @@ mod tests { &owner, &repo, &branch, - &repository_branch_protection, + &repository_branch_protection_request, ) .await;