1use anyhow::{bail, Result};
2use apm_core::{git, ticket, ticket_fmt};
3use chrono::Utc;
4use std::path::Path;
5use crate::ctx::CmdContext;
6
7pub fn run(root: &Path, id_arg: &str, field: String, value: String, no_aggressive: bool) -> Result<()> {
8 let ctx = CmdContext::load(root, no_aggressive)?;
9 let id = ticket::resolve_id_in_slice(&ctx.tickets, id_arg)?;
10 let mut tickets = ctx.tickets;
11
12 if field == "depends_on" && value != "-" {
13 let ids: Vec<String> = value
14 .split(',')
15 .map(|s| s.trim().to_string())
16 .filter(|s| !s.is_empty())
17 .collect();
18 if !ids.is_empty() {
19 let ticket = tickets.iter().find(|t| t.frontmatter.id == id)
20 .ok_or_else(|| anyhow::anyhow!("ticket {id:?} not found"))?;
21 let strategy = apm_core::validate::active_completion_strategy(&ctx.config);
22 apm_core::validate::check_depends_on_rules(
23 &strategy,
24 ticket.frontmatter.epic.as_deref(),
25 ticket.frontmatter.target_branch.as_deref(),
26 &ids,
27 &tickets,
28 &ctx.config.project.default_branch,
29 )?;
30 }
31 }
32
33 let Some(t) = tickets.iter_mut().find(|t| t.frontmatter.id == id) else {
34 bail!("ticket {id:?} not found");
35 };
36 if field == "owner" {
37 ticket::check_owner(root, t)?;
38 let local = apm_core::config::LocalConfig::load(root);
39 apm_core::validate::validate_owner(&ctx.config, &local, &value)?;
40 }
41 if field == "agent" {
42 apm_core::validate::validate_agent_name(&ctx.config, &value)?;
43 }
44 ticket::set_field(&mut t.frontmatter, &field, &value)?;
45 t.frontmatter.updated_at = Some(Utc::now());
46
47 let content = t.serialize()?;
48 let rel_path = format!(
49 "{}/{}",
50 ctx.config.tickets.dir.to_string_lossy(),
51 t.path.file_name().unwrap().to_string_lossy()
52 );
53 let branch = t
54 .frontmatter
55 .branch
56 .clone()
57 .or_else(|| ticket_fmt::branch_name_from_path(&t.path))
58 .unwrap_or_else(|| format!("ticket/{id}"));
59
60 git::commit_to_branch(
61 root,
62 &branch,
63 &rel_path,
64 &content,
65 &format!("ticket({id}): set {field} = {value}"),
66 )?;
67
68 if ctx.aggressive {
69 if let Err(e) = git::push_branch(root, &branch) {
70 eprintln!("warning: push failed: {e:#}");
71 }
72 }
73
74 println!("{id}: {field} = {value}");
75 Ok(())
76}