Skip to main content

quanttide_work/
tasklog.rs

1//! 任务流水与「走过」的算法。
2//!
3//! 一条流水=时间、步骤名、一句话、过没过。步骤名带后缀的(`·审` 审查、`·判` 机器判据)
4//! **给这一步的结论投票**;不带后缀的(重新执行一次)**把结论从头算**。
5
6use serde_yaml::Value as Yaml;
7
8// 读字段的工具在 schema 一处。
9pub use crate::schema::text_of;
10
11/// 哪些步骤走过了。`steps` 是工作流上的步骤名,按定义顺序。
12pub 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
42/// 第一个没走到的步骤。
43pub 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
48/// 状态行:下一步是谁,或者都走过了。
49pub 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}