diff --git a/src/commit_pattern/mod.rs b/src/commit_pattern/mod.rs index 230dd78..8541a6e 100644 --- a/src/commit_pattern/mod.rs +++ b/src/commit_pattern/mod.rs @@ -83,3 +83,15 @@ impl CommitPattern { ] } } + +impl Default for CommitPattern { + fn default() -> Self { + Self { + config: Config::default(), + commit_types: Self::commit_types(), + commit_scopes: Self::commit_scopes(), + skip_commit: vec![], + msg: Messages::default(), + } + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 552f462..24be087 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,17 +2,11 @@ mod tests; use anyhow::{anyhow, Context, Result}; -use std::fs; -use std::path::Path; +use std::fs::File; use std::path::PathBuf; use crate::commit_pattern::CommitPattern; -fn get_config_path_content(config_path: impl AsRef) -> Result { - let content = fs::read_to_string(config_path)?; - Ok(content) -} - fn select_custom_config_path(config: Option) -> Result { match config { Some(config_path) => { @@ -35,22 +29,44 @@ fn select_custom_config_path(config: Option) -> Result { } } -fn get_config_path() -> Result { +fn search_config_file_on_parents() -> Result> { let current_dir = std::env::current_dir()?; - let current_file = current_dir.join("commit.json"); - if current_file.is_file() { - Ok(current_file) - } else { - let config_file = dirs::config_dir() - .ok_or_else(|| anyhow!("Could not find config directory"))? - .join("commit/commit.json"); - Ok(config_file) + let mut current_dir = current_dir.as_path(); + loop { + let config_file = current_dir.join("commit.json"); + if config_file.is_file() { + return Ok(Some(config_file)); + } + if let Some(parent) = current_dir.parent() { + current_dir = parent; + } else { + break; + } } + Ok(None) +} + +fn get_config_path() -> Result { + Ok(search_config_file_on_parents()?.unwrap_or_else(|| { + dirs::config_dir() + .expect("Could not find config directory") + .join("commit/commit.json") + })) } pub fn get_pattern(config_path: Option) -> Result { let selected_config_path = select_custom_config_path(config_path)?; - let pattern_str = - get_config_path_content(selected_config_path).unwrap_or_else(|_| "{}".to_owned()); - serde_json::from_str(&pattern_str).context("Failed to parse commit pattern from file") + if selected_config_path.exists() { + let file = File::open(&selected_config_path).context(format!( + "Could not open config file: {}", + selected_config_path.display() + ))?; + let reader = std::io::BufReader::new(file); + Ok(serde_json::from_reader(reader).context(format!( + "Could not parse config file: {}", + selected_config_path.display() + ))?) + } else { + Ok(CommitPattern::default()) + } } diff --git a/src/config/tests.rs b/src/config/tests.rs index fef8fb4..f953ba9 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -1,4 +1,4 @@ -use std::env::set_current_dir; +use std::{env::set_current_dir, fs::remove_file}; use super::*; use assert_fs::prelude::*; @@ -32,7 +32,15 @@ fn select_custom_config_path_test() -> Result<()> { #[serial] fn get_config_path_test() -> Result<()> { let temp_dir = assert_fs::TempDir::new()?; - set_current_dir(temp_dir.path())?; + temp_dir.child("commit.json").touch()?; + temp_dir.child("some/sub/dir").create_dir_all()?; + set_current_dir(temp_dir.path().join("some/sub/dir"))?; + let config_path = get_config_path()?; + assert_eq!( + config_path.to_str(), + temp_dir.path().join("commit.json").to_str() + ); + remove_file(temp_dir.path().join("commit.json"))?; let config_file = dirs::config_dir() .ok_or_else(|| anyhow!("Could not find config directory"))? .join("commit/commit.json"); @@ -41,23 +49,6 @@ fn get_config_path_test() -> Result<()> { Ok(()) } -#[test] -#[serial] -fn get_config_path_content_test() -> Result<()> { - let temp_dir = assert_fs::TempDir::new()?; - let config_file = temp_dir.child("config.json"); - config_file.touch()?; - let config_path = config_file.path(); - let content = get_config_path_content(config_path)?; - assert_eq!(content, ""); - - let expected = include_str!("../../commit.json"); - config_file.write_str(expected)?; - let content = get_config_path_content(config_path)?; - assert_eq!(content, expected); - Ok(()) -} - #[test] #[serial] fn get_pattern_test() -> Result<()> {