git_adr/cli/
edit.rs

1//! Edit an existing ADR.
2
3use anyhow::Result;
4use clap::Args as ClapArgs;
5use colored::Colorize;
6
7use crate::core::{AdrStatus, ConfigManager, Git, NotesManager};
8
9/// Arguments for the edit command.
10#[derive(ClapArgs, Debug)]
11pub struct Args {
12    /// ADR ID to edit.
13    pub adr_id: String,
14
15    /// Quick edit: change status.
16    #[arg(long, short)]
17    pub status: Option<String>,
18
19    /// Quick edit: add tag.
20    #[arg(long)]
21    pub add_tag: Option<String>,
22
23    /// Quick edit: remove tag.
24    #[arg(long)]
25    pub remove_tag: Option<String>,
26
27    /// Quick edit: change title.
28    #[arg(long, short)]
29    pub title: Option<String>,
30
31    /// Quick edit: add decider.
32    #[arg(long)]
33    pub add_decider: Option<String>,
34
35    /// Quick edit: remove decider.
36    #[arg(long)]
37    pub remove_decider: Option<String>,
38}
39
40/// Run the edit command.
41///
42/// # Errors
43///
44/// Returns an error if editing fails.
45#[allow(clippy::useless_let_if_seq)]
46pub fn run(args: Args) -> Result<()> {
47    let git = Git::new();
48    git.check_repository()?;
49
50    let config = ConfigManager::new(git.clone()).load()?;
51    let notes = NotesManager::new(git, config);
52
53    // Find the ADR
54    let adrs = notes.list()?;
55    let mut adr = adrs
56        .into_iter()
57        .find(|a| a.id == args.adr_id || a.id.contains(&args.adr_id))
58        .ok_or_else(|| anyhow::anyhow!("ADR not found: {}", args.adr_id))?;
59
60    eprintln!("{} Editing ADR: {}", "→".blue(), adr.id);
61
62    let mut modified = false;
63
64    // Apply quick edits
65    if let Some(status_str) = &args.status {
66        let status: AdrStatus = status_str.parse().map_err(|e| anyhow::anyhow!("{}", e))?;
67        eprintln!("  Status: {} → {}", adr.frontmatter.status, status);
68        adr.frontmatter.status = status;
69        modified = true;
70    }
71
72    if let Some(title) = &args.title {
73        eprintln!("  Title: {} → {}", adr.frontmatter.title, title);
74        adr.frontmatter.title.clone_from(title);
75        modified = true;
76    }
77
78    if let Some(tag) = &args.add_tag {
79        if adr.frontmatter.tags.contains(tag) {
80            eprintln!("  Tag already exists: {}", tag);
81        } else {
82            adr.frontmatter.tags.push(tag.clone());
83            eprintln!("  Added tag: {}", tag);
84            modified = true;
85        }
86    }
87
88    if let Some(tag) = &args.remove_tag {
89        if let Some(pos) = adr.frontmatter.tags.iter().position(|t| t == tag) {
90            adr.frontmatter.tags.remove(pos);
91            eprintln!("  Removed tag: {}", tag);
92            modified = true;
93        } else {
94            eprintln!("  Tag not found: {}", tag);
95        }
96    }
97
98    if let Some(decider) = &args.add_decider {
99        if adr.frontmatter.deciders.contains(decider) {
100            eprintln!("  Decider already exists: {}", decider);
101        } else {
102            adr.frontmatter.deciders.push(decider.clone());
103            eprintln!("  Added decider: {}", decider);
104            modified = true;
105        }
106    }
107
108    if let Some(decider) = &args.remove_decider {
109        if let Some(pos) = adr.frontmatter.deciders.iter().position(|d| d == decider) {
110            adr.frontmatter.deciders.remove(pos);
111            eprintln!("  Removed decider: {}", decider);
112            modified = true;
113        } else {
114            eprintln!("  Decider not found: {}", decider);
115        }
116    }
117
118    if !modified {
119        eprintln!("{} No changes specified", "!".yellow());
120        return Ok(());
121    }
122
123    // Save changes
124    notes.update(&adr)?;
125
126    eprintln!("{} ADR updated: {}", "✓".green(), adr.id);
127
128    Ok(())
129}