1use crate::core::Git;
6use crate::Error;
7
8#[derive(Debug, Clone)]
10pub struct AdrConfig {
11 pub prefix: String,
13 pub digits: u8,
15 pub template: String,
17 pub format: String,
19 pub initialized: bool,
21}
22
23impl Default for AdrConfig {
24 fn default() -> Self {
25 Self {
26 prefix: "ADR-".to_string(),
27 digits: 4,
28 template: "default".to_string(),
29 format: "nygard".to_string(),
30 initialized: false,
31 }
32 }
33}
34
35#[derive(Debug)]
37pub struct ConfigManager {
38 git: Git,
39}
40
41impl ConfigManager {
42 #[must_use]
44 pub const fn new(git: Git) -> Self {
45 Self { git }
46 }
47
48 pub fn load(&self) -> Result<AdrConfig, Error> {
54 let mut config = AdrConfig::default();
55
56 if let Some(val) = self.git.config_get("adr.initialized")? {
58 config.initialized = val == "true";
59 }
60
61 if let Some(val) = self.git.config_get("adr.prefix")? {
63 config.prefix = val;
64 }
65
66 if let Some(val) = self.git.config_get("adr.digits")? {
68 if let Ok(digits) = val.parse::<u8>() {
69 config.digits = digits;
70 }
71 }
72
73 if let Some(val) = self.git.config_get("adr.template")? {
75 config.template = val;
76 }
77
78 if let Some(val) = self.git.config_get("adr.format")? {
80 config.format = val;
81 }
82
83 Ok(config)
84 }
85
86 pub fn save(&self, config: &AdrConfig) -> Result<(), Error> {
92 self.git
93 .config_set("adr.initialized", &config.initialized.to_string())?;
94 self.git.config_set("adr.prefix", &config.prefix)?;
95 self.git
96 .config_set("adr.digits", &config.digits.to_string())?;
97 self.git.config_set("adr.template", &config.template)?;
98 self.git.config_set("adr.format", &config.format)?;
99
100 Ok(())
101 }
102
103 pub fn initialize(&self, config: &AdrConfig) -> Result<(), Error> {
109 self.git.check_repository()?;
111
112 let mut init_config = config.clone();
114 init_config.initialized = true;
115 self.save(&init_config)?;
116
117 Ok(())
118 }
119
120 pub fn is_initialized(&self) -> Result<bool, Error> {
126 let config = self.load()?;
127 Ok(config.initialized)
128 }
129
130 pub fn get(&self, key: &str) -> Result<Option<String>, Error> {
136 self.git.config_get(&format!("adr.{key}"))
137 }
138
139 pub fn set(&self, key: &str, value: &str) -> Result<(), Error> {
145 self.git.config_set(&format!("adr.{key}"), value)
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use std::process::Command as StdCommand;
153 use tempfile::TempDir;
154
155 fn setup_git_repo() -> TempDir {
156 let temp_dir = TempDir::new().expect("Failed to create temp directory");
157 let path = temp_dir.path();
158
159 StdCommand::new("git")
160 .args(["init"])
161 .current_dir(path)
162 .output()
163 .expect("Failed to init git repo");
164
165 StdCommand::new("git")
166 .args(["config", "user.email", "test@example.com"])
167 .current_dir(path)
168 .output()
169 .expect("Failed to set git user email");
170
171 StdCommand::new("git")
172 .args(["config", "user.name", "Test User"])
173 .current_dir(path)
174 .output()
175 .expect("Failed to set git user name");
176
177 std::fs::write(path.join("README.md"), "# Test Repo\n").expect("Failed to write README");
178 StdCommand::new("git")
179 .args(["add", "."])
180 .current_dir(path)
181 .output()
182 .expect("Failed to stage files");
183 StdCommand::new("git")
184 .args(["commit", "-m", "Initial commit"])
185 .current_dir(path)
186 .output()
187 .expect("Failed to create initial commit");
188
189 temp_dir
190 }
191
192 #[test]
193 fn test_default_config() {
194 let config = AdrConfig::default();
195 assert_eq!(config.prefix, "ADR-");
196 assert_eq!(config.digits, 4);
197 assert_eq!(config.template, "default");
198 assert_eq!(config.format, "nygard");
199 assert!(!config.initialized);
200 }
201
202 #[test]
203 fn test_custom_config() {
204 let config = AdrConfig {
205 prefix: "DECISION-".to_string(),
206 digits: 3,
207 template: "madr".to_string(),
208 format: "madr".to_string(),
209 initialized: true,
210 };
211 assert_eq!(config.prefix, "DECISION-");
212 assert_eq!(config.digits, 3);
213 assert_eq!(config.template, "madr");
214 assert!(config.initialized);
215 }
216
217 #[test]
218 fn test_config_clone() {
219 let config = AdrConfig::default();
220 let cloned = config.clone();
221 assert_eq!(config.prefix, cloned.prefix);
222 assert_eq!(config.digits, cloned.digits);
223 }
224
225 #[test]
226 fn test_config_manager_new() {
227 let git = Git::new();
228 let _manager = ConfigManager::new(git);
229 }
231
232 #[test]
233 fn test_config_initialize() {
234 let temp_dir = setup_git_repo();
235 let git = Git::with_work_dir(temp_dir.path());
236 let manager = ConfigManager::new(git);
237
238 let config = AdrConfig {
239 prefix: "TEST-".to_string(),
240 digits: 5,
241 template: "madr".to_string(),
242 format: "madr".to_string(),
243 initialized: false,
244 };
245
246 let result = manager.initialize(&config);
247 assert!(result.is_ok());
248
249 let loaded = manager.load().expect("Should load config");
251 assert!(loaded.initialized);
252 assert_eq!(loaded.prefix, "TEST-");
253 assert_eq!(loaded.digits, 5);
254 }
255
256 #[test]
257 fn test_config_load_save() {
258 let temp_dir = setup_git_repo();
259 let git = Git::with_work_dir(temp_dir.path());
260 let manager = ConfigManager::new(git);
261
262 let config = AdrConfig {
263 prefix: "CUSTOM-".to_string(),
264 digits: 6,
265 template: "nygard".to_string(),
266 format: "nygard".to_string(),
267 initialized: true,
268 };
269
270 manager.save(&config).expect("Should save config");
271 let loaded = manager.load().expect("Should load config");
272
273 assert_eq!(loaded.prefix, "CUSTOM-");
274 assert_eq!(loaded.digits, 6);
275 assert!(loaded.initialized);
276 }
277
278 #[test]
279 fn test_config_is_initialized() {
280 let temp_dir = setup_git_repo();
281 let git = Git::with_work_dir(temp_dir.path());
282 let manager = ConfigManager::new(git);
283
284 assert!(!manager.is_initialized().expect("Should check"));
286
287 let config = AdrConfig::default();
289 manager.initialize(&config).expect("Should initialize");
290
291 assert!(manager.is_initialized().expect("Should check"));
293 }
294
295 #[test]
296 fn test_config_get_set() {
297 let temp_dir = setup_git_repo();
298 let git = Git::with_work_dir(temp_dir.path());
299 let manager = ConfigManager::new(git);
300
301 manager.set("custom", "value").expect("Should set");
303
304 let result = manager.get("custom").expect("Should get");
306 assert_eq!(result, Some("value".to_string()));
307
308 let result = manager.get("nonexistent").expect("Should get");
310 assert_eq!(result, None);
311 }
312}