quanttide_work/
tasklog.rs1use serde_yaml::Value as Yaml;
7
8pub use crate::schema::text_of;
10
11pub fn done(steps: &[String], events: &[Yaml]) -> Vec<String> {
13 let mut verdict: Vec<(String, bool)> = Vec::new();
14 for event in events {
15 let ok = event.get("ok").and_then(|v| v.as_bool()).unwrap_or(false);
16 let raw = text_of(event, "step");
17 let (step, extra) = match raw.split_once('·') {
18 Some((step, rest)) => (step.to_string(), Some(rest.to_string())),
19 None => (raw.clone(), None),
20 };
21 if !steps.contains(&step) {
22 continue;
23 }
24 match verdict.iter_mut().find(|(name, _)| *name == step) {
25 Some((_, last)) => {
26 if extra.is_some() {
27 *last = *last && ok;
28 } else {
29 *last = ok;
30 }
31 }
32 None => verdict.push((step, ok)),
33 }
34 }
35 verdict
36 .into_iter()
37 .filter(|(_, ok)| *ok)
38 .map(|(name, _)| name)
39 .collect()
40}
41
42pub fn next_step(steps: &[String], events: &[Yaml]) -> Option<String> {
44 let finished = done(steps, events);
45 steps.iter().find(|name| !finished.contains(name)).cloned()
46}
47
48pub fn state_line(steps: &[String], events: &[Yaml], workflow_name: &str) -> String {
50 if steps.is_empty() {
51 return format!("这条工作流没有步骤——在 workflows/{workflow_name}.yaml 的 steps 里写步骤");
52 }
53 match next_step(steps, events) {
54 Some(step) => format!("下一步:{step}"),
55 None => format!("{} 个步骤都走过了", steps.len()),
56 }
57}