From 60e8f32cb4877697355a7f6e03a5d163964cdbbb Mon Sep 17 00:00:00 2001 From: Finley Thomalla Date: Tue, 17 Dec 2024 11:10:32 +0100 Subject: [PATCH] fix(config): handled better using config-rs closes #118 --- Cargo.lock | 188 +++++++++++++++++++++++++++++++++++- Cargo.toml | 6 +- meta/config/default.toml | 2 + src/bin/main.rs | 2 +- src/lib/answers.rs | 82 +++++++++++----- src/lib/config.rs | 202 +++++++++++++++++++++++---------------- tests/integration.rs | 13 +++ 7 files changed, 382 insertions(+), 113 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bde7928..75851a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,6 +23,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -81,6 +99,12 @@ version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + [[package]] name = "assert_cmd" version = "2.0.16" @@ -97,12 +121,29 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "bitflags" version = "1.3.2" @@ -114,6 +155,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -337,10 +381,37 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" dependencies = [ + "async-trait", + "convert_case", + "json5", "nom", "pathdiff", + "ron", + "rust-ini", "serde", + "serde_json", "toml 0.8.19", + "yaml-rust2", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", ] [[package]] @@ -353,6 +424,15 @@ dependencies = [ "pest_derive", ] +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -418,6 +498,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -482,6 +568,15 @@ dependencies = [ "syn", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -519,6 +614,15 @@ dependencies = [ "phf", ] +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + [[package]] name = "envmnt" version = "0.8.4" @@ -668,12 +772,31 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "heck" version = "0.5.0" @@ -969,6 +1092,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "koji" version = "3.0.0" @@ -978,6 +1112,7 @@ dependencies = [ "clap", "clap_complete_command", "cocogitto", + "config", "conventional_commit_parser", "dirs", "emojis", @@ -989,7 +1124,6 @@ dependencies = [ "rusty-hook", "serde", "tempfile", - "toml 0.8.19", ] [[package]] @@ -1203,6 +1337,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1485,6 +1629,28 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + +[[package]] +name = "rust-ini" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustix" version = "0.38.41" @@ -1780,6 +1946,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -2273,6 +2448,17 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "yaml-rust2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] + [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index e72e9e7..d4e77d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,9 @@ emojis = "0.6" git2 = "0.18" indexmap = "2.1" serde = { version = "1.0", features = ["derive"] } -toml = "0.8" -inquire = "0.7.5" -clap_complete_command = { version = "0.6.1", features = ["nushell"]} +inquire = "0.7" +clap_complete_command = { version = "0.6", features = ["nushell"]} +config = { version = "0.14", features = ["toml"] } [features] vendored-openssl = ["git2/vendored-openssl"] diff --git a/meta/config/default.toml b/meta/config/default.toml index 55d1abb..8d0b072 100644 --- a/meta/config/default.toml +++ b/meta/config/default.toml @@ -1,6 +1,8 @@ +autocomplete = false breaking_changes = true issues = true emoji = false +sign = false [[commit_types]] name = "feat" diff --git a/src/bin/main.rs b/src/bin/main.rs index 07ced59..111aa4a 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -47,7 +47,7 @@ struct Args { help_heading = Some("Configuration"), help = "Path to a custom config file" )] - config: Option, + config: Option, #[arg( long, diff --git a/src/lib/answers.rs b/src/lib/answers.rs index b7e8b6c..b3515ef 100644 --- a/src/lib/answers.rs +++ b/src/lib/answers.rs @@ -96,7 +96,9 @@ pub fn get_extracted_answers(answers: Answers, config: &Config) -> Result Result<(), Box> { + let commit_types = indexmap! { + "docs".into() => CommitType { + name: "docs".into(), + description: "Changes to documentation".into(), + emoji: Some("📚".to_string()), + }, + }; let answer = "needed more badges"; assert_eq!( - get_summary(answer, false, "docs", &commit_types).unwrap(), + get_summary(answer, false, "docs", &commit_types)?, "needed more badges" ); + + Ok(()) } #[test] - fn test_get_summary_with_emoji() { - let config = Config::new(None).unwrap(); - let commit_types = config.commit_types; + fn test_get_summary_with_emoji() -> Result<(), Box> { + let commit_types = indexmap! { + "docs".into() => CommitType { + name: "docs".into(), + description: "Changes to documentation".into(), + emoji: Some("📚".to_string()), + }, + }; let answer = "needed more badges"; assert_eq!( - get_summary(answer, true, "docs", &commit_types).unwrap(), + get_summary(answer, true, "docs", &commit_types)?, "📚 needed more badges" ); + + Ok(()) } #[test] - fn test_get_summary_with_non_configured_emoji() { + fn test_get_summary_with_non_configured_emoji() -> Result<(), Box> { let commit_types = indexmap! { "docs".into() => CommitType { name: "docs".into(), @@ -142,26 +158,35 @@ mod tests { let answer = "needed more badges"; assert_eq!( - get_summary(answer, true, "docs", &commit_types).unwrap(), + get_summary(answer, true, "docs", &commit_types)?, "needed more badges" ); + + Ok(()) } #[test] - fn test_get_summary_with_shortcode() { - let config = Config::new(None).unwrap(); - let commit_types = config.commit_types; + fn test_get_summary_with_shortcode() -> Result<(), Box> { + let commit_types = indexmap! { + "docs".into() => CommitType { + name: "docs".into(), + description: "Changes to documentation".into(), + emoji: None, + }, + }; let answer = "needed more badges :badger:"; assert_eq!( - get_summary(answer, false, "docs", &commit_types).unwrap(), + get_summary(answer, false, "docs", &commit_types)?, "needed more badges 🦡" ); + + Ok(()) } #[test] - fn test_into_breaking_footer() { + fn test_into_breaking_footer() -> Result<(), Box> { let breaking_text = Some("this is a breaking change".to_string()); assert_eq!( into_breaking_footer(&breaking_text), @@ -170,10 +195,12 @@ mod tests { let breaking_text = None; assert_eq!(into_breaking_footer(&breaking_text), None); + + Ok(()) } #[test] - fn test_get_amended_body() { + fn test_get_amended_body() -> Result<(), Box> { let body = Some("i _really_ like badges".to_string()); let issue_reference = Some("closes #1".to_string()); let breaking_text = Some("BREAKING CHANGE: this is a breaking change".to_string()); @@ -205,7 +232,6 @@ mod tests { get_amended_body(&None, &issue_reference, &breaking_text), Some("closes #1\nBREAKING CHANGE: this is a breaking change".into()) ); - assert_eq!( get_amended_body(&None, &issue_reference, &None), Some("closes #1".into()) @@ -217,10 +243,14 @@ mod tests { ); assert_eq!(get_amended_body(&None, &None, &None), None); + + Ok(()) } #[test] - fn test_get_extracted_answers() { + fn test_get_extracted_answers() -> Result<(), Box> { + let tmpdir = tempfile::tempdir()?; + let answers = Answers { commit_type: "feat".into(), scope: Some("space".into()), @@ -231,8 +261,11 @@ mod tests { breaking_change_footer: Some("this is a breaking change".into()), }; - let config = Config::new(None).unwrap(); - let extracted_answers = get_extracted_answers(answers, &config).unwrap(); + let config = Config::new(Some(crate::config::ConfigArgs { + _user_config_path: Some(tmpdir.path().to_path_buf()), + ..Default::default() + }))?; + let extracted_answers = get_extracted_answers(answers, &config)?; assert_eq!( extracted_answers, @@ -252,8 +285,7 @@ mod tests { extracted_answers.body, None, extracted_answers.is_breaking_change, - ) - .unwrap(); + )?; assert_eq!( message, @@ -272,7 +304,7 @@ mod tests { breaking_change_footer: Some("this is a breaking change".into()), }; - let extracted_answers = get_extracted_answers(answers, &config).unwrap(); + let extracted_answers = get_extracted_answers(answers, &config)?; assert_eq!( extracted_answers, @@ -284,5 +316,7 @@ mod tests { is_breaking_change: false, } ); + + Ok(()) } } diff --git a/src/lib/config.rs b/src/lib/config.rs index 9456f28..32641cb 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -1,9 +1,10 @@ -use anyhow::{Context, Result}; +use anyhow::Result; +use config::FileFormat; use dirs::config_dir; use indexmap::IndexMap; use serde::Deserialize; +use std::env::current_dir; use std::path::PathBuf; -use std::{env::current_dir, fs::read_to_string, path::Path}; #[derive(Debug, Clone)] pub struct Config { @@ -23,20 +24,20 @@ pub struct CommitType { pub name: String, } -#[derive(Clone, Deserialize)] +#[derive(Clone, Debug, Deserialize)] struct ConfigTOML { - pub autocomplete: Option, - pub breaking_changes: Option, + pub autocomplete: bool, + pub breaking_changes: bool, #[serde(default)] commit_types: Vec, - pub emoji: Option, - pub issues: Option, - pub sign: Option, + pub emoji: bool, + pub issues: bool, + pub sign: bool, } #[derive(Default)] pub struct ConfigArgs { - pub path: Option, + pub path: Option, pub autocomplete: Option, pub breaking_changes: Option, pub emoji: Option, @@ -60,51 +61,42 @@ impl Config { _current_dir, } = args.unwrap_or_default(); + let mut settings = config::Config::builder(); + let workdir = _current_dir.unwrap_or(current_dir()?); // Get the default config let default_str = include_str!("../../meta/config/default.toml"); - let default_config: ConfigTOML = - toml::from_str(default_str).context("could not parse config file")?; - - let mut parsed: Option = None; + settings = settings.add_source(config::File::from_str(default_str, FileFormat::Toml)); // Try to get config from users config directory let config_dir_path = _user_config_path .unwrap_or(config_dir().unwrap()) .join("koji/config.toml"); - if Path::new(&config_dir_path).exists() { - let contents = read_to_string(config_dir_path).context("could not read config")?; - parsed = Some(toml::from_str(&contents).context("could not parse config")?); - }; + settings = settings.add_source(config::File::from(config_dir_path).required(false)); // Try to get config from working directory let working_dir_path = workdir.join(".koji.toml"); - if Path::new(&working_dir_path).exists() { - let contents = read_to_string(working_dir_path).context("could not read config")?; - parsed = Some(toml::from_str(&contents).context("could not parse config")?); - }; + settings = settings.add_source(config::File::from(working_dir_path).required(false)); // Try to get config from passed directory if let Some(path) = path { - if Path::new(&path).exists() { - let contents = read_to_string(&path).context("could not read config")?; - parsed = Some(toml::from_str(&contents).context("could not parse config")?); - } + settings = settings.add_source(config::File::from(path).required(false)); } - // If the users' config doesn't have any commit types, // merge in the defaults - let config = match parsed { - Some(mut config) => { - if config.commit_types.is_empty() { - config.commit_types = default_config.commit_types; - } - - config - } - None => default_config, - }; + // let config = match parsed { + // Some(mut config) => { + // if config.commit_types.is_empty() { + // config.commit_types = default_config.commit_types; + // } + // + // config + // } + // None => default_config, + // }; + + let config: ConfigTOML = settings.build()?.try_deserialize()?; // Gather up commit types let mut commit_types = IndexMap::new(); @@ -113,12 +105,12 @@ impl Config { } Ok(Config { - autocomplete: autocomplete.unwrap_or(config.autocomplete.unwrap_or(false)), - breaking_changes: breaking_changes.unwrap_or(config.breaking_changes.unwrap_or(true)), + autocomplete: autocomplete.unwrap_or(config.autocomplete), + breaking_changes: breaking_changes.unwrap_or(config.breaking_changes), commit_types, - emoji: emoji.unwrap_or(config.emoji.unwrap_or(false)), - issues: issues.unwrap_or(config.issues.unwrap_or(true)), - sign: sign.unwrap_or(config.sign.unwrap_or(false)), + emoji: emoji.unwrap_or(config.emoji), + issues: issues.unwrap_or(config.issues), + sign: sign.unwrap_or(config.sign), workdir, }) } @@ -127,41 +119,36 @@ impl Config { #[cfg(test)] mod tests { use super::*; + use std::error::Error; #[test] - fn test_from_path() { - let tempdir = tempfile::tempdir().unwrap(); + fn test_from_path() -> Result<(), Box> { + let tempdir = tempfile::tempdir()?; std::fs::write( tempdir.path().join("my-koji.toml"), "[[commit_types]]\nname=\"1234\"\ndescription=\"test\"", - ) - .unwrap(); + )?; let config = Config::new(Some(ConfigArgs { - path: Some( - tempdir - .path() - .join("my-koji.toml") - .to_string_lossy() - .to_string(), - ), + path: Some(tempdir.path().join("my-koji.toml")), ..ConfigArgs::default() })); assert!(config.is_ok()); - assert!(config.unwrap().commit_types.get("1234").is_some()); + assert!(config?.commit_types.get("1234").is_some()); + + tempdir.close()?; - tempdir.close().unwrap(); + Ok(()) } #[test] - fn test_local_config() { - let tempdir = tempfile::tempdir().unwrap(); + fn test_local_config() -> Result<(), Box> { + let tempdir = tempfile::tempdir()?; std::fs::write( tempdir.path().join(".koji.toml"), "[[commit_types]]\nname=\"123\"\ndescription=\"test\"", - ) - .unwrap(); + )?; let config = Config::new(Some(ConfigArgs { _current_dir: Some(tempdir.path().to_path_buf()), @@ -169,21 +156,22 @@ mod tests { })); assert!(config.is_ok()); - assert!(config.unwrap().commit_types.get("123").is_some()); + assert!(config?.commit_types.get("123").is_some()); - tempdir.close().unwrap(); + tempdir.close()?; + + Ok(()) } #[test] - fn test_user_config_config() { - let tempdir_current = tempfile::tempdir().unwrap(); - let tempdir_config = tempfile::tempdir().unwrap(); - std::fs::create_dir(tempdir_config.path().join("koji")).unwrap(); + fn test_user_config_config() -> Result<(), Box> { + let tempdir_current = tempfile::tempdir()?; + let tempdir_config = tempfile::tempdir()?; + std::fs::create_dir(tempdir_config.path().join("koji"))?; std::fs::write( tempdir_config.path().join("koji").join("config.toml"), "[[commit_types]]\nname=\"12345\"\ndescription=\"test\"", - ) - .unwrap(); + )?; let config = Config::new(Some(ConfigArgs { _user_config_path: Some(tempdir_config.path().to_path_buf()), @@ -192,15 +180,55 @@ mod tests { })); assert!(config.is_ok()); - assert!(config.unwrap().commit_types.get("12345").is_some()); + assert!(config?.commit_types.get("12345").is_some()); + + tempdir_current.close()?; + tempdir_config.close()?; - tempdir_current.close().unwrap(); - tempdir_config.close().unwrap(); + Ok(()) } #[test] - fn test_non_custom_use_defaults() { - let tempdir = tempfile::tempdir().unwrap(); + fn test_all_config_sources() -> Result<(), Box> { + let tempdir_config = tempfile::tempdir()?; + std::fs::create_dir(tempdir_config.path().join("koji"))?; + std::fs::write( + tempdir_config.path().join("koji").join("config.toml"), + "[[commit_types]]\nname=\"12345\"\ndescription=\"test\"", + )?; + let tempdir_current = tempfile::tempdir()?; + std::fs::write(tempdir_current.path().join(".koji.toml"), "emoji=\"true\"")?; + let tempdir_path = tempfile::tempdir()?; + std::fs::write(tempdir_path.path().join("custom.toml"), "autocomplete=true")?; + + let config = Config::new(Some(ConfigArgs { + _user_config_path: Some(tempdir_config.path().to_path_buf()), + _current_dir: Some(tempdir_current.path().to_path_buf()), + path: Some(tempdir_path.path().join("custom.toml").to_path_buf()), + emoji: Some(false), + ..Default::default() + }))?; + + // from user config dir + assert!(config.commit_types.get("12345").is_some()); + assert!(config.commit_types.len() == 1); + // set by current dir config and directly, which overwrites the former + assert!(!config.emoji); + // set by passed config path + assert!(config.autocomplete); + // a default + assert!(!config.sign); + + tempdir_current.close()?; + tempdir_config.close()?; + tempdir_path.close()?; + + Ok(()) + } + + #[test] + fn test_non_custom_use_defaults() -> Result<(), Box> { + let tempdir = tempfile::tempdir()?; let config = Config::new(Some(ConfigArgs { _current_dir: Some(tempdir.path().to_path_buf()), @@ -209,40 +237,44 @@ mod tests { })); assert!(config.is_ok()); - assert!(!config.unwrap().commit_types.len() > 0); + assert!(!config?.commit_types.len() > 0); + + tempdir.close()?; - tempdir.close().unwrap(); + Ok(()) } #[test] - fn test_breaking_changes() { - let config = Config::new(None).unwrap(); + fn test_breaking_changes() -> Result<(), Box> { + let config = Config::new(None)?; assert!(config.breaking_changes); let config = Config::new(Some(ConfigArgs { breaking_changes: Some(false), ..Default::default() - })) - .unwrap(); + }))?; assert!(!config.breaking_changes); + + Ok(()) } #[test] - fn test_issues() { - let config = Config::new(None).unwrap(); + fn test_issues() -> Result<(), Box> { + let config = Config::new(None)?; assert!(config.issues); let config = Config::new(Some(ConfigArgs { issues: Some(false), ..Default::default() - })) - .unwrap(); + }))?; assert!(!config.issues); + + Ok(()) } #[test] - fn test_commit_types() { - let config = Config::new(None).unwrap(); + fn test_commit_types() -> Result<(), Box> { + let config = Config::new(None)?; let commit_types = config.commit_types; assert_eq!( @@ -252,6 +284,8 @@ mod tests { emoji: Some("✨".into()), description: "A new feature".into() }) - ) + ); + + Ok(()) } } diff --git a/tests/integration.rs b/tests/integration.rs index 0f0bb55..0643ee1 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -7,6 +7,13 @@ use rexpect::{ use std::{error::Error, fs, path::PathBuf, process::Command}; use tempfile::TempDir; +fn setup_config_home() -> Result> { + let temp_dir = tempfile::tempdir()?; + std::env::set_var("XDG_CONFIG_HOME", temp_dir.path()); + + Ok(temp_dir) +} + fn setup_test_dir() -> Result<(PathBuf, TempDir, Repository), Box> { let bin_path = assert_cmd::cargo::cargo_bin("koji"); let temp_dir = tempfile::tempdir()?; @@ -82,6 +89,7 @@ impl ExpectPromps for PtySession { #[cfg(not(target_os = "windows"))] fn test_everything_correct() -> Result<(), Box> { let (bin_path, temp_dir, repo) = setup_test_dir()?; + let config_temp_dir = setup_config_home()?; fs::write(temp_dir.path().join("README.md"), "foo")?; repo.index()? @@ -147,6 +155,7 @@ fn test_everything_correct() -> Result<(), Box> { ); temp_dir.close()?; + config_temp_dir.close()?; Ok(()) } @@ -154,6 +163,7 @@ fn test_everything_correct() -> Result<(), Box> { #[cfg(not(target_os = "windows"))] fn test_hook_correct() -> Result<(), Box> { let (bin_path, temp_dir, repo) = setup_test_dir()?; + let config_temp_dir = setup_config_home()?; fs::write(temp_dir.path().join("config.json"), "abc")?; repo.index()? @@ -205,6 +215,7 @@ fn test_hook_correct() -> Result<(), Box> { ); temp_dir.close()?; + config_temp_dir.close()?; Ok(()) } @@ -212,6 +223,7 @@ fn test_hook_correct() -> Result<(), Box> { #[cfg(not(target_os = "windows"))] fn test_empty_breaking_text_correct() -> Result<(), Box> { let (bin_path, temp_dir, repo) = setup_test_dir()?; + let config_temp_dir = setup_config_home()?; fs::write(temp_dir.path().join("Cargo.toml"), "bar")?; repo.index()? @@ -262,6 +274,7 @@ fn test_empty_breaking_text_correct() -> Result<(), Box> { assert_eq!(commit.body(), Some("Renamed the project to a new name.")); temp_dir.close()?; + config_temp_dir.close()?; Ok(()) }