autoschematic_connector_github/
resource.rs1use std::collections::HashMap;
2
3use autoschematic_core::{
4 connector::{Resource, ResourceAddress},
5 error_util::invalid_addr,
6 macros::FieldTypes,
7 util::RON,
8};
9use autoschematic_macros::FieldTypes;
10use documented::{Documented, DocumentedFields};
11use serde::{Deserialize, Serialize};
12
13use super::addr::GitHubResourceAddress;
14
15#[derive(Debug, Serialize, Deserialize, PartialEq, Documented, DocumentedFields, FieldTypes)]
16#[serde(default, deny_unknown_fields)]
17pub struct GitHubRepository {
19 pub description: Option<String>,
21 pub homepage: Option<String>,
23 pub topics: Vec<String>,
25 pub private: bool,
27 pub has_issues: bool,
29 pub has_projects: bool,
31 pub has_wiki: bool,
33 pub allow_squash_merge: bool,
35 pub allow_merge_commit: bool,
37 pub allow_rebase_merge: bool,
39 pub allow_auto_merge: bool,
41 pub delete_branch_on_merge: bool,
43 pub default_branch: String,
45 pub archived: bool,
47 pub disabled: bool,
49 pub collaborators: HashMap<CollaboratorPrincipal, Role>,
51}
52
53impl Default for GitHubRepository {
54 fn default() -> Self {
55 Self {
56 description: Default::default(),
57 homepage: Default::default(),
58 topics: Default::default(),
59 private: true,
60 has_issues: true,
61 has_projects: true,
62 has_wiki: true,
63 allow_squash_merge: true,
64 allow_merge_commit: true,
65 allow_rebase_merge: true,
66 allow_auto_merge: false,
67 delete_branch_on_merge: false,
68 default_branch: "main".into(),
69 archived: false,
70 disabled: false,
71 collaborators: Default::default(),
72 }
73 }
74}
75
76#[derive(Debug, Serialize, Deserialize, PartialEq, Documented, DocumentedFields, FieldTypes)]
77#[serde(deny_unknown_fields)]
78pub struct RequiredStatusChecks {
80 pub strict: bool,
82 pub contexts: Vec<String>,
84}
85
86#[derive(Debug, Serialize, Deserialize, PartialEq, Documented, DocumentedFields, FieldTypes)]
87#[serde(deny_unknown_fields)]
88pub struct PullRequestReviewEnforcement {
90 pub required_approving_review_count: u32,
92 pub dismiss_stale_reviews: bool,
94 pub require_code_owner_reviews: bool,
96 pub require_last_push_approval: bool,
98}
99
100#[derive(Debug, Serialize, Deserialize, PartialEq, Documented, DocumentedFields, FieldTypes)]
101#[serde(deny_unknown_fields)]
102pub struct BranchRestrictions {
104 pub users: Vec<String>,
106 pub teams: Vec<String>,
108 pub apps: Vec<String>,
110}
111
112#[derive(Debug, Serialize, Deserialize, PartialEq, Documented, DocumentedFields, FieldTypes)]
113#[serde(deny_unknown_fields)]
114pub struct BranchProtection {
116 pub required_status_checks: Option<RequiredStatusChecks>,
118 pub enforce_admins: bool,
120 pub required_pull_request_reviews: Option<PullRequestReviewEnforcement>,
122 pub restrictions: Option<BranchRestrictions>,
124 pub required_linear_history: bool,
126 pub allow_force_pushes: bool,
128 pub allow_deletions: bool,
130 pub block_creations: bool,
132 pub required_conversation_resolution: bool,
134 pub lock_branch: bool,
136 pub allow_fork_syncing: bool,
138}
139
140#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Documented, DocumentedFields)]
141pub enum CollaboratorPrincipal {
143 User(String),
145 Team(String),
147}
148
149#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Documented)]
150pub enum Role {
152 Read,
154 Triage,
156 Write,
158 Maintain,
160 Admin,
162 Custom(String),
164}
165
166impl Role {
167 pub fn to_string(&self) -> String {
168 match self {
169 Role::Read => "read",
170 Role::Triage => "triage",
171 Role::Write => "write",
172 Role::Maintain => "maintain",
173 Role::Admin => "admin",
174 Role::Custom(s) => s,
175 }
176 .into()
177 }
178 pub fn from_str(s: &str) -> Self {
179 match s {
180 "read" => Role::Read,
181 "triage" => Role::Triage,
182 "write" => Role::Write,
183 "maintain" => Role::Maintain,
184 "admin" => Role::Admin,
185 s => Role::Custom(s.into()),
186 }
187 }
188}
189
190pub enum GitHubResource {
199 Repository(GitHubRepository),
200 BranchProtection(BranchProtection),
201}
202
203impl Resource for GitHubResource {
204 fn to_bytes(&self) -> Result<Vec<u8>, anyhow::Error> {
205 let pretty_config = autoschematic_core::util::PrettyConfig::default().struct_names(true);
206 match self {
207 GitHubResource::Repository(repo) => Ok(RON.to_string_pretty(&repo, pretty_config)?.into()),
208 GitHubResource::BranchProtection(protection) => Ok(RON.to_string_pretty(&protection, pretty_config)?.into()),
209 }
210 }
211
212 fn from_bytes(addr: &impl ResourceAddress, s: &[u8]) -> Result<Self, anyhow::Error>
213 where
214 Self: Sized,
215 {
216 let addr = GitHubResourceAddress::from_path(&addr.to_path_buf())?;
217 let s = std::str::from_utf8(s)?;
218
219 match addr {
220 GitHubResourceAddress::Repository { .. } => Ok(GitHubResource::Repository(RON.from_str(s)?)),
221 GitHubResourceAddress::BranchProtection { .. } => Ok(GitHubResource::BranchProtection(RON.from_str(s)?)),
222 _ => Err(invalid_addr(&addr)),
223 }
224 }
225}