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)]
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: String,
253}
254
255#[derive(Deserialize, Serialize, Debug)]
257#[serde(rename_all = "kebab-case")]
258pub struct WorkflowCallOutput {
259 pub description: Option<String>,
260 pub value: String,
261}
262
263#[derive(Deserialize, Serialize, Debug)]
265#[serde(rename_all = "kebab-case")]
266pub struct WorkflowCallSecret {
267 pub description: Option<String>,
268 #[serde(default)]
269 pub required: bool,
270}
271
272#[derive(Deserialize, Serialize, Debug)]
274#[serde(rename_all = "kebab-case")]
275pub struct WorkflowDispatch {
276 #[serde(default)]
277 pub inputs: IndexMap<String, WorkflowDispatchInput>, }
279
280#[derive(Deserialize, Serialize, Debug)]
282#[serde(rename_all = "kebab-case")]
283pub struct WorkflowDispatchInput {
284 pub description: Option<String>,
285 #[serde(default)]
287 pub required: bool,
288 pub r#type: Option<String>,
290 #[serde(default)]
292 pub options: Vec<EnvValue>,
293}
294
295#[derive(Deserialize, Serialize, Debug)]
297#[serde(rename_all = "kebab-case")]
298pub struct WorkflowRun {
299 pub workflows: Vec<String>,
300 #[serde(default)]
301 pub types: Vec<String>,
302 #[serde(flatten)]
303 pub branch_filters: Option<BranchFilters>,
304}
305
306#[derive(Deserialize, Serialize, Debug)]
308#[serde(rename_all = "kebab-case")]
309pub enum BranchFilters {
310 Branches(Vec<String>),
311 BranchesIgnore(Vec<String>),
312}
313
314#[derive(Deserialize, Serialize, Debug)]
316#[serde(rename_all = "kebab-case")]
317pub enum TagFilters {
318 Tags(Vec<String>),
319 TagsIgnore(Vec<String>),
320}
321
322#[derive(Deserialize, Serialize, Debug)]
324#[serde(rename_all = "kebab-case")]
325pub enum PathFilters {
326 Paths(Vec<String>),
327 PathsIgnore(Vec<String>),
328}
329
330#[cfg(test)]
331mod tests {
332 #[test]
333 fn test_events_count() {
334 let events = "
335push:
336pull_request:
337workflow_dispatch:
338issue_comment:";
339
340 let events = serde_yaml::from_str::<super::Events>(events).unwrap();
341 assert_eq!(events.count(), 4);
342 }
343}