wowlab_docgen_cli/context/collectors/
ci.rs1use serde::Serialize;
2
3use super::{ContextEntry, to_value};
4use crate::{HasName, RenderCtx, sort_by_name};
5
6#[derive(Debug, Serialize)]
8pub struct Workflow {
9 pub name: String,
10 pub file: String,
11 pub triggers: Vec<String>,
12}
13
14impl HasName for Workflow {
15 fn name(&self) -> &str {
16 &self.name
17 }
18}
19
20#[must_use]
22pub fn collect(ctx: &RenderCtx<'_>) -> Vec<ContextEntry> {
23 if !ctx.is_root() {
24 return Vec::new();
25 }
26
27 let workflows_dir = ctx.root.join(".github/workflows");
28 let mut workflows: Vec<Workflow> = ctx
29 .workspace
30 .files_in(&workflows_dir)
31 .filter_map(|path| {
32 let ext = path.extension()?.to_str()?;
33
34 if ext != "yml" && ext != "yaml" {
35 return None;
36 }
37
38 let content = ctx.workspace.contents(path)?;
39 let file = path.file_name()?.to_str()?.to_string();
40
41 parse_workflow(content, file)
42 })
43 .collect();
44
45 if workflows.is_empty() {
46 return Vec::new();
47 }
48
49 sort_by_name(&mut workflows);
50
51 vec![("workflows", to_value(&workflows))]
52}
53
54fn parse_workflow(content: &str, file: String) -> Option<Workflow> {
55 let doc: serde_norway::Value = serde_norway::from_str(content).ok()?;
56 let mapping = doc.as_mapping()?;
57 let name = mapping
58 .get(serde_norway::Value::String("name".into()))?
59 .as_str()?
60 .to_string();
61 let triggers = mapping
62 .get(serde_norway::Value::String("on".into()))
63 .and_then(extract_triggers)
64 .unwrap_or_default();
65
66 Some(Workflow {
67 name,
68 file,
69 triggers,
70 })
71}
72
73fn extract_triggers(on: &serde_norway::Value) -> Option<Vec<String>> {
74 match on {
75 serde_norway::Value::String(s) => Some(vec![s.clone()]),
76 serde_norway::Value::Sequence(seq) => {
77 let triggers: Vec<String> = seq
78 .iter()
79 .filter_map(|v| v.as_str().map(String::from))
80 .collect();
81
82 Some(triggers)
83 }
84 serde_norway::Value::Mapping(map) => {
85 let triggers: Vec<String> = map
86 .keys()
87 .filter_map(|k| k.as_str().map(String::from))
88 .collect();
89
90 Some(triggers)
91 }
92 _ => None,
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use googletest::prelude::*;
99
100 use super::*;
101
102 #[gtest]
103 fn extract_triggers_string() -> Result<()> {
104 let val = serde_norway::Value::String("push".into());
105 let triggers = extract_triggers(&val).or_fail()?;
106
107 verify_that!(triggers, elements_are![eq("push")])
108 }
109
110 #[gtest]
111 fn extract_triggers_sequence() -> Result<()> {
112 let val = serde_norway::Value::Sequence(vec![
113 serde_norway::Value::String("push".into()),
114 serde_norway::Value::String("pull_request".into()),
115 ]);
116 let triggers = extract_triggers(&val).or_fail()?;
117
118 verify_that!(triggers, elements_are![eq("push"), eq("pull_request")])
119 }
120
121 #[gtest]
122 fn extract_triggers_mapping() -> Result<()> {
123 let yaml = "push:\n branches: [main]\npull_request:\n branches: [main]";
124 let val: serde_norway::Value = serde_norway::from_str(yaml).or_fail()?;
125 let mut triggers = extract_triggers(&val).or_fail()?;
126
127 triggers.sort();
128
129 verify_that!(triggers, elements_are![eq("pull_request"), eq("push")])
130 }
131
132 #[gtest]
133 fn extract_triggers_null() -> Result<()> {
134 let val = serde_norway::Value::Null;
135
136 verify_that!(extract_triggers(&val), none())
137 }
138}