1use anyhow::Result;
4use chrono::Utc;
5use clap::Args as ClapArgs;
6use colored::Colorize;
7
8use crate::core::{Adr, AdrStatus, ConfigManager, FlexibleDate, Git, NotesManager, TemplateEngine};
9
10#[derive(ClapArgs, Debug)]
12pub struct Args {
13 pub title: String,
15
16 #[arg(long, short, default_value = "proposed")]
18 pub status: String,
19
20 #[arg(long, short = 'g')]
22 pub tag: Vec<String>,
23
24 #[arg(long, short)]
26 pub deciders: Vec<String>,
27
28 #[arg(long, short)]
30 pub link: Option<String>,
31
32 #[arg(long)]
34 pub template: Option<String>,
35
36 #[arg(long, short)]
38 pub file: Option<String>,
39
40 #[arg(long)]
42 pub no_edit: bool,
43
44 #[arg(long)]
46 pub preview: bool,
47}
48
49pub fn run(args: Args) -> Result<()> {
55 let git = Git::new();
56 git.check_repository()?;
57
58 let config = ConfigManager::new(git.clone()).load()?;
59
60 if !config.initialized {
61 anyhow::bail!("git-adr not initialized. Run 'git adr init' first.");
62 }
63
64 let notes = NotesManager::new(git.clone(), config.clone());
65
66 let next_num = notes.next_number()?;
68 let adr_id = notes.format_id(next_num);
69
70 eprintln!("{} Creating new ADR: {}", "→".blue(), adr_id);
71
72 let status: AdrStatus = args.status.parse().map_err(|e| anyhow::anyhow!("{}", e))?;
74
75 let format = args.template.as_deref().unwrap_or(&config.format);
77
78 let commit = match &args.link {
80 Some(sha) => sha.clone(),
81 None => git.head()?,
82 };
83
84 let mut adr = Adr::new(adr_id.clone(), args.title.clone());
86 adr.commit = commit;
87 adr.frontmatter.status = status;
88 adr.frontmatter.tags.clone_from(&args.tag);
89 adr.frontmatter.deciders.clone_from(&args.deciders);
90 adr.frontmatter.date = Some(FlexibleDate(Utc::now()));
91 adr.frontmatter.format = Some(format.to_string());
92
93 let template_engine = TemplateEngine::new();
95 let mut context = std::collections::HashMap::new();
96 context.insert("title".to_string(), adr.frontmatter.title.clone());
97 context.insert("status".to_string(), adr.frontmatter.status.to_string());
98 let body = template_engine.render(format, &context)?;
99 adr.body = body;
100
101 if let Some(file_path) = &args.file {
103 let file_content = std::fs::read_to_string(file_path)?;
104 if file_content.trim().starts_with("---") {
106 let parsed = Adr::from_markdown(adr_id.clone(), adr.commit.clone(), &file_content)?;
107 adr.frontmatter = parsed.frontmatter;
108 adr.body = parsed.body;
109 } else {
110 adr.body = file_content;
111 }
112 }
113
114 if args.preview {
116 eprintln!("{} Preview mode - not saving", "!".yellow());
117 println!("{}", adr.to_markdown()?);
118 return Ok(());
119 }
120
121 notes.create(&adr)?;
123
124 eprintln!("{} Created ADR: {}", "✓".green(), adr_id);
125 eprintln!(" Title: {}", args.title);
126 eprintln!(" Status: {}", adr.frontmatter.status);
127 if !args.tag.is_empty() {
128 eprintln!(" Tags: {}", args.tag.join(", "));
129 }
130
131 Ok(())
132}