git_adr/cli/
convert.rs

1//! Convert ADR between formats.
2
3use anyhow::Result;
4use clap::Args as ClapArgs;
5use colored::Colorize;
6
7use crate::core::{ConfigManager, Git, NotesManager, TemplateEngine};
8
9/// Arguments for the convert command.
10#[derive(ClapArgs, Debug)]
11pub struct Args {
12    /// ADR ID to convert.
13    pub adr_id: String,
14
15    /// Target format (nygard, madr, y-statement, alexandrian).
16    #[arg(long, short)]
17    pub to: String,
18
19    /// Save in place (update the ADR).
20    #[arg(long)]
21    pub in_place: bool,
22}
23
24/// Supported formats.
25const FORMATS: &[&str] = &["nygard", "madr", "y-statement", "alexandrian"];
26
27/// Run the convert command.
28///
29/// # Errors
30///
31/// Returns an error if conversion fails.
32pub fn run(args: Args) -> Result<()> {
33    let git = Git::new();
34    git.check_repository()?;
35
36    let config = ConfigManager::new(git.clone()).load()?;
37    let notes = NotesManager::new(git, config);
38
39    // Validate target format
40    if !FORMATS.contains(&args.to.as_str()) {
41        anyhow::bail!(
42            "Unknown format: {}. Supported formats: {}",
43            args.to,
44            FORMATS.join(", ")
45        );
46    }
47
48    // Find the ADR
49    let adrs = notes.list()?;
50    let mut adr = adrs
51        .into_iter()
52        .find(|a| a.id == args.adr_id || a.id.contains(&args.adr_id))
53        .ok_or_else(|| anyhow::anyhow!("ADR not found: {}", args.adr_id))?;
54
55    let current_format = adr.frontmatter.format.as_deref().unwrap_or("nygard");
56
57    if current_format == args.to {
58        eprintln!(
59            "{} ADR is already in {} format",
60            "!".yellow(),
61            args.to.cyan()
62        );
63        return Ok(());
64    }
65
66    eprintln!(
67        "{} Converting ADR {} from {} to {}",
68        "→".blue(),
69        adr.id.cyan(),
70        current_format.yellow(),
71        args.to.green()
72    );
73
74    // Re-render the body with the new template
75    let template_engine = TemplateEngine::new();
76    let mut context = std::collections::HashMap::new();
77    context.insert("title".to_string(), adr.frontmatter.title.clone());
78    context.insert("status".to_string(), adr.frontmatter.status.to_string());
79    let new_body = template_engine.render(&args.to, &context)?;
80
81    // Update format metadata
82    adr.frontmatter.format = Some(args.to.clone());
83    adr.body = new_body;
84
85    if args.in_place {
86        // Save the converted ADR
87        notes.update(&adr)?;
88        eprintln!("{} ADR {} converted and saved", "✓".green(), adr.id.cyan());
89    } else {
90        // Just print the converted content
91        println!("{}", adr.to_markdown()?);
92        eprintln!();
93        eprintln!("{} Use {} to save changes", "→".blue(), "--in-place".cyan());
94    }
95
96    Ok(())
97}