Skip to main content

josh_github_graphql/operations/
repo.rs

1use crate::connection::GithubApiConnection;
2
3use josh_github_codegen_graphql::{
4    get_default_branch,
5    get_repository_rulesets::{self, RepositoryRulesetTarget, RuleEnforcement},
6    get_ruleset_required_checks::{
7        self, GetRulesetRequiredChecksNode, RequiredStatusChecksInfoParameters,
8    },
9    GetDefaultBranch, GetRepositoryRulesets, GetRulesetRequiredChecks,
10};
11
12/// A repository ruleset with its branch conditions.
13#[derive(Debug)]
14pub struct RepositoryRuleset {
15    pub id: String,
16    pub name: String,
17    pub enforcement: RuleEnforcement,
18    pub target: Option<RepositoryRulesetTarget>,
19    pub include_refs: Vec<String>,
20    pub exclude_refs: Vec<String>,
21}
22
23/// A required status check from a ruleset.
24#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
25pub struct RequiredStatusCheck {
26    pub context: String,
27    pub integration_id: Option<i64>,
28}
29
30impl GithubApiConnection {
31    /// Returns (default_branch_name, default_branch_head_oid) if available.
32    pub async fn get_default_branch(
33        &self,
34        owner: &str,
35        name: &str,
36    ) -> anyhow::Result<Option<(String, String)>> {
37        let variables = get_default_branch::Variables {
38            owner: owner.to_string(),
39            name: name.to_string(),
40        };
41
42        let response = self.make_request::<GetDefaultBranch>(variables).await?;
43        let repo = match response.repository {
44            Some(r) => r,
45            None => return Ok(None),
46        };
47        let default_ref = match repo.default_branch_ref {
48            Some(r) => r,
49            None => return Ok(None),
50        };
51
52        let target = match default_ref.target {
53            Some(t) => t,
54            None => return Ok(None),
55        };
56
57        Ok(Some((default_ref.name, target.oid)))
58    }
59
60    /// Returns all rulesets for the given repository with their branch conditions.
61    pub async fn get_repository_rulesets(
62        &self,
63        owner: &str,
64        name: &str,
65    ) -> anyhow::Result<Vec<RepositoryRuleset>> {
66        let variables = get_repository_rulesets::Variables {
67            owner: owner.to_string(),
68            name: name.to_string(),
69        };
70
71        let response = self
72            .make_request::<GetRepositoryRulesets>(variables)
73            .await?;
74
75        let rulesets = response
76            .repository
77            .and_then(|r| r.rulesets)
78            .and_then(|r| r.nodes)
79            .unwrap_or_default();
80
81        Ok(rulesets
82            .into_iter()
83            .flatten()
84            .map(|node| {
85                let (include_refs, exclude_refs) = match node.conditions.ref_name {
86                    Some(ref_name) => (ref_name.include, ref_name.exclude),
87                    None => (vec![], vec![]),
88                };
89                RepositoryRuleset {
90                    id: node.id,
91                    name: node.name,
92                    enforcement: node.enforcement,
93                    target: node.target,
94                    include_refs,
95                    exclude_refs,
96                }
97            })
98            .collect())
99    }
100
101    /// Returns the required status checks for the given ruleset.
102    pub async fn get_ruleset_required_checks(
103        &self,
104        ruleset_id: &str,
105    ) -> anyhow::Result<Vec<RequiredStatusCheck>> {
106        let variables = get_ruleset_required_checks::Variables {
107            ruleset_id: ruleset_id.to_string(),
108        };
109
110        let response = self
111            .make_request::<GetRulesetRequiredChecks>(variables)
112            .await?;
113
114        let rules = match response.node {
115            Some(GetRulesetRequiredChecksNode::RepositoryRuleset(ruleset)) => {
116                ruleset.rules.and_then(|r| r.nodes).unwrap_or_default()
117            }
118            _ => return Ok(vec![]),
119        };
120
121        let checks = rules
122            .into_iter()
123            .flatten()
124            .filter_map(|rule| match rule.parameters {
125                Some(RequiredStatusChecksInfoParameters::RequiredStatusChecksParameters(
126                    params,
127                )) => Some(params.required_status_checks),
128                _ => None,
129            })
130            .flatten()
131            .map(|check| RequiredStatusCheck {
132                context: check.context,
133                integration_id: check.integration_id,
134            })
135            .collect();
136
137        Ok(checks)
138    }
139}