|
1 | | -use crate::github::api::Ruleset; |
| 1 | +use crate::github::api::{BranchPolicy, Ruleset}; |
2 | 2 | use crate::github::api::{ |
3 | 3 | BranchProtection, GraphNode, GraphNodes, GraphPageInfo, HttpClient, Login, Repo, RepoTeam, |
4 | | - RepoUser, Team, TeamMember, TeamRole, team_node_id, url::GitHubUrl, user_node_id, |
| 4 | + RepoUser, RestPaginatedError, Team, TeamMember, TeamRole, team_node_id, url::GitHubUrl, |
| 5 | + user_node_id, |
5 | 6 | }; |
6 | 7 | use anyhow::Context as _; |
7 | | -use reqwest::Method; |
| 8 | +use reqwest::{Method, StatusCode}; |
8 | 9 | use rust_team_data::v1::Environment; |
9 | 10 | use std::collections::{HashMap, HashSet}; |
10 | 11 |
|
@@ -68,6 +69,13 @@ pub(crate) trait GithubRead { |
68 | 69 | org: &str, |
69 | 70 | repo: &str, |
70 | 71 | ) -> anyhow::Result<Vec<crate::github::api::Ruleset>>; |
| 72 | + |
| 73 | + fn environment_branch_policies( |
| 74 | + &self, |
| 75 | + org: &str, |
| 76 | + repo: &str, |
| 77 | + environment: &str, |
| 78 | + ) -> anyhow::Result<Vec<BranchPolicy>>; |
71 | 79 | } |
72 | 80 |
|
73 | 81 | pub(crate) struct GitHubApiRead { |
@@ -479,22 +487,6 @@ impl GithubRead for GitHubApiRead { |
479 | 487 | environments: Vec<GitHubEnvironment>, |
480 | 488 | } |
481 | 489 |
|
482 | | - #[derive(serde::Deserialize)] |
483 | | - struct BranchPolicy { |
484 | | - name: String, |
485 | | - #[serde(rename = "type", default = "default_branch_type")] |
486 | | - pattern_type: String, |
487 | | - } |
488 | | - |
489 | | - fn default_branch_type() -> String { |
490 | | - "branch".to_string() |
491 | | - } |
492 | | - |
493 | | - #[derive(serde::Deserialize)] |
494 | | - struct BranchPoliciesResponse { |
495 | | - branch_policies: Vec<BranchPolicy>, |
496 | | - } |
497 | | - |
498 | 490 | let mut env_infos = Vec::new(); |
499 | 491 |
|
500 | 492 | // Fetch all environments with their protection_rules metadata |
@@ -522,23 +514,21 @@ impl GithubRead for GitHubApiRead { |
522 | 514 | let (branches, tags) = if has_branch_policies { |
523 | 515 | let mut branches = Vec::new(); |
524 | 516 | let mut tags = Vec::new(); |
525 | | - self.client.rest_paginated( |
526 | | - &Method::GET, |
527 | | - &GitHubUrl::repos( |
528 | | - org, |
529 | | - repo, |
530 | | - &format!("environments/{}/deployment-branch-policies", env_info.name), |
531 | | - )?, |
532 | | - |resp: BranchPoliciesResponse| { |
533 | | - for p in resp.branch_policies { |
534 | | - match p.pattern_type.as_str() { |
535 | | - "tag" => tags.push(p.name), |
536 | | - _ => branches.push(p.name), |
537 | | - } |
538 | | - } |
539 | | - Ok(()) |
540 | | - }, |
541 | | - )?; |
| 517 | + let policies = |
| 518 | + self.environment_branch_policies(org, repo, &env_info.name).with_context( |
| 519 | + || { |
| 520 | + format!( |
| 521 | + "failed to load deployment branch policies for environment '{}' in '{org}/{repo}'", |
| 522 | + env_info.name |
| 523 | + ) |
| 524 | + }, |
| 525 | + )?; |
| 526 | + for p in policies { |
| 527 | + match p.pattern_type.as_str() { |
| 528 | + "tag" => tags.push(p.name), |
| 529 | + _ => branches.push(p.name), |
| 530 | + } |
| 531 | + } |
542 | 532 | (branches, tags) |
543 | 533 | } else { |
544 | 534 | (Vec::new(), Vec::new()) |
@@ -570,4 +560,47 @@ impl GithubRead for GitHubApiRead { |
570 | 560 |
|
571 | 561 | Ok(rulesets) |
572 | 562 | } |
| 563 | + |
| 564 | + fn environment_branch_policies( |
| 565 | + &self, |
| 566 | + org: &str, |
| 567 | + repo: &str, |
| 568 | + environment: &str, |
| 569 | + ) -> anyhow::Result<Vec<BranchPolicy>> { |
| 570 | + #[derive(serde::Deserialize)] |
| 571 | + struct BranchPoliciesResponse { |
| 572 | + branch_policies: Vec<BranchPolicy>, |
| 573 | + } |
| 574 | + |
| 575 | + let mut policies = Vec::new(); |
| 576 | + let url = GitHubUrl::repos( |
| 577 | + org, |
| 578 | + repo, |
| 579 | + &format!("environments/{environment}/deployment-branch-policies"), |
| 580 | + )?; |
| 581 | + |
| 582 | + if let Err(err) = |
| 583 | + self.client |
| 584 | + .rest_paginated(&Method::GET, &url, |resp: BranchPoliciesResponse| { |
| 585 | + policies.extend(resp.branch_policies); |
| 586 | + Ok(()) |
| 587 | + }) |
| 588 | + { |
| 589 | + match err { |
| 590 | + RestPaginatedError::Http { |
| 591 | + status: StatusCode::NOT_FOUND, |
| 592 | + .. |
| 593 | + } => return Ok(policies), |
| 594 | + other => { |
| 595 | + return Err(anyhow::Error::from(other)).with_context(|| { |
| 596 | + format!( |
| 597 | + "failed to fetch deployment branch policies for environment '{environment}' in '{org}/{repo}'" |
| 598 | + ) |
| 599 | + }); |
| 600 | + } |
| 601 | + } |
| 602 | + } |
| 603 | + |
| 604 | + Ok(policies) |
| 605 | + } |
573 | 606 | } |
0 commit comments