1use indexmap::IndexMap;
4use serde::{Deserialize, Serialize};
5
6use crate::common::EnvValue;
7
8#[derive(Deserialize, Debug, PartialEq, Eq, Hash)]
17#[serde(rename_all = "snake_case")]
18pub enum BareEvent {
19 BranchProtectionRule,
20 CheckRun,
21 CheckSuite,
22 Create,
23 Delete,
24 Deployment,
25 DeploymentStatus,
26 Discussion,
27 DiscussionComment,
28 Fork,
29 Gollum,
30 IssueComment,
31 Issues,
32 Label,
33 MergeGroup,
34 Milestone,
35 PageBuild,
36 Project,
37 ProjectCard,
38 ProjectColumn,
39 Public,
40 PullRequest,
41 PullRequestComment,
42 PullRequestReview,
43 PullRequestReviewComment,
44 PullRequestTarget,
45 Push,
46 RegistryPackage,
47 Release,
48 RepositoryDispatch,
49 Status,
51 Watch,
52 WorkflowCall,
53 WorkflowDispatch,
54 WorkflowRun,
55}
56
57#[derive(Deserialize, Serialize, Debug, Default)]
61#[serde(default, rename_all = "snake_case")]
62pub struct Events {
63 pub branch_protection_rule: OptionalBody<GenericEvent>,
64 pub check_run: OptionalBody<GenericEvent>,
65 pub check_suite: OptionalBody<GenericEvent>,
66 pub discussion: OptionalBody<GenericEvent>,
69 pub discussion_comment: OptionalBody<GenericEvent>,
70 pub issue_comment: OptionalBody<GenericEvent>,
72 pub issues: OptionalBody<GenericEvent>,
73 pub label: OptionalBody<GenericEvent>,
74 pub merge_group: OptionalBody<GenericEvent>,
75 pub milestone: OptionalBody<GenericEvent>,
76 pub project: OptionalBody<GenericEvent>,
78 pub project_card: OptionalBody<GenericEvent>,
79 pub project_column: OptionalBody<GenericEvent>,
80 pub pull_request: OptionalBody<PullRequest>,
82 pub pull_request_comment: OptionalBody<GenericEvent>,
83 pub pull_request_review: OptionalBody<GenericEvent>,
84 pub pull_request_review_comment: OptionalBody<GenericEvent>,
85 pub pull_request_target: OptionalBody<PullRequest>,
87 pub push: OptionalBody<Push>,
88 pub registry_package: OptionalBody<GenericEvent>,
89 pub release: OptionalBody<GenericEvent>,
90 pub repository_dispatch: OptionalBody<GenericEvent>,
91 pub schedule: OptionalBody<Vec<Cron>>,
92 pub watch: OptionalBody<GenericEvent>,
94 pub workflow_call: OptionalBody<WorkflowCall>,
95 pub workflow_dispatch: OptionalBody<WorkflowDispatch>,
97 pub workflow_run: OptionalBody<WorkflowRun>,
98}
99
100impl Events {
101 pub fn count(&self) -> u32 {
105 let mut count = 0;
108
109 macro_rules! count_if_present {
110 ($($field:ident),*) => {
111 $(
112 if !matches!(self.$field, OptionalBody::Missing) {
113 count += 1;
114 }
115 )*
116 };
117 }
118
119 count_if_present!(
120 branch_protection_rule,
121 check_run,
122 check_suite,
123 discussion,
124 discussion_comment,
125 issue_comment,
126 issues,
127 label,
128 merge_group,
129 milestone,
130 project,
131 project_card,
132 project_column,
133 pull_request,
134 pull_request_comment,
135 pull_request_review,
136 pull_request_review_comment,
137 pull_request_target,
138 push,
139 registry_package,
140 release,
141 repository_dispatch,
142 schedule,
143 watch,
144 workflow_call,
145 workflow_dispatch,
146 workflow_run
147 );
148
149 count
150 }
151}
152
153#[derive(Serialize, Debug, Default)]
161pub enum OptionalBody<T> {
162 Default,
163 #[default]
164 Missing,
165 Body(T),
166}
167
168impl<'de, T> Deserialize<'de> for OptionalBody<T>
169where
170 T: Deserialize<'de>,
171{
172 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
173 where
174 D: serde::Deserializer<'de>,
175 {
176 Option::deserialize(deserializer).map(Into::into)
177 }
178}
179
180impl<T> From<Option<T>> for OptionalBody<T> {
181 fn from(value: Option<T>) -> Self {
182 match value {
183 Some(v) => OptionalBody::Body(v),
184 None => OptionalBody::Default,
185 }
186 }
187}
188
189#[derive(Deserialize, Serialize, Debug)]
191#[serde(rename_all = "kebab-case")]
192pub struct GenericEvent {
193 #[serde(default, deserialize_with = "crate::common::scalar_or_vector")]
194 pub types: Vec<String>,
195}
196
197#[derive(Deserialize, Serialize, Debug)]
199#[serde(rename_all = "kebab-case")]
200pub struct PullRequest {
201 #[serde(default, deserialize_with = "crate::common::scalar_or_vector")]
202 pub types: Vec<String>,
203
204 #[serde(flatten)]
205 pub branch_filters: Option<BranchFilters>,
206
207 #[serde(flatten)]
208 pub path_filters: Option<PathFilters>,
209}
210
211#[derive(Deserialize, Serialize, Debug)]
213#[serde(rename_all = "kebab-case")]
214pub struct Push {
215 #[serde(flatten)]
216 pub branch_filters: Option<BranchFilters>,
217
218 #[serde(flatten)]
219 pub path_filters: Option<PathFilters>,
220
221 #[serde(flatten)]
222 pub tag_filters: Option<TagFilters>,
223}
224
225#[derive(Deserialize, Serialize, Debug)]
227#[serde(rename_all = "kebab-case")]
228pub struct Cron {
229 pub cron: String,
230}
231
232#[derive(Deserialize, Serialize, Debug)]
234#[serde(rename_all = "kebab-case")]
235pub struct WorkflowCall {
236 #[serde(default)]
237 pub inputs: IndexMap<String, WorkflowCallInput>,
238 #[serde(default)]
239 pub outputs: IndexMap<String, WorkflowCallOutput>,
240 #[serde(default)]
241 pub secrets: IndexMap<String, Option<WorkflowCallSecret>>,
242}
243
244#[derive(Deserialize, Serialize, Debug)]
246#[serde(rename_all = "kebab-case")]
247pub struct WorkflowCallInput {
248 pub description: Option<String>,
249 #[serde(default)]
251 pub required: bool,
252 pub r#type: WorkflowCallInputType,
253}
254
255#[derive(Deserialize, Serialize, Debug)]
257#[serde(rename_all = "kebab-case")]
258pub enum WorkflowCallInputType {
259 Boolean,
260 Number,
261 String,
262}
263
264#[derive(Deserialize, Serialize, Debug)]
266#[serde(rename_all = "kebab-case")]
267pub struct WorkflowCallOutput {
268 pub description: Option<String>,
269 pub value: String,
270}
271
272#[derive(Deserialize, Serialize, Debug)]
274#[serde(rename_all = "kebab-case")]
275pub struct WorkflowCallSecret {
276 pub description: Option<String>,
277 #[serde(default)]
278 pub required: bool,
279}
280
281#[derive(Deserialize, Serialize, Debug)]
283#[serde(rename_all = "kebab-case")]
284pub struct WorkflowDispatch {
285 #[serde(default)]
286 pub inputs: IndexMap<String, WorkflowDispatchInput>,
287}
288
289#[derive(Deserialize, Serialize, Debug)]
291#[serde(rename_all = "kebab-case")]
292pub struct WorkflowDispatchInput {
293 pub description: Option<String>,
294 #[serde(default)]
296 pub required: bool,
297 #[serde(default)]
299 pub r#type: WorkflowDispatchInputType,
300 #[serde(default)]
302 pub options: Vec<EnvValue>,
303}
304
305#[derive(Default, Deserialize, Serialize, Debug)]
306#[serde(rename_all = "kebab-case")]
307pub enum WorkflowDispatchInputType {
308 Boolean,
309 Choice,
310 Environment,
311 Number,
312 #[default]
313 String,
314}
315
316#[derive(Deserialize, Serialize, Debug)]
318#[serde(rename_all = "kebab-case")]
319pub struct WorkflowRun {
320 pub workflows: Vec<String>,
321 #[serde(default)]
322 pub types: Vec<String>,
323 #[serde(flatten)]
324 pub branch_filters: Option<BranchFilters>,
325}
326
327#[derive(Deserialize, Serialize, Debug)]
329#[serde(rename_all = "kebab-case")]
330pub enum BranchFilters {
331 Branches(Vec<String>),
332 BranchesIgnore(Vec<String>),
333}
334
335#[derive(Deserialize, Serialize, Debug)]
337#[serde(rename_all = "kebab-case")]
338pub enum TagFilters {
339 Tags(Vec<String>),
340 TagsIgnore(Vec<String>),
341}
342
343#[derive(Deserialize, Serialize, Debug)]
345#[serde(rename_all = "kebab-case")]
346pub enum PathFilters {
347 Paths(Vec<String>),
348 PathsIgnore(Vec<String>),
349}
350
351#[cfg(test)]
352mod tests {
353 #[test]
354 fn test_events_count() {
355 let events = "
356push:
357pull_request:
358workflow_dispatch:
359issue_comment:";
360
361 let events = serde_yaml::from_str::<super::Events>(events).unwrap();
362 assert_eq!(events.count(), 4);
363 }
364}