From e362dac244aed35359184401420cec39aafc2bd7 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 7 May 2019 21:06:24 -0500 Subject: [PATCH 1/7] feat(config): Layered config support Now we'll load from all config sources, merging the result. Fixes #93 --- src/config.rs | 47 +++++++++++++++++++++++------------------------ src/main.rs | 7 +++---- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/config.rs b/src/config.rs index d5ae7dbb4..2dea1e162 100644 --- a/src/config.rs +++ b/src/config.rs @@ -446,41 +446,40 @@ pub fn resolve_custom_config(file_path: &Path) -> Result, FatalEr /// Try to resolve configuration source. /// -/// This tries the following sources in order, short-circuiting on the first one found: -/// 1. $(pwd)/release.toml +/// This tries the following sources in order, merging the results: +/// 1. $HOME/.release.toml /// 2. $(pwd)/Cargo.toml `package.metadata.release` (with deprecation warning) -/// 3. $HOME/.release.toml +/// 3. $(pwd)/release.toml /// -pub fn resolve_config(manifest_path: &Path) -> Result, FatalError> { - // Project release file. - let default_config = manifest_path - .parent() - .unwrap_or_else(|| Path::new(".")) - .join("release.toml"); - let current_dir_config = get_config_from_file(&default_config)?; - if let Some(cfg) = current_dir_config { - let mut config = Config::default(); - config.update(&cfg); - return Ok(Some(config)); +pub fn resolve_config(manifest_path: &Path) -> Result { + let mut config = Config::default(); + + // User-local configuration from home directory. + let home_dir = dirs::home_dir(); + if let Some(mut home) = home_dir { + home.push(".release.toml"); + if let Some(cfg) = get_config_from_file(&home)? { + config.update(&cfg); + } }; // Crate manifest. let current_dir_config = get_config_from_manifest(manifest_path)?; if let Some(cfg) = current_dir_config { - let mut config = Config::default(); config.update(&cfg); - return Ok(Some(config)); }; - // User-local configuration from home directory. - let home_dir = dirs::home_dir(); - if let Some(mut home) = home_dir { - home.push(".release.toml"); - return resolve_custom_config(home.as_path()); + // Project release file. + let default_config = manifest_path + .parent() + .unwrap_or_else(|| Path::new(".")) + .join("release.toml"); + let current_dir_config = get_config_from_file(&default_config)?; + if let Some(cfg) = current_dir_config { + config.update(&cfg); }; - // No project-wide configuration. - Ok(None) + Ok(config) } #[cfg(test)] @@ -492,7 +491,7 @@ mod test { #[test] fn doesnt_panic() { - let release_config = resolve_config(Path::new("Cargo.toml")).unwrap().unwrap(); + let release_config = resolve_config(Path::new("Cargo.toml")).unwrap(); assert!(release_config.sign_commit()); } } diff --git a/src/main.rs b/src/main.rs index 99194e1c9..3e00d3202 100755 --- a/src/main.rs +++ b/src/main.rs @@ -81,11 +81,10 @@ fn execute(args: &ReleaseOpt) -> Result { let release_config = { let mut release_config = if let Some(custom_config_path) = custom_config_path_option { // when calling with -c option - config::resolve_custom_config(Path::new(custom_config_path))? + config::resolve_custom_config(Path::new(custom_config_path))?.unwrap_or_default() } else { config::resolve_config(&manifest_path)? - } - .unwrap_or_default(); + }; release_config.update(args); release_config }; @@ -407,7 +406,7 @@ struct ReleaseOpt { level: version::BumpLevel, #[structopt(short = "c", long = "config")] - /// Custom config file + /// Custom config file (isolated) config: Option, #[structopt(short = "m")] From ed29cc4165bc4488ef1f4968989e0f87cf58ad46 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 7 May 2019 22:01:35 -0500 Subject: [PATCH 2/7] refactor(cmd): Use native types --- src/cmd.rs | 9 ++++----- src/main.rs | 7 ++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cmd.rs b/src/cmd.rs index 810bb6821..5c11b3431 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -1,4 +1,5 @@ use std::collections::BTreeMap; +use std::ffi::OsStr; use std::path::Path; use std::process::Command; @@ -7,7 +8,7 @@ use crate::error::FatalError; fn do_call( command: Vec<&str>, path: Option<&Path>, - envs: Option>, + envs: Option>, dry_run: bool, ) -> Result { if dry_run { @@ -30,9 +31,7 @@ fn do_call( } if let Some(e) = envs { - for (key, val) in e.iter() { - cmd.env(key, val); - } + cmd.envs(e.iter()); } for arg in iter { @@ -57,7 +56,7 @@ pub fn call_on_path(command: Vec<&str>, path: &Path, dry_run: bool) -> Result, - envs: BTreeMap<&str, &str>, + envs: BTreeMap<&OsStr, &OsStr>, path: &Path, dry_run: bool, ) -> Result { diff --git a/src/main.rs b/src/main.rs index 3e00d3202..918e55008 100755 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use structopt; #[cfg(test)] extern crate assert_fs; +use std::ffi::OsStr; use std::path::Path; use std::process::exit; @@ -269,9 +270,9 @@ fn execute(args: &ReleaseOpt) -> Result { if let Some(pre_rel_hook) = pre_release_hook { shell::log_info(&format!("Calling pre-release hook: {:?}", pre_rel_hook)); let envs = btreemap! { - "PREV_VERSION" => prev_version_string.as_ref(), - "NEW_VERSION" => new_version_string.as_ref(), - "DRY_RUN" => if dry_run { "true" } else { "false" } + OsStr::new("PREV_VERSION") => prev_version_string.as_ref(), + OsStr::new("NEW_VERSION") => new_version_string.as_ref(), + OsStr::new("DRY_RUN") => OsStr::new(if dry_run { "true" } else { "false" }), }; // we use dry_run environmental variable to run the script // so here we set dry_run=false and always execute the command. From cc6385bee5f09e3678d882d5fe8a9bf2c1d79644 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 7 May 2019 22:07:21 -0500 Subject: [PATCH 3/7] feat(hook): Expose crate paths --- src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.rs b/src/main.rs index 918e55008..bf6fac5e4 100755 --- a/src/main.rs +++ b/src/main.rs @@ -273,6 +273,8 @@ fn execute(args: &ReleaseOpt) -> Result { OsStr::new("PREV_VERSION") => prev_version_string.as_ref(), OsStr::new("NEW_VERSION") => new_version_string.as_ref(), OsStr::new("DRY_RUN") => OsStr::new(if dry_run { "true" } else { "false" }), + OsStr::new("WORKSPACE_ROOT") => ws_meta.workspace_root.as_os_str(), + OsStr::new("CRATE_ROOT") => manifest_path.parent().unwrap_or_else(|| Path::new(".")).as_os_str(), }; // we use dry_run environmental variable to run the script // so here we set dry_run=false and always execute the command. From 1d2277772adc0dc04358a1e68d57ca013f740eab Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 7 May 2019 22:23:38 -0500 Subject: [PATCH 4/7] feat(config): Support workspace-wide config Not supporting `workspace_root/Cargo.toml` since a comment states it is deprecated. --- src/config.rs | 24 ++++++++++++++++-------- src/main.rs | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/config.rs b/src/config.rs index 2dea1e162..3b15731a3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -448,10 +448,11 @@ pub fn resolve_custom_config(file_path: &Path) -> Result, FatalEr /// /// This tries the following sources in order, merging the results: /// 1. $HOME/.release.toml -/// 2. $(pwd)/Cargo.toml `package.metadata.release` (with deprecation warning) -/// 3. $(pwd)/release.toml +/// 2. $(workspace)/release.toml +/// 3. $(crate)/Cargo.toml `package.metadata.release` (with deprecation warning) +/// 4. $(crate)/release.toml /// -pub fn resolve_config(manifest_path: &Path) -> Result { +pub fn resolve_config(workspace_root: &Path, manifest_path: &Path) -> Result { let mut config = Config::default(); // User-local configuration from home directory. @@ -463,6 +464,16 @@ pub fn resolve_config(manifest_path: &Path) -> Result { } }; + let crate_root = manifest_path.parent().unwrap_or_else(|| Path::new(".")); + + if crate_root != workspace_root { + let default_config = workspace_root.join("release.toml"); + let current_dir_config = get_config_from_file(&default_config)?; + if let Some(cfg) = current_dir_config { + config.update(&cfg); + }; + } + // Crate manifest. let current_dir_config = get_config_from_manifest(manifest_path)?; if let Some(cfg) = current_dir_config { @@ -470,10 +481,7 @@ pub fn resolve_config(manifest_path: &Path) -> Result { }; // Project release file. - let default_config = manifest_path - .parent() - .unwrap_or_else(|| Path::new(".")) - .join("release.toml"); + let default_config = crate_root.join("release.toml"); let current_dir_config = get_config_from_file(&default_config)?; if let Some(cfg) = current_dir_config { config.update(&cfg); @@ -491,7 +499,7 @@ mod test { #[test] fn doesnt_panic() { - let release_config = resolve_config(Path::new("Cargo.toml")).unwrap(); + let release_config = resolve_config(Path::new("."), Path::new("Cargo.toml")).unwrap(); assert!(release_config.sign_commit()); } } diff --git a/src/main.rs b/src/main.rs index bf6fac5e4..a6702ea80 100755 --- a/src/main.rs +++ b/src/main.rs @@ -84,7 +84,7 @@ fn execute(args: &ReleaseOpt) -> Result { // when calling with -c option config::resolve_custom_config(Path::new(custom_config_path))?.unwrap_or_default() } else { - config::resolve_config(&manifest_path)? + config::resolve_config(&ws_meta.workspace_root, &manifest_path)? }; release_config.update(args); release_config From b19dfed47de5dae695a8283a92ea186af3a2507c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 8 May 2019 07:10:35 -0500 Subject: [PATCH 5/7] feat(hook): Pass crate name along to ease conditionals --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index a6702ea80..1a6c7eb2b 100755 --- a/src/main.rs +++ b/src/main.rs @@ -273,6 +273,7 @@ fn execute(args: &ReleaseOpt) -> Result { OsStr::new("PREV_VERSION") => prev_version_string.as_ref(), OsStr::new("NEW_VERSION") => new_version_string.as_ref(), OsStr::new("DRY_RUN") => OsStr::new(if dry_run { "true" } else { "false" }), + OsStr::new("CRATE_NAME") => OsStr::new(crate_name), OsStr::new("WORKSPACE_ROOT") => ws_meta.workspace_root.as_os_str(), OsStr::new("CRATE_ROOT") => manifest_path.parent().unwrap_or_else(|| Path::new(".")).as_os_str(), }; From 9e7f4ba5a8579211f0c29d7b6cb3648cd8b08098 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 8 May 2019 07:15:56 -0500 Subject: [PATCH 6/7] feat(config): Layer custom config --- src/main.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1a6c7eb2b..e6cc6f7ad 100755 --- a/src/main.rs +++ b/src/main.rs @@ -80,11 +80,14 @@ fn execute(args: &ReleaseOpt) -> Result { let cargo_file = cargo::parse_cargo_config(&manifest_path)?; let custom_config_path_option = args.config.as_ref(); let release_config = { - let mut release_config = if let Some(custom_config_path) = custom_config_path_option { + let mut release_config = config::Config::default(); + let cfg = config::resolve_config(&ws_meta.workspace_root, &manifest_path)?; + release_config.update(&cfg); + if let Some(custom_config_path) = custom_config_path_option { // when calling with -c option - config::resolve_custom_config(Path::new(custom_config_path))?.unwrap_or_default() - } else { - config::resolve_config(&ws_meta.workspace_root, &manifest_path)? + let cfg = + config::resolve_custom_config(Path::new(custom_config_path))?.unwrap_or_default(); + release_config.update(&cfg); }; release_config.update(args); release_config @@ -410,7 +413,7 @@ struct ReleaseOpt { level: version::BumpLevel, #[structopt(short = "c", long = "config")] - /// Custom config file (isolated) + /// Custom config file config: Option, #[structopt(short = "m")] From 8716693d76d5c757970bef15952c51e71ec986a6 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 8 May 2019 07:26:55 -0500 Subject: [PATCH 7/7] feat(config): Add isolated config support --- src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index e6cc6f7ad..a21f3490f 100755 --- a/src/main.rs +++ b/src/main.rs @@ -81,8 +81,10 @@ fn execute(args: &ReleaseOpt) -> Result { let custom_config_path_option = args.config.as_ref(); let release_config = { let mut release_config = config::Config::default(); - let cfg = config::resolve_config(&ws_meta.workspace_root, &manifest_path)?; - release_config.update(&cfg); + if !args.isolated { + let cfg = config::resolve_config(&ws_meta.workspace_root, &manifest_path)?; + release_config.update(&cfg); + } if let Some(custom_config_path) = custom_config_path_option { // when calling with -c option let cfg = @@ -416,6 +418,10 @@ struct ReleaseOpt { /// Custom config file config: Option, + #[structopt(long = "isolated")] + /// Ignore implicit configuration files. + isolated: bool, + #[structopt(short = "m")] /// Semver metadata metadata: Option,