chant/operations/
update.rs1use anyhow::Result;
6use std::path::Path;
7
8use crate::spec::{Spec, SpecStatus, TransitionBuilder};
9
10#[derive(Debug, Clone, Default)]
12pub struct UpdateOptions {
13 pub status: Option<SpecStatus>,
15 pub depends_on: Option<Vec<String>>,
17 pub labels: Option<Vec<String>>,
19 pub target_files: Option<Vec<String>>,
21 pub model: Option<String>,
23 pub output: Option<String>,
25 pub replace_body: bool,
27 pub force: bool,
29}
30
31pub fn update_spec(spec: &mut Spec, spec_path: &Path, options: UpdateOptions) -> Result<()> {
36 let mut updated = false;
37
38 if let Some(new_status) = options.status {
40 let mut builder = TransitionBuilder::new(spec);
41 if options.force {
42 builder = builder.force();
43 }
44 builder.to(new_status)?;
45 updated = true;
46 }
47
48 if let Some(depends_on) = options.depends_on {
50 spec.frontmatter.depends_on = Some(depends_on);
51 updated = true;
52 }
53
54 if let Some(labels) = options.labels {
56 spec.frontmatter.labels = Some(labels);
57 updated = true;
58 }
59
60 if let Some(target_files) = options.target_files {
62 spec.frontmatter.target_files = Some(target_files);
63 updated = true;
64 }
65
66 if let Some(model) = options.model {
68 spec.frontmatter.model = Some(model);
69 updated = true;
70 }
71
72 if let Some(output) = options.output {
74 if !output.is_empty() {
75 if options.replace_body {
76 let has_title_in_output = output.lines().any(|l| l.trim().starts_with("# "));
78 if !has_title_in_output {
79 if let Some(ref title) = spec.title {
80 spec.body = format!("# {}\n\n{}", title, output);
81 } else {
82 spec.body = output.clone();
83 }
84 } else {
85 spec.body = output.clone();
86 }
87 if !spec.body.ends_with('\n') {
88 spec.body.push('\n');
89 }
90 } else {
91 if !spec.body.ends_with('\n') && !spec.body.is_empty() {
93 spec.body.push('\n');
94 }
95 spec.body.push_str("\n## Output\n\n");
96 spec.body.push_str(&output);
97 spec.body.push('\n');
98 }
99 updated = true;
100 }
101 }
102
103 if !updated {
104 anyhow::bail!("No updates specified");
105 }
106
107 spec.save(spec_path)?;
109
110 Ok(())
111}