From f0caed3cd39b2ab1456a2799ed14b9cb4b9b1aa7 Mon Sep 17 00:00:00 2001 From: Fauzaan Date: Tue, 28 Mar 2023 09:28:29 +0000 Subject: [PATCH 01/43] feat(secret-edit): added a command to edit the secret via cli --- Cargo.lock | 7 + Cargo.toml | 1 + src/commands/dev/config_secrets_edit.rs | 162 ++++++++++++++++++++++++ src/commands/dev/mod.rs | 9 ++ src/error.rs | 4 + src/utils/custom_dialoguer_theme.rs | 100 +++++++++++++++ src/utils/mod.rs | 1 + 7 files changed, 284 insertions(+) create mode 100644 src/commands/dev/config_secrets_edit.rs create mode 100644 src/utils/custom_dialoguer_theme.rs diff --git a/Cargo.lock b/Cargo.lock index 316a6ff99..f74f166d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1003,6 +1003,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + [[package]] name = "difflib" version = "0.4.0" @@ -4106,6 +4112,7 @@ dependencies = [ "criterion", "ctrlc", "dialoguer", + "difference", "dirs", "edit", "elixir_linter", diff --git a/Cargo.toml b/Cargo.toml index 561e6823c..53fc29c5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ miette = { version = "5.5.0", features = ["fancy"] } ignore = "0.4.20" rayon = "1.7.0" tree-sitter = "0.20.9" +difference = "2.0.0" [dev-dependencies] httpmock = "0.6.7" diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs new file mode 100644 index 000000000..5ad6fdf6a --- /dev/null +++ b/src/commands/dev/config_secrets_edit.rs @@ -0,0 +1,162 @@ +use crate::{ + error::CliError, services::vault::Vault, utils::custom_dialoguer_theme::CustomDialoguerTheme, +}; +use dialoguer::{ + console::{style, Style}, + MultiSelect, +}; +use difference::{Changeset, Difference}; +use edit::Builder; +use serde_json; +use std::collections::HashMap; + +pub async fn config_secrets_edit(path: &str) -> Result { + let vault = Vault::new(); + let api_token = vault.get_token_or_login().await?; + + let secrets = vault.get_secrets(&api_token, &path).await?.data; + + println!("{:?}", secrets); + // Open editor with secrets: + let edited_secrets_str = edit::edit_with_builder( + serde_json::to_string_pretty::>(&secrets)?, + Builder::new().prefix("config_secrets_edit").suffix(".json"), + )?; + + let edited_secrets: HashMap = serde_json::from_str(&edited_secrets_str)?; + let secrets_checklist_items = generate_checklist_items(&secrets, &edited_secrets); + + // Build the checklist: + let themes = CustomDialoguerTheme::default(); + let selected_secrets = MultiSelect::with_theme(&themes) + .with_prompt(format!( + "{}", + style("Choose which changes to update").bold() + )) + .items_checked( + &secrets_checklist_items + .iter() + .map(|(value, _)| (value.to_string(), true)) + .collect::>(), + ) + .report(false) + .interact()?; + + let mut secrets_to_update: HashMap = secrets.clone(); + + for selected_secrets in selected_secrets { + let key = &secrets_checklist_items[selected_secrets].1; + + // Update the secret with updated value: + if let Some(value) = edited_secrets.get(&key.to_string()) { + secrets_to_update.insert(key.to_string(), value.to_string()); + } + + // Delete the secret if it's empty: + if edited_secrets.get(&key.to_string()).is_none() { + secrets_to_update.remove(&key.to_string()); + } + } + + // Update into as a ref: + let secrets_to_update_refs: HashMap<&str, &str> = secrets_to_update + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect(); + + println!("{:?}", secrets_to_update_refs); + vault + .update_secret(&api_token, path, &secrets_to_update_refs) + .await?; + + Ok(true) +} + +fn generate_checklist_items( + secrets: &HashMap, + edited_secrets: &HashMap, +) -> Vec<(String, String)> { + let max_key_len = edited_secrets + .values() + .map(|key| key.len()) + .max() + .unwrap_or(0); + let max_old_value_len = secrets.values().map(|key| key.len()).max().unwrap_or(0); + + let green = Style::new().for_stderr().green(); + let red = Style::new().for_stderr().red(); + + let mut items: Vec<(String, String)> = edited_secrets + .iter() + .map(|(key, new_value)| { + let mut key_with_style: String = key.clone(); + let mut old_value_with_style: String = new_value.clone(); + let mut new_value_with_style: String = new_value.clone(); + + // Insert Key: + if !secrets.contains_key(key) { + key_with_style = format!("{}{}", green.apply_to("+"), green.apply_to(key)); + } else { + // Updated values: + let old_value = secrets.get(key).unwrap_or(&String::from("")).to_string(); + let changeset = Changeset::new(&old_value, new_value, ""); + + let changes: Vec = changeset + .diffs + .iter() + .map(|diff| match diff { + Difference::Same(s) => s.to_string(), + Difference::Add(s) => format!("{}", green.apply_to(s)), + Difference::Rem(s) => format!("{}", red.apply_to(s)), + }) + .collect(); + + new_value_with_style = changes.join(""); + old_value_with_style = old_value; + } + + // Return the item: + ( + format!( + "{:>(); + + for key in deleted_keys { + let item = ( + format!( + "{: handle_config_lint(path), DevSubcommand::ConfigSynthesizer { path } => handle_config_synthesizer(path).await, + DevSubcommand::ConfigSecretEdit { path } => config_secrets_edit(path).await, } } } diff --git a/src/error.rs b/src/error.rs index b42c3ac03..f619282f3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,6 +23,10 @@ pub enum CliError { DeploymentError(#[from] DeploymentError), #[error(transparent)] VaultError(#[from] VaultError), + #[error(transparent)] + SerdeJsonError(#[from] serde_json::Error), + #[error("{message}")] + DuplicateKeyError { message: String }, } #[derive(Debug, ThisError)] diff --git a/src/utils/custom_dialoguer_theme.rs b/src/utils/custom_dialoguer_theme.rs new file mode 100644 index 000000000..7a9b8cad2 --- /dev/null +++ b/src/utils/custom_dialoguer_theme.rs @@ -0,0 +1,100 @@ +use core::fmt; + +use dialoguer::{ + console::{style, Style, StyledObject}, + theme::Theme, +}; + +impl Default for CustomDialoguerTheme { + fn default() -> CustomDialoguerTheme { + CustomDialoguerTheme { + defaults_style: Style::new().for_stderr().cyan(), + prompt_style: Style::new().for_stderr().bold(), + prompt_prefix: style("?".to_string()).for_stderr().yellow(), + prompt_suffix: style("› Space to deselect. Enter to execute".to_string()) + .for_stderr() + .black() + .bright(), + active_item_style: Style::new().for_stderr().white(), + inactive_item_style: Style::new().for_stderr(), + active_item_prefix: style("❯".to_string()).for_stderr(), + inactive_item_prefix: style(" ".to_string()).for_stderr(), + checked_item_prefix: style("◉".to_string()).for_stderr().green(), + unchecked_item_prefix: style("◯".to_string()).for_stderr().white(), + } + } +} + +impl Theme for CustomDialoguerTheme { + /// Formats a prompt. + fn format_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result { + if !prompt.is_empty() { + write!( + f, + "{} {} ", + &self.prompt_prefix, + self.prompt_style.apply_to(prompt) + )?; + } + + write!(f, "{}", &self.prompt_suffix) + } + + /// Formats a multi select prompt item. + fn format_multi_select_prompt_item( + &self, + f: &mut dyn fmt::Write, + text: &str, + checked: bool, + active: bool, + ) -> fmt::Result { + let details = match (checked, active) { + (true, true) => ( + &self.active_item_prefix, + &self.checked_item_prefix, + self.active_item_style.apply_to(text), + ), + (true, false) => ( + &self.inactive_item_prefix, + &self.checked_item_prefix, + self.inactive_item_style.apply_to(text), + ), + (false, true) => ( + &self.active_item_prefix, + &self.unchecked_item_prefix, + self.active_item_style.apply_to(text), + ), + (false, false) => ( + &self.inactive_item_prefix, + &self.unchecked_item_prefix, + self.inactive_item_style.apply_to(text), + ), + }; + + write!(f, "{} {} {}", details.0, details.1, details.2) + } +} + +/// A colorful theme +pub struct CustomDialoguerTheme { + /// The style for default values + pub defaults_style: Style, + /// The style for prompt + pub prompt_style: Style, + /// Prompt prefix value and style + pub prompt_prefix: StyledObject, + /// Prompt suffix value and style + pub prompt_suffix: StyledObject, + /// The style for active items + pub active_item_style: Style, + /// The style for inactive items + pub inactive_item_style: Style, + /// Active item in select prefix value and style + pub active_item_prefix: StyledObject, + /// Inctive item in select prefix value and style + pub inactive_item_prefix: StyledObject, + /// Checked item in multi select prefix value and style + pub checked_item_prefix: StyledObject, + /// Unchecked item in multi select prefix value and style + pub unchecked_item_prefix: StyledObject, +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 441c53fe5..80db2a24b 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1 +1,2 @@ pub mod annotations; +pub mod custom_dialoguer_theme; From 7ed5b4c5e02a678cc2df6debd2518ff8237b55ef Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Tue, 28 Mar 2023 10:51:02 +0000 Subject: [PATCH 02/43] style: removed unnnesry returns --- src/commands/dev/config_secrets_edit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 5ad6fdf6a..cfc2569ce 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -14,7 +14,7 @@ pub async fn config_secrets_edit(path: &str) -> Result { let vault = Vault::new(); let api_token = vault.get_token_or_login().await?; - let secrets = vault.get_secrets(&api_token, &path).await?.data; + let secrets = vault.get_secrets(&api_token, path).await?.data; println!("{:?}", secrets); // Open editor with secrets: @@ -158,5 +158,5 @@ fn generate_checklist_items( items.push(item); } - return items; + items } From b0f4d69c4e720386dc7e1497cedbae78f7663ea9 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Tue, 28 Mar 2023 11:33:54 +0000 Subject: [PATCH 03/43] style: fix clippy issues --- src/commands/dev/config_secrets_edit.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index cfc2569ce..2093ca3b9 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -16,7 +16,6 @@ pub async fn config_secrets_edit(path: &str) -> Result { let secrets = vault.get_secrets(&api_token, path).await?.data; - println!("{:?}", secrets); // Open editor with secrets: let edited_secrets_str = edit::edit_with_builder( serde_json::to_string_pretty::>(&secrets)?, @@ -64,7 +63,6 @@ pub async fn config_secrets_edit(path: &str) -> Result { .map(|(k, v)| (k.as_str(), v.as_str())) .collect(); - println!("{:?}", secrets_to_update_refs); vault .update_secret(&api_token, path, &secrets_to_update_refs) .await?; @@ -120,7 +118,7 @@ fn generate_checklist_items( format!( "{: Date: Wed, 29 Mar 2023 05:40:45 +0000 Subject: [PATCH 04/43] test(secrets-edit-commands): generated snapshots for wukong cli --- src/utils/custom_dialoguer_theme.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/custom_dialoguer_theme.rs b/src/utils/custom_dialoguer_theme.rs index 7a9b8cad2..b19b4f0eb 100644 --- a/src/utils/custom_dialoguer_theme.rs +++ b/src/utils/custom_dialoguer_theme.rs @@ -75,7 +75,7 @@ impl Theme for CustomDialoguerTheme { } } -/// A colorful theme +/// A Custom theme pub struct CustomDialoguerTheme { /// The style for default values pub defaults_style: Style, From cb6b9466a504748d68a54c99c0b177db551bc593 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 29 Mar 2023 06:09:09 +0000 Subject: [PATCH 05/43] test(secrets-edit-commands): generated snapshots for wukong commands --- tests/snapshots/dev__wukong_dev_help.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/snapshots/dev__wukong_dev_help.snap b/tests/snapshots/dev__wukong_dev_help.snap index d01e082d2..008041f85 100644 --- a/tests/snapshots/dev__wukong_dev_help.snap +++ b/tests/snapshots/dev__wukong_dev_help.snap @@ -10,6 +10,8 @@ Commands: config-lint Linting the config and show possible warnings, as well as suggestion how to fix the config file config-synthesizer Synthesize the development config with secrets file from Bunker + config-secret-edit Linting the config and show possible warnings, as well as suggestion how + to fix the config file help Print this message or the help of the given subcommand(s) Options: From ec33e698c546198a188dea879bc4850b311a762b Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 29 Mar 2023 06:26:24 +0000 Subject: [PATCH 06/43] style: removed duplicate variables --- src/commands/dev/config_secrets_edit.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 2093ca3b9..8fd0eb2bb 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -12,9 +12,9 @@ use std::collections::HashMap; pub async fn config_secrets_edit(path: &str) -> Result { let vault = Vault::new(); - let api_token = vault.get_token_or_login().await?; - let secrets = vault.get_secrets(&api_token, path).await?.data; + let api_token = vault.get_token_or_login().await?; + let mut secrets = vault.get_secrets(&api_token, path).await?.data; // Open editor with secrets: let edited_secrets_str = edit::edit_with_builder( @@ -41,24 +41,22 @@ pub async fn config_secrets_edit(path: &str) -> Result { .report(false) .interact()?; - let mut secrets_to_update: HashMap = secrets.clone(); - for selected_secrets in selected_secrets { let key = &secrets_checklist_items[selected_secrets].1; // Update the secret with updated value: if let Some(value) = edited_secrets.get(&key.to_string()) { - secrets_to_update.insert(key.to_string(), value.to_string()); + secrets.insert(key.to_string(), value.to_string()); } // Delete the secret if it's empty: if edited_secrets.get(&key.to_string()).is_none() { - secrets_to_update.remove(&key.to_string()); + secrets.remove(&key.to_string()); } } // Update into as a ref: - let secrets_to_update_refs: HashMap<&str, &str> = secrets_to_update + let secrets_to_update_refs: HashMap<&str, &str> = secrets .iter() .map(|(k, v)| (k.as_str(), v.as_str())) .collect(); From 7926a1cc4735b8cc49bf682c850034118c42a888 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 29 Mar 2023 06:55:38 +0000 Subject: [PATCH 07/43] test(secrets-edit-commands): added test case for test_generate_checklist_items --- src/commands/dev/config_secrets_edit.rs | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 8fd0eb2bb..25206b253 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -156,3 +156,48 @@ fn generate_checklist_items( items } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_generate_checklist_items() { + let mut secrets = HashMap::new(); + secrets.insert("github_token".to_owned(), "not_changed".to_owned()); + secrets.insert("jenkins_password".to_owned(), "not_changed".to_owned()); + secrets.insert("jenkins_url".to_owned(), "to_remove".to_owned()); + + let mut edited_secrets = HashMap::new(); + edited_secrets.insert("github_token".to_owned(), "not_changed".to_owned()); + edited_secrets.insert("jenkins_password".to_owned(), "changed".to_owned()); + edited_secrets.insert("jenkins_username".to_owned(), "new".to_owned()); + + let mut expected_items = HashMap::new(); + + expected_items.insert( + "github_token \t not_changed → not_changed".to_owned(), + "github_token".to_owned(), + ); + expected_items.insert( + "\u{1b}[32m+\u{1b}[0m\u{1b}[32mjenkins_username\u{1b}[0m \t new → new" + .to_owned(), + "jenkins_username".to_owned(), + ); + expected_items.insert( + "jenkins_password \t not_changed → \u{1b}[31mnot_\u{1b}[0mchanged".to_owned(), + "jenkins_password".to_owned(), + ); + expected_items.insert( + "\u{1b}[31m-\u{1b}[0m\u{1b}[31mjenkins_url\u{1b}[0m \t to_remove → to_remove" + .to_owned(), + "jenkins_url".to_owned(), + ); + + let items = generate_checklist_items(&secrets, &edited_secrets); + + for item in items { + assert_eq!(expected_items.get(&item.0), Some(&item.1)); + } + } +} From edafcf1ab35e41da52308ce350f30f1d9cbff0ef Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 29 Mar 2023 07:18:44 +0000 Subject: [PATCH 08/43] test(test_generate_checklist_items): added test case to verify the length --- src/commands/dev/config_secrets_edit.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 25206b253..dad3ad7cc 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -174,7 +174,6 @@ mod test { edited_secrets.insert("jenkins_username".to_owned(), "new".to_owned()); let mut expected_items = HashMap::new(); - expected_items.insert( "github_token \t not_changed → not_changed".to_owned(), "github_token".to_owned(), @@ -196,7 +195,10 @@ mod test { let items = generate_checklist_items(&secrets, &edited_secrets); + assert_eq!(items.len(), expected_items.len()); + for item in items { + // Verify the key assert_eq!(expected_items.get(&item.0), Some(&item.1)); } } From 7636c3ec10f48c835fd49b50cb15adba35445c1b Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 29 Mar 2023 07:47:23 +0000 Subject: [PATCH 09/43] test(test_generate_checklist_items): changed the logic to check the content of the result as its formatted it cannot be compared directly --- src/commands/dev/config_secrets_edit.rs | 66 ++++++++++++++----------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index dad3ad7cc..1fcabe3fa 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -171,35 +171,43 @@ mod test { let mut edited_secrets = HashMap::new(); edited_secrets.insert("github_token".to_owned(), "not_changed".to_owned()); edited_secrets.insert("jenkins_password".to_owned(), "changed".to_owned()); - edited_secrets.insert("jenkins_username".to_owned(), "new".to_owned()); - - let mut expected_items = HashMap::new(); - expected_items.insert( - "github_token \t not_changed → not_changed".to_owned(), - "github_token".to_owned(), - ); - expected_items.insert( - "\u{1b}[32m+\u{1b}[0m\u{1b}[32mjenkins_username\u{1b}[0m \t new → new" - .to_owned(), - "jenkins_username".to_owned(), - ); - expected_items.insert( - "jenkins_password \t not_changed → \u{1b}[31mnot_\u{1b}[0mchanged".to_owned(), - "jenkins_password".to_owned(), - ); - expected_items.insert( - "\u{1b}[31m-\u{1b}[0m\u{1b}[31mjenkins_url\u{1b}[0m \t to_remove → to_remove" - .to_owned(), - "jenkins_url".to_owned(), - ); - - let items = generate_checklist_items(&secrets, &edited_secrets); - - assert_eq!(items.len(), expected_items.len()); - - for item in items { - // Verify the key - assert_eq!(expected_items.get(&item.0), Some(&item.1)); + edited_secrets.insert("jenkins_username".to_owned(), "new_value".to_owned()); + + // Call the function + let result = generate_checklist_items(&secrets, &edited_secrets); + + // Check the result + assert_eq!(result.len(), 4); // 2 edited keys + 1 deleted key + 1 without changes + + // We can't directly compare the result items because of the colored styles, + // but we can check for the presence of key indicators and substrings + let mut added_found = false; + let mut modified_found = false; + let mut removed_found = false; + for (item, _) in result { + if item.contains("jenkins_username") && item.contains("+") && item.contains("new_value") + { + added_found = true; + } else if item.contains("jenkins_password") + && item.contains("not_changed") + && item.contains("changed") + { + modified_found = true; + } else if item.contains("github_token") + && item.contains("not_changed") + && item.contains("not_changed") + { + modified_found = true; + } else if item.contains("jenkins_url") + && item.contains("-") + && item.contains("to_remove") + { + removed_found = true; + } } + + assert!(added_found, "The added secret was not found"); + assert!(modified_found, "The modified secrets were not found"); + assert!(removed_found, "The removed secret was not found"); } } From 72a1dcebed6601f1dd187ec35ba0a44034e21175 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 29 Mar 2023 07:49:58 +0000 Subject: [PATCH 10/43] style: removed the unused error codes --- src/error.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index f619282f3..63f2aced2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -25,8 +25,6 @@ pub enum CliError { VaultError(#[from] VaultError), #[error(transparent)] SerdeJsonError(#[from] serde_json::Error), - #[error("{message}")] - DuplicateKeyError { message: String }, } #[derive(Debug, ThisError)] From 86a270d85f547b5759d22da952141920081d180f Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 30 Mar 2023 04:29:42 +0000 Subject: [PATCH 11/43] style: updated function name and naming of some variables --- src/commands/dev/config_secrets_edit.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 1fcabe3fa..81486847b 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -10,7 +10,7 @@ use edit::Builder; use serde_json; use std::collections::HashMap; -pub async fn config_secrets_edit(path: &str) -> Result { +pub async fn handle_config_secrets_edit(path: &str) -> Result { let vault = Vault::new(); let api_token = vault.get_token_or_login().await?; @@ -206,8 +206,8 @@ mod test { } } - assert!(added_found, "The added secret was not found"); + assert!(added_found, "The added secrets was not found"); assert!(modified_found, "The modified secrets were not found"); - assert!(removed_found, "The removed secret was not found"); + assert!(removed_found, "The removed secrets was not found"); } } From 97455550345d8652ad6d3e3b5690167fe523a162 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Fri, 31 Mar 2023 05:35:49 +0000 Subject: [PATCH 12/43] WIP --- src/commands/dev/config_secrets_edit.rs | 190 +++++++++++------------- src/commands/dev/mod.rs | 12 +- src/error.rs | 9 +- 3 files changed, 97 insertions(+), 114 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 81486847b..d36b83767 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -7,67 +7,98 @@ use dialoguer::{ }; use difference::{Changeset, Difference}; use edit::Builder; +use ignore::{overrides::OverrideBuilder, WalkBuilder}; use serde_json; -use std::collections::HashMap; +use std::{collections::HashMap, io::ErrorKind}; +use std::{ + env::current_dir, + fs::File, + path::{Path, PathBuf}, +}; -pub async fn handle_config_secrets_edit(path: &str) -> Result { - let vault = Vault::new(); +pub async fn handle_config_secrets_edit(path: &Path) -> Result { + let path = path.try_exists().map(|value| match value { + true => match path.to_string_lossy() == "." { + true => current_dir(), + false => Ok(path.to_path_buf()), + }, + false => Err(std::io::Error::new( + ErrorKind::NotFound, + format!("path '{}' does not exist", path.to_string_lossy()), + )), + })??; - let api_token = vault.get_token_or_login().await?; - let mut secrets = vault.get_secrets(&api_token, path).await?.data; + let vault = Vault::new(); + let vault_token = vault.get_token_or_login().await?; + let available_files = get_dev_config_files(&path); + let secrets = vault.get_secrets(&vault_token, "wukong-test").await?; + println!("{:?}", secrets); // Open editor with secrets: - let edited_secrets_str = edit::edit_with_builder( - serde_json::to_string_pretty::>(&secrets)?, - Builder::new().prefix("config_secrets_edit").suffix(".json"), - )?; - - let edited_secrets: HashMap = serde_json::from_str(&edited_secrets_str)?; - let secrets_checklist_items = generate_checklist_items(&secrets, &edited_secrets); - - // Build the checklist: - let themes = CustomDialoguerTheme::default(); - let selected_secrets = MultiSelect::with_theme(&themes) - .with_prompt(format!( - "{}", - style("Choose which changes to update").bold() - )) - .items_checked( - &secrets_checklist_items - .iter() - .map(|(value, _)| (value.to_string(), true)) - .collect::>(), - ) - .report(false) - .interact()?; - - for selected_secrets in selected_secrets { - let key = &secrets_checklist_items[selected_secrets].1; - - // Update the secret with updated value: - if let Some(value) = edited_secrets.get(&key.to_string()) { - secrets.insert(key.to_string(), value.to_string()); - } - - // Delete the secret if it's empty: - if edited_secrets.get(&key.to_string()).is_none() { - secrets.remove(&key.to_string()); - } - } - - // Update into as a ref: - let secrets_to_update_refs: HashMap<&str, &str> = secrets - .iter() - .map(|(k, v)| (k.as_str(), v.as_str())) - .collect(); - - vault - .update_secret(&api_token, path, &secrets_to_update_refs) - .await?; + // let edited_secrets_str = edit::edit_with_builder( + // serde_json::to_string_pretty::>(&secrets)?, + // Builder::new().prefix("config_secrets_edit").suffix(".json"), + // )?; + + // let edited_secrets: HashMap = serde_json::from_str(&edited_secrets_str)?; + // let secrets_checklist_items = generate_checklist_items(&secrets, &edited_secrets); + + // // Build the checklist: + // let themes = CustomDialoguerTheme::default(); + // let selected_secrets = MultiSelect::with_theme(&themes) + // .with_prompt(format!( + // "{}", + // style("Choose which changes to update").bold() + // )) + // .items_checked( + // &secrets_checklist_items + // .iter() + // .map(|(value, _)| (value.to_string(), true)) + // .collect::>(), + // ) + // .report(false) + // .interact()?; + + // for selected_secrets in selected_secrets { + // let key = &secrets_checklist_items[selected_secrets].1; + + // // Update the secret with updated value: + // if let Some(value) = edited_secrets.get(&key.to_string()) { + // secrets.insert(key.to_string(), value.to_string()); + // } + + // // Delete the secret if it's empty: + // if edited_secrets.get(&key.to_string()).is_none() { + // secrets.remove(&key.to_string()); + // } + // } + + // // Update into as a ref: + // let secrets_to_update_refs: HashMap<&str, &str> = secrets + // .iter() + // .map(|(k, v)| (k.as_str(), v.as_str())) + // .collect(); + + // vault + // .update_secret(&api_token, path, &secrets_to_update_refs) + // .await?; Ok(true) } +fn get_dev_config_files(path: &Path) -> Vec { + let mut overrides = OverrideBuilder::new(path); + overrides.add("**/config/dev.exs").unwrap(); + + WalkBuilder::new(path) + .overrides(overrides.build().unwrap()) + .build() + .flatten() + .filter(|e| e.path().is_file()) + .map(|e| e.path().to_path_buf()) + .collect() +} + fn generate_checklist_items( secrets: &HashMap, edited_secrets: &HashMap, @@ -156,58 +187,3 @@ fn generate_checklist_items( items } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_generate_checklist_items() { - let mut secrets = HashMap::new(); - secrets.insert("github_token".to_owned(), "not_changed".to_owned()); - secrets.insert("jenkins_password".to_owned(), "not_changed".to_owned()); - secrets.insert("jenkins_url".to_owned(), "to_remove".to_owned()); - - let mut edited_secrets = HashMap::new(); - edited_secrets.insert("github_token".to_owned(), "not_changed".to_owned()); - edited_secrets.insert("jenkins_password".to_owned(), "changed".to_owned()); - edited_secrets.insert("jenkins_username".to_owned(), "new_value".to_owned()); - - // Call the function - let result = generate_checklist_items(&secrets, &edited_secrets); - - // Check the result - assert_eq!(result.len(), 4); // 2 edited keys + 1 deleted key + 1 without changes - - // We can't directly compare the result items because of the colored styles, - // but we can check for the presence of key indicators and substrings - let mut added_found = false; - let mut modified_found = false; - let mut removed_found = false; - for (item, _) in result { - if item.contains("jenkins_username") && item.contains("+") && item.contains("new_value") - { - added_found = true; - } else if item.contains("jenkins_password") - && item.contains("not_changed") - && item.contains("changed") - { - modified_found = true; - } else if item.contains("github_token") - && item.contains("not_changed") - && item.contains("not_changed") - { - modified_found = true; - } else if item.contains("jenkins_url") - && item.contains("-") - && item.contains("to_remove") - { - removed_found = true; - } - } - - assert!(added_found, "The added secrets was not found"); - assert!(modified_found, "The modified secrets were not found"); - assert!(removed_found, "The removed secrets was not found"); - } -} diff --git a/src/commands/dev/mod.rs b/src/commands/dev/mod.rs index 50fe68af4..e7b3db1b2 100644 --- a/src/commands/dev/mod.rs +++ b/src/commands/dev/mod.rs @@ -6,7 +6,7 @@ use crate::error::CliError; use clap::{Args, Subcommand}; use config_lint::handle_config_lint; use config_synthesizer::handle_config_synthesizer; -use config_secrets_edit::config_secrets_edit; +use config_secrets_edit::handle_config_secrets_edit; use std::path::PathBuf; #[derive(Debug, Args)] @@ -30,10 +30,10 @@ pub enum DevSubcommand { path: PathBuf, }, /// Linting the config and show possible warnings, as well as suggestion how to fix the config file. - ConfigSecretEdit { - /// The path to the vault - #[arg(required = true)] - path: String, + ConfigSecretsEdit { + /// The path to the project + #[arg(default_value = ".")] + path: PathBuf, }, } @@ -42,7 +42,7 @@ impl Dev { match &self.subcommand { DevSubcommand::ConfigLint { path } => handle_config_lint(path), DevSubcommand::ConfigSynthesizer { path } => handle_config_synthesizer(path).await, - DevSubcommand::ConfigSecretEdit { path } => config_secrets_edit(path).await, + DevSubcommand::ConfigSecretsEdit { path } => handle_config_secrets_edit(path).await, } } } diff --git a/src/error.rs b/src/error.rs index 63f2aced2..addbd4c48 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,7 +43,7 @@ pub enum VaultError { SecretNotFound, #[error("API token not found.")] ApiTokenNotFound, - #[error("Invalid API token.")] + #[error("Invalid token.")] ApiTokenInvalid, #[error("Permission denied.")] PermissionDenied, @@ -147,6 +147,13 @@ If none of the above steps work for you, please contact the following people on ), _ => None, }, + CliError::VaultError(error) => match error { + VaultError::ApiPermissionDenied => Some( + String::from("Please check your vault secret path. It could be invalid or you don't have permission to access it."), + ), + _ => None, + }, + _ => None, } } From 4942fe74138f4b22ec8f94330435d685e7dd5132 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Mon, 3 Apr 2023 08:31:06 +0000 Subject: [PATCH 13/43] refactor: changed the logic to fetch annotations on provided path --- src/commands/dev/config_secrets_edit.rs | 242 +++++++++--------------- 1 file changed, 92 insertions(+), 150 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index d36b83767..942ab95a5 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -1,10 +1,5 @@ -use crate::{ - error::CliError, services::vault::Vault, utils::custom_dialoguer_theme::CustomDialoguerTheme, -}; -use dialoguer::{ - console::{style, Style}, - MultiSelect, -}; +use crate::{error::CliError, services::vault::Vault, utils::annotations::read_vault_annotation}; +use dialoguer::{theme::ColorfulTheme, Select}; use difference::{Changeset, Difference}; use edit::Builder; use ignore::{overrides::OverrideBuilder, WalkBuilder}; @@ -12,11 +7,11 @@ use serde_json; use std::{collections::HashMap, io::ErrorKind}; use std::{ env::current_dir, - fs::File, path::{Path, PathBuf}, }; pub async fn handle_config_secrets_edit(path: &Path) -> Result { + println!("🔍 Searching for config files..."); let path = path.try_exists().map(|value| match value { true => match path.to_string_lossy() == "." { true => current_dir(), @@ -28,64 +23,100 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { )), })??; - let vault = Vault::new(); - let vault_token = vault.get_token_or_login().await?; let available_files = get_dev_config_files(&path); - let secrets = vault.get_secrets(&vault_token, "wukong-test").await?; - - println!("{:?}", secrets); - // Open editor with secrets: - // let edited_secrets_str = edit::edit_with_builder( - // serde_json::to_string_pretty::>(&secrets)?, - // Builder::new().prefix("config_secrets_edit").suffix(".json"), - // )?; - - // let edited_secrets: HashMap = serde_json::from_str(&edited_secrets_str)?; - // let secrets_checklist_items = generate_checklist_items(&secrets, &edited_secrets); - - // // Build the checklist: - // let themes = CustomDialoguerTheme::default(); - // let selected_secrets = MultiSelect::with_theme(&themes) - // .with_prompt(format!( - // "{}", - // style("Choose which changes to update").bold() - // )) - // .items_checked( - // &secrets_checklist_items - // .iter() - // .map(|(value, _)| (value.to_string(), true)) - // .collect::>(), - // ) - // .report(false) - // .interact()?; - - // for selected_secrets in selected_secrets { - // let key = &secrets_checklist_items[selected_secrets].1; - - // // Update the secret with updated value: - // if let Some(value) = edited_secrets.get(&key.to_string()) { - // secrets.insert(key.to_string(), value.to_string()); - // } - - // // Delete the secret if it's empty: - // if edited_secrets.get(&key.to_string()).is_none() { - // secrets.remove(&key.to_string()); - // } - // } - - // // Update into as a ref: - // let secrets_to_update_refs: HashMap<&str, &str> = secrets - // .iter() - // .map(|(k, v)| (k.as_str(), v.as_str())) - // .collect(); - - // vault - // .update_secret(&api_token, path, &secrets_to_update_refs) - // .await?; + let mut annotations_selections: Vec<(String, String)> = vec![]; + + for file in available_files { + let src = std::fs::read_to_string(file.clone())?; + let annotations = read_vault_annotation(&src); + + // Push this to annotations selections: + annotations_selections.extend( + annotations + .iter() + .filter(|annotation| { + annotation.key == "wukong.mindvalley.dev/config-secrets-location" + && annotation.source == "vault" + && annotation.engine == "secret" + }) + .map(|annotation| { + ( + annotation.secret_path.clone(), + format!( + "{} \t {}::{}/{}#{}", + remove_parent_directories(&file), + &annotation.source, + &annotation.engine, + &annotation.secret_path, + &annotation.secret_name + ), + ) + }) + .collect::>(), + ) + } + + if annotations_selections.is_empty() { + eprintln!("No config files found !"); + return Ok(false); + } + + println!( + "There are ({}) config files found !", + annotations_selections.len() + ); + + let selection = Select::with_theme(&ColorfulTheme::default()) + .items( + &annotations_selections + .iter() + .map(|(_, value)| value) + .collect::>(), + ) + .with_prompt("Which one do you like to make the changes ?") + .default(0) + .report(false) + .interact_opt() + .unwrap(); + + match selection { + Some(index) => { + let vault = Vault::new(); + let vault_token = vault.get_token_or_login().await?; + + // Get the secret path based on the selection: + let (secret_path, _) = &annotations_selections[index]; + let secrets = vault.get_secrets(&vault_token, &secret_path).await?.data; + + // Open editor with secrets: + let edited_secrets_str = edit::edit_with_builder( + serde_json::to_string_pretty::>(&secrets)?, + Builder::new().prefix("config_secrets_edit").suffix(".json"), + )?; + + let edited_secrets: HashMap = + serde_json::from_str(&edited_secrets_str)?; + + println!("Selected: {:?}", &edited_secrets); + } + None => { + println!("No selection made !"); + return Ok(false); + } + } Ok(true) } +fn remove_parent_directories(file: &Path) -> String { + file.components() + .filter(|component| component.as_os_str() != "..") + .collect::() + .to_str() + .unwrap() + .to_string() +} + fn get_dev_config_files(path: &Path) -> Vec { let mut overrides = OverrideBuilder::new(path); overrides.add("**/config/dev.exs").unwrap(); @@ -98,92 +129,3 @@ fn get_dev_config_files(path: &Path) -> Vec { .map(|e| e.path().to_path_buf()) .collect() } - -fn generate_checklist_items( - secrets: &HashMap, - edited_secrets: &HashMap, -) -> Vec<(String, String)> { - let max_key_len = edited_secrets - .values() - .map(|key| key.len()) - .max() - .unwrap_or(0); - let max_old_value_len = secrets.values().map(|key| key.len()).max().unwrap_or(0); - - let green = Style::new().for_stderr().green(); - let red = Style::new().for_stderr().red(); - - let mut items: Vec<(String, String)> = edited_secrets - .iter() - .map(|(key, new_value)| { - let mut key_with_style: String = key.clone(); - let mut old_value_with_style: String = new_value.clone(); - let mut new_value_with_style: String = new_value.clone(); - - // Insert Key: - if !secrets.contains_key(key) { - key_with_style = format!("{}{}", green.apply_to("+"), green.apply_to(key)); - } else { - // Updated values: - let old_value = secrets.get(key).unwrap_or(&String::from("")).to_string(); - let changeset = Changeset::new(&old_value, new_value, ""); - - let changes: Vec = changeset - .diffs - .iter() - .map(|diff| match diff { - Difference::Same(s) => s.to_string(), - Difference::Add(s) => format!("{}", green.apply_to(s)), - Difference::Rem(s) => format!("{}", red.apply_to(s)), - }) - .collect(); - - new_value_with_style = changes.join(""); - old_value_with_style = old_value; - } - - // Return the item: - ( - format!( - "{:>(); - - for key in deleted_keys { - let item = ( - format!( - "{: Date: Mon, 3 Apr 2023 09:30:27 +0000 Subject: [PATCH 14/43] feat: added vault update logic --- src/commands/dev/config_secrets_edit.rs | 59 +++++++++++--- src/utils/custom_dialoguer_theme.rs | 100 ------------------------ src/utils/mod.rs | 1 - 3 files changed, 50 insertions(+), 110 deletions(-) delete mode 100644 src/utils/custom_dialoguer_theme.rs diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 942ab95a5..a8ac3468d 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -1,9 +1,11 @@ +use crate::loader::new_spinner_progress_bar; use crate::{error::CliError, services::vault::Vault, utils::annotations::read_vault_annotation}; +use dialoguer::Confirm; use dialoguer::{theme::ColorfulTheme, Select}; use difference::{Changeset, Difference}; use edit::Builder; use ignore::{overrides::OverrideBuilder, WalkBuilder}; -use serde_json; +use owo_colors::OwoColorize; use std::{collections::HashMap, io::ErrorKind}; use std::{ env::current_dir, @@ -11,7 +13,9 @@ use std::{ }; pub async fn handle_config_secrets_edit(path: &Path) -> Result { - println!("🔍 Searching for config files..."); + let progress_bar = new_spinner_progress_bar(); + progress_bar.set_message("🔍 Finding config with annotation"); + let path = path.try_exists().map(|value| match value { true => match path.to_string_lossy() == "." { true => current_dir(), @@ -56,14 +60,20 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { ) } + progress_bar.finish_and_clear(); + if annotations_selections.is_empty() { eprintln!("No config files found !"); return Ok(false); } println!( - "There are ({}) config files found !", - annotations_selections.len() + "{}", + format!( + "There are ({}) config files found!", + annotations_selections.len() + ) + .bright_yellow() ); let selection = Select::with_theme(&ColorfulTheme::default()) @@ -79,6 +89,9 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { .interact_opt() .unwrap(); + // Clear the config file count line: + println!("\x1B[1A\x1B[K"); + match selection { Some(index) => { let vault = Vault::new(); @@ -88,19 +101,35 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { let (secret_path, _) = &annotations_selections[index]; let secrets = vault.get_secrets(&vault_token, &secret_path).await?.data; + let secret_string = serde_json::to_string_pretty::>(&secrets)?; + // Open editor with secrets: let edited_secrets_str = edit::edit_with_builder( serde_json::to_string_pretty::>(&secrets)?, Builder::new().prefix("config_secrets_edit").suffix(".json"), )?; - let edited_secrets: HashMap = - serde_json::from_str(&edited_secrets_str)?; - - println!("Selected: {:?}", &edited_secrets); + // Intentionally placed here to throw json parse error if the user input is invalid: + let edited_secrets: HashMap<&str, &str> = serde_json::from_str(&edited_secrets_str)?; + + println!( + "{}", + "Finished editing, please review your changes before pusing to Bunker...".cyan() + ); + print_diff(&secret_string, &edited_secrets_str); + + let agree_to_deploy = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Are you sure to push this change?") + .default(false) + .interact()?; + + if agree_to_deploy { + vault + .update_secret(&vault_token, secret_path, &edited_secrets) + .await?; + } } None => { - println!("No selection made !"); return Ok(false); } } @@ -108,6 +137,18 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { Ok(true) } +fn print_diff(secret_string: &str, edited_secrets_str: &str) -> () { + let changeset = Changeset::new(&edited_secrets_str, &secret_string, "\n"); + + for diff in &changeset.diffs { + match diff { + Difference::Same(part) => println!("{}", part), + Difference::Add(part) => println!("\x1b[32m+{}\x1b[0m", part), + Difference::Rem(part) => println!("\x1b[31m-{}\x1b[0m", part), + } + } +} + fn remove_parent_directories(file: &Path) -> String { file.components() .filter(|component| component.as_os_str() != "..") diff --git a/src/utils/custom_dialoguer_theme.rs b/src/utils/custom_dialoguer_theme.rs deleted file mode 100644 index b19b4f0eb..000000000 --- a/src/utils/custom_dialoguer_theme.rs +++ /dev/null @@ -1,100 +0,0 @@ -use core::fmt; - -use dialoguer::{ - console::{style, Style, StyledObject}, - theme::Theme, -}; - -impl Default for CustomDialoguerTheme { - fn default() -> CustomDialoguerTheme { - CustomDialoguerTheme { - defaults_style: Style::new().for_stderr().cyan(), - prompt_style: Style::new().for_stderr().bold(), - prompt_prefix: style("?".to_string()).for_stderr().yellow(), - prompt_suffix: style("› Space to deselect. Enter to execute".to_string()) - .for_stderr() - .black() - .bright(), - active_item_style: Style::new().for_stderr().white(), - inactive_item_style: Style::new().for_stderr(), - active_item_prefix: style("❯".to_string()).for_stderr(), - inactive_item_prefix: style(" ".to_string()).for_stderr(), - checked_item_prefix: style("◉".to_string()).for_stderr().green(), - unchecked_item_prefix: style("◯".to_string()).for_stderr().white(), - } - } -} - -impl Theme for CustomDialoguerTheme { - /// Formats a prompt. - fn format_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result { - if !prompt.is_empty() { - write!( - f, - "{} {} ", - &self.prompt_prefix, - self.prompt_style.apply_to(prompt) - )?; - } - - write!(f, "{}", &self.prompt_suffix) - } - - /// Formats a multi select prompt item. - fn format_multi_select_prompt_item( - &self, - f: &mut dyn fmt::Write, - text: &str, - checked: bool, - active: bool, - ) -> fmt::Result { - let details = match (checked, active) { - (true, true) => ( - &self.active_item_prefix, - &self.checked_item_prefix, - self.active_item_style.apply_to(text), - ), - (true, false) => ( - &self.inactive_item_prefix, - &self.checked_item_prefix, - self.inactive_item_style.apply_to(text), - ), - (false, true) => ( - &self.active_item_prefix, - &self.unchecked_item_prefix, - self.active_item_style.apply_to(text), - ), - (false, false) => ( - &self.inactive_item_prefix, - &self.unchecked_item_prefix, - self.inactive_item_style.apply_to(text), - ), - }; - - write!(f, "{} {} {}", details.0, details.1, details.2) - } -} - -/// A Custom theme -pub struct CustomDialoguerTheme { - /// The style for default values - pub defaults_style: Style, - /// The style for prompt - pub prompt_style: Style, - /// Prompt prefix value and style - pub prompt_prefix: StyledObject, - /// Prompt suffix value and style - pub prompt_suffix: StyledObject, - /// The style for active items - pub active_item_style: Style, - /// The style for inactive items - pub inactive_item_style: Style, - /// Active item in select prefix value and style - pub active_item_prefix: StyledObject, - /// Inctive item in select prefix value and style - pub inactive_item_prefix: StyledObject, - /// Checked item in multi select prefix value and style - pub checked_item_prefix: StyledObject, - /// Unchecked item in multi select prefix value and style - pub unchecked_item_prefix: StyledObject, -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 80db2a24b..441c53fe5 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1 @@ pub mod annotations; -pub mod custom_dialoguer_theme; From 5474889e945714988288e1a8102aa04c57aa50fb Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Mon, 3 Apr 2023 09:37:59 +0000 Subject: [PATCH 15/43] style: fix fmt issues --- src/commands/dev/config_secrets_edit.rs | 6 +++--- src/error.rs | 7 ------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index a8ac3468d..5a32bd267 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -99,7 +99,7 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { // Get the secret path based on the selection: let (secret_path, _) = &annotations_selections[index]; - let secrets = vault.get_secrets(&vault_token, &secret_path).await?.data; + let secrets = vault.get_secrets(&vault_token, secret_path).await?.data; let secret_string = serde_json::to_string_pretty::>(&secrets)?; @@ -137,8 +137,8 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { Ok(true) } -fn print_diff(secret_string: &str, edited_secrets_str: &str) -> () { - let changeset = Changeset::new(&edited_secrets_str, &secret_string, "\n"); +fn print_diff(secret_string: &str, edited_secrets_str: &str) { + let changeset = Changeset::new(edited_secrets_str, secret_string, "\n"); for diff in &changeset.diffs { match diff { diff --git a/src/error.rs b/src/error.rs index addbd4c48..09c19bd4c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -147,13 +147,6 @@ If none of the above steps work for you, please contact the following people on ), _ => None, }, - CliError::VaultError(error) => match error { - VaultError::ApiPermissionDenied => Some( - String::from("Please check your vault secret path. It could be invalid or you don't have permission to access it."), - ), - _ => None, - }, - _ => None, } } From 6d7186ad3f22be9ad3415790612695a0ecf3e300 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Mon, 3 Apr 2023 10:47:42 +0000 Subject: [PATCH 16/43] chore: added reccursive function --- Cargo.lock | 12 +++ Cargo.toml | 1 + src/commands/dev/config_secrets_edit.rs | 132 +++++++++++++++--------- 3 files changed, 96 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f74f166d4..93de562a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -283,6 +283,17 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "async-recursion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.12", +] + [[package]] name = "async-std" version = "1.12.0" @@ -4103,6 +4114,7 @@ dependencies = [ "anyhow", "assert_cmd", "assert_fs", + "async-recursion", "base64 0.21.0", "chrono", "chrono-tz", diff --git a/Cargo.toml b/Cargo.toml index 53fc29c5b..90c15f777 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ ignore = "0.4.20" rayon = "1.7.0" tree-sitter = "0.20.9" difference = "2.0.0" +async-recursion = "1.0.4" [dev-dependencies] httpmock = "0.6.7" diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 5a32bd267..7c9a595eb 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -1,5 +1,6 @@ use crate::loader::new_spinner_progress_bar; use crate::{error::CliError, services::vault::Vault, utils::annotations::read_vault_annotation}; +use async_recursion::async_recursion; use dialoguer::Confirm; use dialoguer::{theme::ColorfulTheme, Select}; use difference::{Changeset, Difference}; @@ -16,53 +17,12 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { let progress_bar = new_spinner_progress_bar(); progress_bar.set_message("🔍 Finding config with annotation"); - let path = path.try_exists().map(|value| match value { - true => match path.to_string_lossy() == "." { - true => current_dir(), - false => Ok(path.to_path_buf()), - }, - false => Err(std::io::Error::new( - ErrorKind::NotFound, - format!("path '{}' does not exist", path.to_string_lossy()), - )), - })??; - - let available_files = get_dev_config_files(&path); - let mut annotations_selections: Vec<(String, String)> = vec![]; - - for file in available_files { - let src = std::fs::read_to_string(file.clone())?; - let annotations = read_vault_annotation(&src); - - // Push this to annotations selections: - annotations_selections.extend( - annotations - .iter() - .filter(|annotation| { - annotation.key == "wukong.mindvalley.dev/config-secrets-location" - && annotation.source == "vault" - && annotation.engine == "secret" - }) - .map(|annotation| { - ( - annotation.secret_path.clone(), - format!( - "{} \t {}::{}/{}#{}", - remove_parent_directories(&file), - &annotation.source, - &annotation.engine, - &annotation.secret_path, - &annotation.secret_name - ), - ) - }) - .collect::>(), - ) - } + let available_files = get_available_files(path)?; + let available_annotations = collect_filtered_annotations(available_files)?; progress_bar.finish_and_clear(); - if annotations_selections.is_empty() { + if available_annotations.is_empty() { eprintln!("No config files found !"); return Ok(false); } @@ -71,14 +31,23 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { "{}", format!( "There are ({}) config files found!", - annotations_selections.len() + available_annotations.len() ) .bright_yellow() ); + select_and_edit_secrets(&available_annotations).await?; + + Ok(true) +} + +#[async_recursion] +async fn select_and_edit_secrets( + available_annotations: &Vec<(String, String)>, +) -> Result { let selection = Select::with_theme(&ColorfulTheme::default()) .items( - &annotations_selections + &available_annotations .iter() .map(|(_, value)| value) .collect::>(), @@ -98,7 +67,7 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { let vault_token = vault.get_token_or_login().await?; // Get the secret path based on the selection: - let (secret_path, _) = &annotations_selections[index]; + let (secret_path, _) = &available_annotations[index]; let secrets = vault.get_secrets(&vault_token, secret_path).await?.data; let secret_string = serde_json::to_string_pretty::>(&secrets)?; @@ -118,12 +87,12 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { ); print_diff(&secret_string, &edited_secrets_str); - let agree_to_deploy = Confirm::with_theme(&ColorfulTheme::default()) + let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) .with_prompt("Are you sure to push this change?") .default(false) .interact()?; - if agree_to_deploy { + if agree_to_update { vault .update_secret(&vault_token, secret_path, &edited_secrets) .await?; @@ -134,9 +103,74 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { } } + // Prompt to continue editing other secrets + let continue_editing = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Do you wish to continue editing other secrets ?") + .default(false) + .interact()?; + + if continue_editing { + select_and_edit_secrets(available_annotations).await?; + } + Ok(true) } +fn get_available_files(path: &Path) -> Result, CliError> { + let path = path.try_exists().map(|value| match value { + true => match path.to_string_lossy() == "." { + true => current_dir(), + false => Ok(path.to_path_buf()), + }, + false => Err(std::io::Error::new( + ErrorKind::NotFound, + format!("path '{}' does not exist", path.to_string_lossy()), + )), + })??; + + let available_files = get_dev_config_files(&path); + + Ok(available_files) +} + +fn collect_filtered_annotations( + available_files: Vec, +) -> Result, CliError> { + let mut annotations_selections: Vec<(String, String)> = vec![]; + + for file in available_files { + let src = std::fs::read_to_string(file.clone())?; + let annotations = read_vault_annotation(&src); + + // Push this to annotations selections: + annotations_selections.extend( + annotations + .iter() + .filter(|annotation| { + annotation.key == "wukong.mindvalley.dev/config-secrets-location" + && annotation.source == "vault" + && annotation.engine == "secret" + }) + .map(|annotation| { + ( + annotation.secret_path.clone(), + format!( + "{} \t {}::{}/{}#{}", + remove_parent_directories(&file), + &annotation.source, + &annotation.engine, + &annotation.secret_path, + &annotation.secret_name + ), + ) + }) + .collect::>(), + ) + } + + Ok(annotations_selections) +} + fn print_diff(secret_string: &str, edited_secrets_str: &str) { let changeset = Changeset::new(edited_secrets_str, secret_string, "\n"); From 120f1780416459f4efb0ae005de5927c5de59e35 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Mon, 3 Apr 2023 11:02:21 +0000 Subject: [PATCH 17/43] feat: added a logic to bypass the annotation picker if there is only one selection --- src/commands/dev/config_secrets_edit.rs | 80 ++++++++++++++----------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 7c9a595eb..ed23bc2cb 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -36,11 +36,54 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { .bright_yellow() ); - select_and_edit_secrets(&available_annotations).await?; + if available_annotations.len() == 1 { + edit_secrets(&available_annotations[0]).await?; + } else { + select_and_edit_secrets(&available_annotations).await?; + } Ok(true) } +async fn edit_secrets(annotation: &(String, String)) -> Result<(), CliError> { + let vault = Vault::new(); + let vault_token = vault.get_token_or_login().await?; + + // Get the secret path based on the selection: + let (secret_path, _) = annotation; + let secrets = vault.get_secrets(&vault_token, secret_path).await?.data; + + let secret_string = serde_json::to_string_pretty::>(&secrets)?; + + // Open editor with secrets: + let edited_secrets_str = edit::edit_with_builder( + serde_json::to_string_pretty::>(&secrets)?, + Builder::new().prefix("config_secrets_edit").suffix(".json"), + )?; + + // Intentionally placed here to throw json parse error if the user input is invalid: + let edited_secrets: HashMap<&str, &str> = serde_json::from_str(&edited_secrets_str)?; + + println!( + "{}", + "Finished editing, please review your changes before pusing to Bunker...".cyan() + ); + print_diff(&secret_string, &edited_secrets_str); + + let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Are you sure to push this change?") + .default(false) + .interact()?; + + if agree_to_update { + vault + .update_secret(&vault_token, secret_path, &edited_secrets) + .await?; + } + + Ok(()) +} + #[async_recursion] async fn select_and_edit_secrets( available_annotations: &Vec<(String, String)>, @@ -63,40 +106,7 @@ async fn select_and_edit_secrets( match selection { Some(index) => { - let vault = Vault::new(); - let vault_token = vault.get_token_or_login().await?; - - // Get the secret path based on the selection: - let (secret_path, _) = &available_annotations[index]; - let secrets = vault.get_secrets(&vault_token, secret_path).await?.data; - - let secret_string = serde_json::to_string_pretty::>(&secrets)?; - - // Open editor with secrets: - let edited_secrets_str = edit::edit_with_builder( - serde_json::to_string_pretty::>(&secrets)?, - Builder::new().prefix("config_secrets_edit").suffix(".json"), - )?; - - // Intentionally placed here to throw json parse error if the user input is invalid: - let edited_secrets: HashMap<&str, &str> = serde_json::from_str(&edited_secrets_str)?; - - println!( - "{}", - "Finished editing, please review your changes before pusing to Bunker...".cyan() - ); - print_diff(&secret_string, &edited_secrets_str); - - let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt("Are you sure to push this change?") - .default(false) - .interact()?; - - if agree_to_update { - vault - .update_secret(&vault_token, secret_path, &edited_secrets) - .await?; - } + edit_secrets(&available_annotations[index]).await?; } None => { return Ok(false); From 73cf714426cfc735923adf59ebbfc550f437d4a1 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Mon, 3 Apr 2023 11:11:22 +0000 Subject: [PATCH 18/43] bug: fix an issue where there is always a new line at the end of the new file --- src/commands/dev/config_secrets_edit.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index ed23bc2cb..424b6c976 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -61,6 +61,9 @@ async fn edit_secrets(annotation: &(String, String)) -> Result<(), CliError> { Builder::new().prefix("config_secrets_edit").suffix(".json"), )?; + // Remove the additional newline character at the end of edited_secrets_str + let edited_secrets_str = edited_secrets_str.trim_end(); + // Intentionally placed here to throw json parse error if the user input is invalid: let edited_secrets: HashMap<&str, &str> = serde_json::from_str(&edited_secrets_str)?; @@ -182,7 +185,7 @@ fn collect_filtered_annotations( } fn print_diff(secret_string: &str, edited_secrets_str: &str) { - let changeset = Changeset::new(edited_secrets_str, secret_string, "\n"); + let changeset = Changeset::new(secret_string, edited_secrets_str, "\n"); for diff in &changeset.diffs { match diff { From 7b966ae33ab94b54e1e1bd1fa5f4a214be19ae74 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Mon, 3 Apr 2023 11:29:33 +0000 Subject: [PATCH 19/43] feat: generated autocompletions --- src/commands/dev/config_secrets_edit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs index 424b6c976..ea8c79003 100644 --- a/src/commands/dev/config_secrets_edit.rs +++ b/src/commands/dev/config_secrets_edit.rs @@ -45,12 +45,12 @@ pub async fn handle_config_secrets_edit(path: &Path) -> Result { Ok(true) } -async fn edit_secrets(annotation: &(String, String)) -> Result<(), CliError> { +async fn edit_secrets(available_annotation: &(String, String)) -> Result<(), CliError> { let vault = Vault::new(); let vault_token = vault.get_token_or_login().await?; // Get the secret path based on the selection: - let (secret_path, _) = annotation; + let (secret_path, _) = available_annotation; let secrets = vault.get_secrets(&vault_token, secret_path).await?.data; let secret_string = serde_json::to_string_pretty::>(&secrets)?; From e9805db6db132af3e46dfdf10b9c39eaec1b646a Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Tue, 4 Apr 2023 11:19:50 +0000 Subject: [PATCH 20/43] refactor: changed the flow to behave like git diff --- src/commands/dev/config_secrets_edit.rs | 219 --------------------- src/commands/dev/config_secrets_push.rs | 248 ++++++++++++++++++++++++ src/commands/dev/mod.rs | 10 +- src/utils/annotations.rs | 2 +- 4 files changed, 254 insertions(+), 225 deletions(-) delete mode 100644 src/commands/dev/config_secrets_edit.rs create mode 100644 src/commands/dev/config_secrets_push.rs diff --git a/src/commands/dev/config_secrets_edit.rs b/src/commands/dev/config_secrets_edit.rs deleted file mode 100644 index ea8c79003..000000000 --- a/src/commands/dev/config_secrets_edit.rs +++ /dev/null @@ -1,219 +0,0 @@ -use crate::loader::new_spinner_progress_bar; -use crate::{error::CliError, services::vault::Vault, utils::annotations::read_vault_annotation}; -use async_recursion::async_recursion; -use dialoguer::Confirm; -use dialoguer::{theme::ColorfulTheme, Select}; -use difference::{Changeset, Difference}; -use edit::Builder; -use ignore::{overrides::OverrideBuilder, WalkBuilder}; -use owo_colors::OwoColorize; -use std::{collections::HashMap, io::ErrorKind}; -use std::{ - env::current_dir, - path::{Path, PathBuf}, -}; - -pub async fn handle_config_secrets_edit(path: &Path) -> Result { - let progress_bar = new_spinner_progress_bar(); - progress_bar.set_message("🔍 Finding config with annotation"); - - let available_files = get_available_files(path)?; - let available_annotations = collect_filtered_annotations(available_files)?; - - progress_bar.finish_and_clear(); - - if available_annotations.is_empty() { - eprintln!("No config files found !"); - return Ok(false); - } - - println!( - "{}", - format!( - "There are ({}) config files found!", - available_annotations.len() - ) - .bright_yellow() - ); - - if available_annotations.len() == 1 { - edit_secrets(&available_annotations[0]).await?; - } else { - select_and_edit_secrets(&available_annotations).await?; - } - - Ok(true) -} - -async fn edit_secrets(available_annotation: &(String, String)) -> Result<(), CliError> { - let vault = Vault::new(); - let vault_token = vault.get_token_or_login().await?; - - // Get the secret path based on the selection: - let (secret_path, _) = available_annotation; - let secrets = vault.get_secrets(&vault_token, secret_path).await?.data; - - let secret_string = serde_json::to_string_pretty::>(&secrets)?; - - // Open editor with secrets: - let edited_secrets_str = edit::edit_with_builder( - serde_json::to_string_pretty::>(&secrets)?, - Builder::new().prefix("config_secrets_edit").suffix(".json"), - )?; - - // Remove the additional newline character at the end of edited_secrets_str - let edited_secrets_str = edited_secrets_str.trim_end(); - - // Intentionally placed here to throw json parse error if the user input is invalid: - let edited_secrets: HashMap<&str, &str> = serde_json::from_str(&edited_secrets_str)?; - - println!( - "{}", - "Finished editing, please review your changes before pusing to Bunker...".cyan() - ); - print_diff(&secret_string, &edited_secrets_str); - - let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt("Are you sure to push this change?") - .default(false) - .interact()?; - - if agree_to_update { - vault - .update_secret(&vault_token, secret_path, &edited_secrets) - .await?; - } - - Ok(()) -} - -#[async_recursion] -async fn select_and_edit_secrets( - available_annotations: &Vec<(String, String)>, -) -> Result { - let selection = Select::with_theme(&ColorfulTheme::default()) - .items( - &available_annotations - .iter() - .map(|(_, value)| value) - .collect::>(), - ) - .with_prompt("Which one do you like to make the changes ?") - .default(0) - .report(false) - .interact_opt() - .unwrap(); - - // Clear the config file count line: - println!("\x1B[1A\x1B[K"); - - match selection { - Some(index) => { - edit_secrets(&available_annotations[index]).await?; - } - None => { - return Ok(false); - } - } - - // Prompt to continue editing other secrets - let continue_editing = Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt("Do you wish to continue editing other secrets ?") - .default(false) - .interact()?; - - if continue_editing { - select_and_edit_secrets(available_annotations).await?; - } - - Ok(true) -} - -fn get_available_files(path: &Path) -> Result, CliError> { - let path = path.try_exists().map(|value| match value { - true => match path.to_string_lossy() == "." { - true => current_dir(), - false => Ok(path.to_path_buf()), - }, - false => Err(std::io::Error::new( - ErrorKind::NotFound, - format!("path '{}' does not exist", path.to_string_lossy()), - )), - })??; - - let available_files = get_dev_config_files(&path); - - Ok(available_files) -} - -fn collect_filtered_annotations( - available_files: Vec, -) -> Result, CliError> { - let mut annotations_selections: Vec<(String, String)> = vec![]; - - for file in available_files { - let src = std::fs::read_to_string(file.clone())?; - let annotations = read_vault_annotation(&src); - - // Push this to annotations selections: - annotations_selections.extend( - annotations - .iter() - .filter(|annotation| { - annotation.key == "wukong.mindvalley.dev/config-secrets-location" - && annotation.source == "vault" - && annotation.engine == "secret" - }) - .map(|annotation| { - ( - annotation.secret_path.clone(), - format!( - "{} \t {}::{}/{}#{}", - remove_parent_directories(&file), - &annotation.source, - &annotation.engine, - &annotation.secret_path, - &annotation.secret_name - ), - ) - }) - .collect::>(), - ) - } - - Ok(annotations_selections) -} - -fn print_diff(secret_string: &str, edited_secrets_str: &str) { - let changeset = Changeset::new(secret_string, edited_secrets_str, "\n"); - - for diff in &changeset.diffs { - match diff { - Difference::Same(part) => println!("{}", part), - Difference::Add(part) => println!("\x1b[32m+{}\x1b[0m", part), - Difference::Rem(part) => println!("\x1b[31m-{}\x1b[0m", part), - } - } -} - -fn remove_parent_directories(file: &Path) -> String { - file.components() - .filter(|component| component.as_os_str() != "..") - .collect::() - .to_str() - .unwrap() - .to_string() -} - -fn get_dev_config_files(path: &Path) -> Vec { - let mut overrides = OverrideBuilder::new(path); - overrides.add("**/config/dev.exs").unwrap(); - - WalkBuilder::new(path) - .overrides(overrides.build().unwrap()) - .build() - .flatten() - .filter(|e| e.path().is_file()) - .map(|e| e.path().to_path_buf()) - .collect() -} diff --git a/src/commands/dev/config_secrets_push.rs b/src/commands/dev/config_secrets_push.rs new file mode 100644 index 000000000..6abe48087 --- /dev/null +++ b/src/commands/dev/config_secrets_push.rs @@ -0,0 +1,248 @@ +use crate::loader::new_spinner_progress_bar; +use crate::utils::annotations::VaultSecretAnnotation; +use crate::{error::CliError, services::vault::Vault, utils::annotations::read_vault_annotation}; +use dialoguer::Confirm; +use dialoguer::{theme::ColorfulTheme, Select}; +use difference::{Changeset, Difference}; +use ignore::{overrides::OverrideBuilder, WalkBuilder}; +use owo_colors::OwoColorize; +use std::{collections::HashMap, io::ErrorKind}; +use std::{ + env::current_dir, + path::{Path, PathBuf}, +}; + +pub async fn handle_config_secrets_push(path: &Path) -> Result { + let progress_bar = new_spinner_progress_bar(); + progress_bar.set_message("🔍 Finding config with annotation"); + + let available_files = get_available_files(path)?; + let config_files = filter_vault_secret_annotations(available_files)?; + + progress_bar.finish_and_clear(); + + if config_files.is_empty() { + eprintln!("No config files found!"); + return Ok(false); + } + + println!( + "{}", + format!("There are ({}) config files found!", config_files.len()).bright_yellow() + ); + + compare_config_files(&config_files).await?; + + Ok(true) +} + +async fn compare_config_files( + config_files: &HashMap, +) -> Result<(), CliError> { + // Comparing local vs remote .... + println!("{}", "Comparing local config vs remote config...".cyan()); + + let vault = Vault::new(); + let vault_token = vault.get_token_or_login().await?; + + let mut configss = HashMap::new(); + + for config_file in config_files { + let (config_path, vault_secret_annotation) = config_file; + let remote_secrets = vault + .get_secrets(&vault_token, &vault_secret_annotation.secret_path) + .await? + .data; + + let path = PathBuf::from(config_path); + let dir_path = path.parent().unwrap(); + + let local_secrets = dir_path.join(&vault_secret_annotation.destination_file); + let local_secrets = std::fs::read_to_string(local_secrets)?; + + // Get only one key from hashmap + let remote_config = remote_secrets + .get(&vault_secret_annotation.secret_name) + .unwrap(); + + let changeset = Changeset::new(remote_config, &local_secrets, "\n"); + + if has_diff(&changeset) { + configss.insert(config_path.clone(), vault_secret_annotation.clone()); + } + } + + let config_to_update = select_config(&configss).await; + update_secrets(&config_to_update).await?; + + Ok(()) +} + +async fn update_secrets( + config_to_update: &(String, VaultSecretAnnotation), +) -> Result<(), CliError> { + let vault = Vault::new(); + + let vault_token = vault.get_token_or_login().await?; + + let (secret_path, vault_secret_annotation) = config_to_update; + + let path = PathBuf::from(secret_path); + let dir_path = path.parent().unwrap(); + + let local_secrets = dir_path.join(&vault_secret_annotation.destination_file); + let local_secrets = std::fs::read_to_string(local_secrets)?; + let mut secrets = vault + .get_secrets(&vault_token, &vault_secret_annotation.secret_path) + .await? + .data; + + let remote_config = secrets.get(&vault_secret_annotation.secret_name).unwrap(); + + print_diff(remote_config, &local_secrets.to_owned()); + + // print_diff(&secret_string, &edited_secrets_str); + let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Confirm this change & push?") + .default(false) + .interact()?; + + // Update one key from secrets: + secrets.insert(vault_secret_annotation.secret_name.clone(), local_secrets); + + let hashmap: HashMap<&str, &str> = secrets + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect(); + + if agree_to_update { + vault + .update_secret(&vault_token, &vault_secret_annotation.secret_path, &hashmap) + .await?; + } + + Ok(()) +} + +fn has_diff(changeset: &Changeset) -> bool { + changeset + .diffs + .iter() + .any(|diff| matches!(diff, Difference::Add(_) | Difference::Rem(_))) +} + +async fn select_config( + available_config: &HashMap, +) -> (String, VaultSecretAnnotation) { + let selection = Select::with_theme(&ColorfulTheme::default()) + .items( + &available_config + .iter() + .map(|(config_path, annotation)| { + format!( + "{} \t {}::{}/{}#{}", + remove_parent_directories(config_path), + annotation.source, + annotation.engine, + annotation.secret_path, + annotation.secret_name + ) + }) + .collect::>(), + ) + .with_prompt("Which one do you like to push the changes?") + .default(0) + .report(false) + .interact_opt() + .unwrap(); + + // Clear the config file count line: + println!("\x1B[1A\x1B[K"); + + return match selection { + Some(index) => { + let (config_path, annotation) = available_config.iter().nth(index).unwrap(); + (config_path.clone(), annotation.clone()) + } + None => { + println!("No selection made, exiting..."); + std::process::exit(0); + } + }; +} + +fn get_available_files(path: &Path) -> Result, CliError> { + let path = path.try_exists().map(|value| match value { + true => match path.to_string_lossy() == "." { + true => current_dir(), + false => Ok(path.to_path_buf()), + }, + false => Err(std::io::Error::new( + ErrorKind::NotFound, + format!("path '{}' does not exist", path.to_string_lossy()), + )), + })??; + + let available_files = get_dev_config_files(&path); + + Ok(available_files) +} + +fn filter_vault_secret_annotations( + available_files: Vec, +) -> Result, CliError> { + let mut filtered_annotations: HashMap = HashMap::new(); + + for file in available_files { + let src = std::fs::read_to_string(file.clone())?; + let annotations = read_vault_annotation(&src); + + for annotation in annotations { + if annotation.key == "wukong.mindvalley.dev/config-secrets-location" + && annotation.source == "vault" + && annotation.engine == "secret" + { + filtered_annotations.insert(file.to_string_lossy().to_string(), annotation); + } + } + } + + Ok(filtered_annotations) +} + +fn print_diff(secret_string: &str, edited_secrets_str: &str) { + let changeset = Changeset::new(secret_string, edited_secrets_str, "\n"); + + println!(); + + for diff in changeset.diffs.iter() { + match diff { + Difference::Same(part) => println!("{}", part), + Difference::Add(part) => println!("\x1b[32m+{}\x1b[0m", part), + Difference::Rem(part) => println!("\x1b[31m-{}\x1b[0m", part), + } + } +} + +fn remove_parent_directories(path: &str) -> String { + let file = Path::new(path); + file.components() + .filter(|component| component.as_os_str() != "..") + .collect::() + .to_str() + .unwrap() + .to_string() +} + +fn get_dev_config_files(path: &Path) -> Vec { + let mut overrides = OverrideBuilder::new(path); + overrides.add("**/config/dev.exs").unwrap(); + + WalkBuilder::new(path) + .overrides(overrides.build().unwrap()) + .build() + .flatten() + .filter(|e| e.path().is_file()) + .map(|e| e.path().to_path_buf()) + .collect() +} diff --git a/src/commands/dev/mod.rs b/src/commands/dev/mod.rs index e7b3db1b2..d3f51d7a6 100644 --- a/src/commands/dev/mod.rs +++ b/src/commands/dev/mod.rs @@ -1,12 +1,12 @@ mod config_lint; mod config_synthesizer; -mod config_secrets_edit; +mod config_secrets_push; use crate::error::CliError; use clap::{Args, Subcommand}; use config_lint::handle_config_lint; use config_synthesizer::handle_config_synthesizer; -use config_secrets_edit::handle_config_secrets_edit; +use config_secrets_push::handle_config_secrets_push; use std::path::PathBuf; #[derive(Debug, Args)] @@ -29,8 +29,8 @@ pub enum DevSubcommand { #[arg(default_value = ".")] path: PathBuf, }, - /// Linting the config and show possible warnings, as well as suggestion how to fix the config file. - ConfigSecretsEdit { + /// Edit the config file from the vault + ConfigSecretsPush { /// The path to the project #[arg(default_value = ".")] path: PathBuf, @@ -42,7 +42,7 @@ impl Dev { match &self.subcommand { DevSubcommand::ConfigLint { path } => handle_config_lint(path), DevSubcommand::ConfigSynthesizer { path } => handle_config_synthesizer(path).await, - DevSubcommand::ConfigSecretsEdit { path } => handle_config_secrets_edit(path).await, + DevSubcommand::ConfigSecretsPush { path } => handle_config_secrets_push(path).await, } } } diff --git a/src/utils/annotations.rs b/src/utils/annotations.rs index fe4d34bee..2c2a00d73 100644 --- a/src/utils/annotations.rs +++ b/src/utils/annotations.rs @@ -11,7 +11,7 @@ use tree_sitter::{Parser, Query, QueryCursor}; // secret_path = path/to/secret // secret_name = secret_key // destination_file = dev.secret.exs -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct VaultSecretAnnotation { pub key: String, pub source: String, From 91727dd7b5cfbdea89f2e555699717a7afa69850 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Tue, 4 Apr 2023 11:49:09 +0000 Subject: [PATCH 21/43] style: fix issues on style --- src/commands/dev/config_secrets_push.rs | 86 +++++++++++++++---------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/src/commands/dev/config_secrets_push.rs b/src/commands/dev/config_secrets_push.rs index 6abe48087..571c8f267 100644 --- a/src/commands/dev/config_secrets_push.rs +++ b/src/commands/dev/config_secrets_push.rs @@ -26,80 +26,95 @@ pub async fn handle_config_secrets_push(path: &Path) -> Result { return Ok(false); } - println!( - "{}", - format!("There are ({}) config files found!", config_files.len()).bright_yellow() - ); + if config_files.len() != 1 { + println!( + "{}", + format!("There are ({}) config files found!", config_files.len()).bright_yellow() + ); + } + + let vault = Vault::new(); + let vault_token = vault.get_token_or_login().await?; + + let updated_configs = get_updated_configs(&vault, &vault_token, &config_files).await?; + + if updated_configs.is_empty() { + eprintln!("No config files need to be updated!"); + return Ok(false); + } - compare_config_files(&config_files).await?; + let config_to_update = select_config(&updated_configs).await; + update_secrets(&vault, &vault_token, &config_to_update).await?; Ok(true) } -async fn compare_config_files( +async fn get_updated_configs( + vault: &Vault, + vault_token: &str, config_files: &HashMap, -) -> Result<(), CliError> { +) -> Result, CliError> { // Comparing local vs remote .... println!("{}", "Comparing local config vs remote config...".cyan()); - let vault = Vault::new(); - let vault_token = vault.get_token_or_login().await?; - - let mut configss = HashMap::new(); + let mut updated_configs = HashMap::new(); for config_file in config_files { let (config_path, vault_secret_annotation) = config_file; let remote_secrets = vault - .get_secrets(&vault_token, &vault_secret_annotation.secret_path) + .get_secrets(vault_token, &vault_secret_annotation.secret_path) .await? .data; - let path = PathBuf::from(config_path); - let dir_path = path.parent().unwrap(); - - let local_secrets = dir_path.join(&vault_secret_annotation.destination_file); - let local_secrets = std::fs::read_to_string(local_secrets)?; + let config_string = + get_local_config_as_string(&vault_secret_annotation.destination_file, config_path)?; // Get only one key from hashmap let remote_config = remote_secrets .get(&vault_secret_annotation.secret_name) .unwrap(); - let changeset = Changeset::new(remote_config, &local_secrets, "\n"); + let changeset = Changeset::new(remote_config, &config_string, "\n"); if has_diff(&changeset) { - configss.insert(config_path.clone(), vault_secret_annotation.clone()); + updated_configs.insert(config_path.clone(), vault_secret_annotation.clone()); } } - let config_to_update = select_config(&configss).await; - update_secrets(&config_to_update).await?; + Ok(updated_configs) +} - Ok(()) +fn get_local_config_as_string( + destination_file: &str, + config_path: &str, +) -> Result { + let path = PathBuf::from(config_path); + let dir_path = path.parent().unwrap(); + let local_secrets = dir_path.join(destination_file); + + let local_secrets = std::fs::read_to_string(local_secrets)?; + + Ok(local_secrets) } async fn update_secrets( + vault: &Vault, + vault_token: &str, config_to_update: &(String, VaultSecretAnnotation), ) -> Result<(), CliError> { - let vault = Vault::new(); - - let vault_token = vault.get_token_or_login().await?; - let (secret_path, vault_secret_annotation) = config_to_update; - let path = PathBuf::from(secret_path); - let dir_path = path.parent().unwrap(); + let local_config_string = + get_local_config_as_string(&vault_secret_annotation.destination_file, secret_path)?; - let local_secrets = dir_path.join(&vault_secret_annotation.destination_file); - let local_secrets = std::fs::read_to_string(local_secrets)?; let mut secrets = vault - .get_secrets(&vault_token, &vault_secret_annotation.secret_path) + .get_secrets(vault_token, &vault_secret_annotation.secret_path) .await? .data; let remote_config = secrets.get(&vault_secret_annotation.secret_name).unwrap(); - print_diff(remote_config, &local_secrets.to_owned()); + print_diff(remote_config, &local_config_string); // print_diff(&secret_string, &edited_secrets_str); let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) @@ -108,7 +123,10 @@ async fn update_secrets( .interact()?; // Update one key from secrets: - secrets.insert(vault_secret_annotation.secret_name.clone(), local_secrets); + secrets.insert( + vault_secret_annotation.secret_name.clone(), + local_config_string, + ); let hashmap: HashMap<&str, &str> = secrets .iter() @@ -117,7 +135,7 @@ async fn update_secrets( if agree_to_update { vault - .update_secret(&vault_token, &vault_secret_annotation.secret_path, &hashmap) + .update_secret(vault_token, &vault_secret_annotation.secret_path, &hashmap) .await?; } From ec6afd5912caf32831becc1af1228776faf415c9 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Tue, 4 Apr 2023 11:49:58 +0000 Subject: [PATCH 22/43] style: fix issues on style --- src/commands/dev/config_secrets_push.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/commands/dev/config_secrets_push.rs b/src/commands/dev/config_secrets_push.rs index 571c8f267..832daa30d 100644 --- a/src/commands/dev/config_secrets_push.rs +++ b/src/commands/dev/config_secrets_push.rs @@ -91,7 +91,6 @@ fn get_local_config_as_string( let path = PathBuf::from(config_path); let dir_path = path.parent().unwrap(); let local_secrets = dir_path.join(destination_file); - let local_secrets = std::fs::read_to_string(local_secrets)?; Ok(local_secrets) @@ -116,7 +115,6 @@ async fn update_secrets( print_diff(remote_config, &local_config_string); - // print_diff(&secret_string, &edited_secrets_str); let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) .with_prompt("Confirm this change & push?") .default(false) From ffeceacd68c32deeccb4c5d7acb1753d100961fc Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Tue, 4 Apr 2023 12:05:14 +0000 Subject: [PATCH 23/43] style: clippy fixes --- src/commands/dev/config_secrets_push.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/dev/config_secrets_push.rs b/src/commands/dev/config_secrets_push.rs index 832daa30d..5112f7b8b 100644 --- a/src/commands/dev/config_secrets_push.rs +++ b/src/commands/dev/config_secrets_push.rs @@ -210,8 +210,8 @@ fn filter_vault_secret_annotations( let mut filtered_annotations: HashMap = HashMap::new(); for file in available_files { - let src = std::fs::read_to_string(file.clone())?; - let annotations = read_vault_annotation(&src); + let file_contents = std::fs::read_to_string(file.clone())?; + let annotations = read_vault_annotation(&file_contents); for annotation in annotations { if annotation.key == "wukong.mindvalley.dev/config-secrets-location" From 0c186f5dd7141ac30fe2096c0da5b91e1132acaa Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 03:36:19 +0000 Subject: [PATCH 24/43] chore: generated autocompletions --- completions/bash/wukong.bash | 65 ++++++++++++++++++++++++++++++++++-- completions/fish/wukong.fish | 37 +++++++++++++------- completions/zsh/_wukong | 51 ++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 15 deletions(-) diff --git a/completions/bash/wukong.bash b/completions/bash/wukong.bash index a036e2607..e0655ad95 100644 --- a/completions/bash/wukong.bash +++ b/completions/bash/wukong.bash @@ -102,6 +102,9 @@ _wukong() { wukong__dev,config-lint) cmd="wukong__dev__config__lint" ;; + wukong__dev,config-secrets-push) + cmd="wukong__dev__config__secrets__push" + ;; wukong__dev,config-synthesizer) cmd="wukong__dev__config__synthesizer" ;; @@ -111,6 +114,9 @@ _wukong() { wukong__dev__help,config-lint) cmd="wukong__dev__help__config__lint" ;; + wukong__dev__help,config-secrets-push) + cmd="wukong__dev__help__config__secrets__push" + ;; wukong__dev__help,config-synthesizer) cmd="wukong__dev__help__config__synthesizer" ;; @@ -168,6 +174,9 @@ _wukong() { wukong__help__dev,config-lint) cmd="wukong__help__dev__config__lint" ;; + wukong__help__dev,config-secrets-push) + cmd="wukong__help__dev__config__secrets__push" + ;; wukong__help__dev,config-synthesizer) cmd="wukong__help__dev__config__synthesizer" ;; @@ -677,7 +686,7 @@ _wukong() { return 0 ;; wukong__dev) - opts="-a -v -q -h --application --verbose --quiet --help config-lint config-synthesizer help" + opts="-a -v -q -h --application --verbose --quiet --help config-lint config-synthesizer config-secrets-push help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -720,6 +729,28 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__config__secrets__push) + opts="-a -v -q -h --application --verbose --quiet --help [PATH]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --application) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -a) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__config__synthesizer) opts="-a -v -q -h --application --verbose --quiet --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -743,7 +774,7 @@ _wukong() { return 0 ;; wukong__dev__help) - opts="config-lint config-synthesizer help" + opts="config-lint config-synthesizer config-secrets-push help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -770,6 +801,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__help__config__secrets__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__help__config__synthesizer) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -967,7 +1012,7 @@ _wukong() { return 0 ;; wukong__help__dev) - opts="config-lint config-synthesizer" + opts="config-lint config-synthesizer config-secrets-push" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -994,6 +1039,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__help__dev__config__secrets__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__help__dev__config__synthesizer) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then diff --git a/completions/fish/wukong.fish b/completions/fish/wukong.fish index b1b530c93..d02c52898 100644 --- a/completions/fish/wukong.fish +++ b/completions/fish/wukong.fish @@ -155,19 +155,20 @@ complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_s complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "execute" -d 'Start the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "rollback" -d 'Rollback the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. By default, it\'ll only report errors. `-v` show warnings `-vv` show info `-vvv` show debug `-vvvv` show trace' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-secrets-push" -d 'Edit the config file from the vault' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-lint" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-lint" -s v -l verbose -d 'Use verbos output. More output per occurrence. @@ -188,9 +189,20 @@ By default, it\'ll only report errors. `-vvvv` show trace' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-synthesizer" -s q -l quiet -d 'Do not print log message' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-synthesizer" -s h -l help -d 'Print help' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s v -l verbose -d 'Use verbos output. More output per occurrence. + +By default, it\'ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-secrets-push" -d 'Edit the config file from the vault' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c wukong -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r complete -c wukong -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. @@ -275,8 +287,9 @@ complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcomm complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "list" -d 'List the current available deployment pipelines of an application' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "execute" -d 'Start the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "rollback" -d 'Rollback the deployment pipeline' -complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push" -f -a "config-secrets-push" -d 'Edit the config file from the vault' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "list" -d 'List the configurations' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "set" -d 'Set the value of a configuration' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "get" -d 'Print the value of a configuration' diff --git a/completions/zsh/_wukong b/completions/zsh/_wukong index 96dbf34e1..1c035b684 100644 --- a/completions/zsh/_wukong +++ b/completions/zsh/_wukong @@ -512,6 +512,31 @@ By default, it'\''ll only report errors. `-vvvv` show trace]' \ '*--verbose[Use verbos output. More output per occurrence. +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'(-v --verbose)*-q[Do not print log message]' \ +'(-v --verbose)*--quiet[Do not print log message]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'::path -- The path to the project:_files' \ +&& ret=0 +;; +(config-secrets-push) +_arguments "${_arguments_options[@]}" \ +'-a+[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'--application=[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'*-v[Use verbos output. More output per occurrence. + +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'*--verbose[Use verbos output. More output per occurrence. + By default, it'\''ll only report errors. `-v` show warnings `-vv` show info @@ -544,6 +569,10 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(config-secrets-push) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; (help) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -859,6 +888,10 @@ _arguments "${_arguments_options[@]}" \ (config-synthesizer) _arguments "${_arguments_options[@]}" \ && ret=0 +;; +(config-secrets-push) +_arguments "${_arguments_options[@]}" \ +&& ret=0 ;; esac ;; @@ -1002,6 +1035,21 @@ _wukong__help__dev__config-lint_commands() { local commands; commands=() _describe -t commands 'wukong help dev config-lint commands' commands "$@" } +(( $+functions[_wukong__dev__config-secrets-push_commands] )) || +_wukong__dev__config-secrets-push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev config-secrets-push commands' commands "$@" +} +(( $+functions[_wukong__dev__help__config-secrets-push_commands] )) || +_wukong__dev__help__config-secrets-push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev help config-secrets-push commands' commands "$@" +} +(( $+functions[_wukong__help__dev__config-secrets-push_commands] )) || +_wukong__help__dev__config-secrets-push_commands() { + local commands; commands=() + _describe -t commands 'wukong help dev config-secrets-push commands' commands "$@" +} (( $+functions[_wukong__dev__config-synthesizer_commands] )) || _wukong__dev__config-synthesizer_commands() { local commands; commands=() @@ -1056,6 +1104,7 @@ _wukong__dev_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ +'config-secrets-push:Edit the config file from the vault' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'wukong dev commands' commands "$@" @@ -1065,6 +1114,7 @@ _wukong__help__dev_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ +'config-secrets-push:Edit the config file from the vault' \ ) _describe -t commands 'wukong help dev commands' commands "$@" } @@ -1146,6 +1196,7 @@ _wukong__dev__help_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ +'config-secrets-push:Edit the config file from the vault' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'wukong dev help commands' commands "$@" From 8b93601556f222673c8ba43fff1cf87bf8ef19d7 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 03:40:18 +0000 Subject: [PATCH 25/43] revert: removed async-recursion function --- Cargo.lock | 38 +++++++++++++------------------------- Cargo.toml | 1 - 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93de562a3..6027f5daf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -283,17 +283,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "async-recursion" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.12", -] - [[package]] name = "async-std" version = "1.12.0" @@ -873,7 +862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -982,7 +971,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 1.0.109", + "syn", ] [[package]] @@ -993,7 +982,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -1412,7 +1401,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 1.0.109", + "syn", ] [[package]] @@ -1423,7 +1412,7 @@ checksum = "d52fc9cde811f44b15ec0692b31e56a3067f6f431c5ace712f286e47c1dacc98" dependencies = [ "graphql_client_codegen", "proc-macro2", - "syn 1.0.109", + "syn", ] [[package]] @@ -2498,7 +2487,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -2618,7 +2607,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", + "syn", "version_check", ] @@ -3056,7 +3045,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -3258,7 +3247,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -3544,7 +3533,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -3799,7 +3788,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn", "wasm-bindgen-shared", ] @@ -3833,7 +3822,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4114,7 +4103,6 @@ dependencies = [ "anyhow", "assert_cmd", "assert_fs", - "async-recursion", "base64 0.21.0", "chrono", "chrono-tz", @@ -4165,7 +4153,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 90c15f777..53fc29c5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,6 @@ ignore = "0.4.20" rayon = "1.7.0" tree-sitter = "0.20.9" difference = "2.0.0" -async-recursion = "1.0.4" [dev-dependencies] httpmock = "0.6.7" From 263791a2e3f180e32e17c9fb2f63557f1ea09c7c Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 04:23:59 +0000 Subject: [PATCH 26/43] revert(errors): unnesry changes in errors --- src/error.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index 09c19bd4c..b42c3ac03 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,8 +23,6 @@ pub enum CliError { DeploymentError(#[from] DeploymentError), #[error(transparent)] VaultError(#[from] VaultError), - #[error(transparent)] - SerdeJsonError(#[from] serde_json::Error), } #[derive(Debug, ThisError)] @@ -43,7 +41,7 @@ pub enum VaultError { SecretNotFound, #[error("API token not found.")] ApiTokenNotFound, - #[error("Invalid token.")] + #[error("Invalid API token.")] ApiTokenInvalid, #[error("Permission denied.")] PermissionDenied, From d7f041fa1611808d980894205c0db878af543869 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 04:47:49 +0000 Subject: [PATCH 27/43] feat: added new sub command group --- src/commands/dev/config/mod.rs | 30 +++++++++++++++++++ .../push.rs} | 2 +- src/commands/dev/mod.rs | 13 +++----- 3 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 src/commands/dev/config/mod.rs rename src/commands/dev/{config_secrets_push.rs => config/push.rs} (99%) diff --git a/src/commands/dev/config/mod.rs b/src/commands/dev/config/mod.rs new file mode 100644 index 000000000..740c8f954 --- /dev/null +++ b/src/commands/dev/config/mod.rs @@ -0,0 +1,30 @@ +mod push; + +use crate::error::CliError; +use clap::{Args, Subcommand}; +use push::handle_config_push; +use std::path::PathBuf; + +#[derive(Debug, Args)] +pub struct Config { + #[command(subcommand)] + pub subcommand: ConfigSubcommand, +} + +#[derive(Debug, Subcommand)] +pub enum ConfigSubcommand { + /// Push the current configuration changes to the Bunker. + Push { + /// The path to the project + #[arg(default_value = ".")] + path: PathBuf, + }, +} + +impl Config { + pub async fn handle_command(&self) -> Result { + match &self.subcommand { + ConfigSubcommand::Push { path } => handle_config_push(path).await, + } + } +} diff --git a/src/commands/dev/config_secrets_push.rs b/src/commands/dev/config/push.rs similarity index 99% rename from src/commands/dev/config_secrets_push.rs rename to src/commands/dev/config/push.rs index 5112f7b8b..3f4a47a79 100644 --- a/src/commands/dev/config_secrets_push.rs +++ b/src/commands/dev/config/push.rs @@ -12,7 +12,7 @@ use std::{ path::{Path, PathBuf}, }; -pub async fn handle_config_secrets_push(path: &Path) -> Result { +pub async fn handle_config_push(path: &Path) -> Result { let progress_bar = new_spinner_progress_bar(); progress_bar.set_message("🔍 Finding config with annotation"); diff --git a/src/commands/dev/mod.rs b/src/commands/dev/mod.rs index d3f51d7a6..16eae50f7 100644 --- a/src/commands/dev/mod.rs +++ b/src/commands/dev/mod.rs @@ -1,12 +1,11 @@ +mod config; mod config_lint; mod config_synthesizer; -mod config_secrets_push; use crate::error::CliError; use clap::{Args, Subcommand}; use config_lint::handle_config_lint; use config_synthesizer::handle_config_synthesizer; -use config_secrets_push::handle_config_secrets_push; use std::path::PathBuf; #[derive(Debug, Args)] @@ -29,12 +28,8 @@ pub enum DevSubcommand { #[arg(default_value = ".")] path: PathBuf, }, - /// Edit the config file from the vault - ConfigSecretsPush { - /// The path to the project - #[arg(default_value = ".")] - path: PathBuf, - }, + /// This command group contains the commands to interact with the config secrets with bunker. + Config(config::Config), } impl Dev { @@ -42,7 +37,7 @@ impl Dev { match &self.subcommand { DevSubcommand::ConfigLint { path } => handle_config_lint(path), DevSubcommand::ConfigSynthesizer { path } => handle_config_synthesizer(path).await, - DevSubcommand::ConfigSecretsPush { path } => handle_config_secrets_push(path).await, + DevSubcommand::Config(config) => config.handle_command().await, } } } From 3a8958332b0f801f4a008d48fc482f18ee8401b2 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 05:09:04 +0000 Subject: [PATCH 28/43] feat: disable selection if there is only one option available --- src/commands/dev/config/push.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 3f4a47a79..39393e992 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -43,8 +43,23 @@ pub async fn handle_config_push(path: &Path) -> Result { return Ok(false); } - let config_to_update = select_config(&updated_configs).await; - update_secrets(&vault, &vault_token, &config_to_update).await?; + if updated_configs.len() != 1 { + let config_to_update = select_config(&updated_configs).await; + update_secrets(&vault, &vault_token, &config_to_update).await?; + } else { + println!( + "{}", + "There is only one config file to update...".bright_yellow() + ); + let (config_path, annotation) = updated_configs.iter().next().unwrap(); + + update_secrets( + &vault, + &vault_token, + &(config_path.clone(), annotation.clone()), + ) + .await?; + } Ok(true) } @@ -55,7 +70,7 @@ async fn get_updated_configs( config_files: &HashMap, ) -> Result, CliError> { // Comparing local vs remote .... - println!("{}", "Comparing local config vs remote config...".cyan()); + println!("{}", "comparing local config vs remote config...".cyan()); let mut updated_configs = HashMap::new(); @@ -126,14 +141,18 @@ async fn update_secrets( local_config_string, ); - let hashmap: HashMap<&str, &str> = secrets + let secrets_ref: HashMap<&str, &str> = secrets .iter() .map(|(k, v)| (k.as_str(), v.as_str())) .collect(); if agree_to_update { vault - .update_secret(vault_token, &vault_secret_annotation.secret_path, &hashmap) + .update_secret( + vault_token, + &vault_secret_annotation.secret_path, + &secrets_ref, + ) .await?; } From da070eee4969cbef9e0490be51286204aa77e8f2 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 06:44:37 +0000 Subject: [PATCH 29/43] refactor: changed diff library to similar.rs --- Cargo.lock | 8 +--- Cargo.toml | 2 +- src/commands/dev/config/push.rs | 69 ++++++++++++++++++++++++--------- src/utils/line.rs | 12 ++++++ src/utils/mod.rs | 1 + 5 files changed, 66 insertions(+), 26 deletions(-) create mode 100644 src/utils/line.rs diff --git a/Cargo.lock b/Cargo.lock index 6027f5daf..23955c816 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1003,12 +1003,6 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - [[package]] name = "difflib" version = "0.4.0" @@ -4112,7 +4106,6 @@ dependencies = [ "criterion", "ctrlc", "dialoguer", - "difference", "dirs", "edit", "elixir_linter", @@ -4135,6 +4128,7 @@ dependencies = [ "rexpect", "serde", "serde_json", + "similar", "tabled", "thiserror", "time-humanize", diff --git a/Cargo.toml b/Cargo.toml index 53fc29c5b..32f79621a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ miette = { version = "5.5.0", features = ["fancy"] } ignore = "0.4.20" rayon = "1.7.0" tree-sitter = "0.20.9" -difference = "2.0.0" +similar = { version = "2.2.1", features = ["inline"] } [dev-dependencies] httpmock = "0.6.7" diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 39393e992..e470584a1 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -1,11 +1,15 @@ use crate::loader::new_spinner_progress_bar; use crate::utils::annotations::VaultSecretAnnotation; -use crate::{error::CliError, services::vault::Vault, utils::annotations::read_vault_annotation}; +use crate::{ + error::CliError, services::vault::Vault, utils::annotations::read_vault_annotation, + utils::line::Line, +}; +use dialoguer::console::{style, Style}; use dialoguer::Confirm; use dialoguer::{theme::ColorfulTheme, Select}; -use difference::{Changeset, Difference}; use ignore::{overrides::OverrideBuilder, WalkBuilder}; use owo_colors::OwoColorize; +use similar::{ChangeTag, TextDiff}; use std::{collections::HashMap, io::ErrorKind}; use std::{ env::current_dir, @@ -89,9 +93,7 @@ async fn get_updated_configs( .get(&vault_secret_annotation.secret_name) .unwrap(); - let changeset = Changeset::new(remote_config, &config_string, "\n"); - - if has_diff(&changeset) { + if has_diff(remote_config, &config_string) { updated_configs.insert(config_path.clone(), vault_secret_annotation.clone()); } } @@ -128,7 +130,7 @@ async fn update_secrets( let remote_config = secrets.get(&vault_secret_annotation.secret_name).unwrap(); - print_diff(remote_config, &local_config_string); + print_diff(remote_config, &local_config_string, secret_path); let agree_to_update = Confirm::with_theme(&ColorfulTheme::default()) .with_prompt("Confirm this change & push?") @@ -159,11 +161,16 @@ async fn update_secrets( Ok(()) } -fn has_diff(changeset: &Changeset) -> bool { +fn has_diff(old_secret_config: &str, new_secret_config: &str) -> bool { + let changeset = TextDiff::from_lines(old_secret_config, new_secret_config); + changeset - .diffs - .iter() - .any(|diff| matches!(diff, Difference::Add(_) | Difference::Rem(_))) + .iter_all_changes() + .any(|change| match change.tag() { + ChangeTag::Delete => true, + ChangeTag::Insert => true, + _ => false, + }) } async fn select_config( @@ -245,18 +252,44 @@ fn filter_vault_secret_annotations( Ok(filtered_annotations) } -fn print_diff(secret_string: &str, edited_secrets_str: &str) { - let changeset = Changeset::new(secret_string, edited_secrets_str, "\n"); - +fn print_diff(old_secret_config: &str, new_secret_config: &str, secret_path: &str) { println!(); + println!("{}", secret_path.dimmed()); - for diff in changeset.diffs.iter() { - match diff { - Difference::Same(part) => println!("{}", part), - Difference::Add(part) => println!("\x1b[32m+{}\x1b[0m", part), - Difference::Rem(part) => println!("\x1b[31m-{}\x1b[0m", part), + let diff = TextDiff::from_lines(old_secret_config, new_secret_config); + + for (idx, group) in diff.grouped_ops(3).iter().enumerate() { + if idx > 0 { + println!("{:-^1$}", "-", 80); + } + for op in group { + for change in diff.iter_inline_changes(op) { + let (sign, s) = match change.tag() { + ChangeTag::Delete => ("-", Style::new().red()), + ChangeTag::Insert => ("+", Style::new().green()), + ChangeTag::Equal => (" ", Style::new().dim()), + }; + print!( + "{}{} |{}", + style(Line(change.old_index())).dim(), + style(Line(change.new_index())).dim(), + s.apply_to(sign).bold(), + ); + for (emphasized, value) in change.iter_strings_lossy() { + if emphasized { + print!("{}", s.apply_to(value).underlined().on_black()); + } else { + print!("{}", s.apply_to(value)); + } + } + if change.missing_newline() { + println!(); + } + } } } + + println!(); } fn remove_parent_directories(path: &str) -> String { diff --git a/src/utils/line.rs b/src/utils/line.rs new file mode 100644 index 000000000..211117d00 --- /dev/null +++ b/src/utils/line.rs @@ -0,0 +1,12 @@ +use core::fmt; + +pub struct Line(pub Option); + +impl fmt::Display for Line { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + None => write!(f, " "), + Some(idx) => write!(f, "{:<4}", idx + 1), + } + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 441c53fe5..cd8723bd2 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1 +1,2 @@ pub mod annotations; +pub mod line; From 89e7ba31060fcf431177fcdbe215081c7e2ce073 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 06:53:47 +0000 Subject: [PATCH 30/43] chore: updated autocompletions --- completions/bash/wukong.bash | 152 ++++++++++++++++--- completions/fish/wukong.fish | 54 ++++--- completions/zsh/_wukong | 174 +++++++++++++++++++--- src/commands/dev/config/push.rs | 6 +- tests/snapshots/dev__wukong_dev_help.snap | 2 - 5 files changed, 320 insertions(+), 68 deletions(-) diff --git a/completions/bash/wukong.bash b/completions/bash/wukong.bash index e0655ad95..2bdd4de6f 100644 --- a/completions/bash/wukong.bash +++ b/completions/bash/wukong.bash @@ -99,30 +99,45 @@ _wukong() { wukong__deployment__help,rollback) cmd="wukong__deployment__help__rollback" ;; + wukong__dev,config) + cmd="wukong__dev__config" + ;; wukong__dev,config-lint) cmd="wukong__dev__config__lint" ;; - wukong__dev,config-secrets-push) - cmd="wukong__dev__config__secrets__push" - ;; wukong__dev,config-synthesizer) cmd="wukong__dev__config__synthesizer" ;; wukong__dev,help) cmd="wukong__dev__help" ;; + wukong__dev__config,help) + cmd="wukong__dev__config__help" + ;; + wukong__dev__config,push) + cmd="wukong__dev__config__push" + ;; + wukong__dev__config__help,help) + cmd="wukong__dev__config__help__help" + ;; + wukong__dev__config__help,push) + cmd="wukong__dev__config__help__push" + ;; + wukong__dev__help,config) + cmd="wukong__dev__help__config" + ;; wukong__dev__help,config-lint) cmd="wukong__dev__help__config__lint" ;; - wukong__dev__help,config-secrets-push) - cmd="wukong__dev__help__config__secrets__push" - ;; wukong__dev__help,config-synthesizer) cmd="wukong__dev__help__config__synthesizer" ;; wukong__dev__help,help) cmd="wukong__dev__help__help" ;; + wukong__dev__help__config,push) + cmd="wukong__dev__help__config__push" + ;; wukong__help,application) cmd="wukong__help__application" ;; @@ -171,15 +186,18 @@ _wukong() { wukong__help__deployment,rollback) cmd="wukong__help__deployment__rollback" ;; + wukong__help__dev,config) + cmd="wukong__help__dev__config" + ;; wukong__help__dev,config-lint) cmd="wukong__help__dev__config__lint" ;; - wukong__help__dev,config-secrets-push) - cmd="wukong__help__dev__config__secrets__push" - ;; wukong__help__dev,config-synthesizer) cmd="wukong__help__dev__config__synthesizer" ;; + wukong__help__dev__config,push) + cmd="wukong__help__dev__config__push" + ;; wukong__help__pipeline,ci-status) cmd="wukong__help__pipeline__ci__status" ;; @@ -686,7 +704,7 @@ _wukong() { return 0 ;; wukong__dev) - opts="-a -v -q -h --application --verbose --quiet --help config-lint config-synthesizer config-secrets-push help" + opts="-a -v -q -h --application --verbose --quiet --help config-lint config-synthesizer config help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -707,8 +725,8 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - wukong__dev__config__lint) - opts="-a -v -q -h --application --verbose --quiet --help [PATH]" + wukong__dev__config) + opts="-a -v -q -h --application --verbose --quiet --help push help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -729,7 +747,7 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - wukong__dev__config__secrets__push) + wukong__dev__config__lint) opts="-a -v -q -h --application --verbose --quiet --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -773,8 +791,72 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__config__help) + opts="push help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + wukong__dev__config__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + wukong__dev__config__help__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + wukong__dev__config__push) + opts="-a -v -q -h --application --verbose --quiet --help [PATH]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --application) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -a) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__help) - opts="config-lint config-synthesizer config-secrets-push help" + opts="config-lint config-synthesizer config help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -787,8 +869,8 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - wukong__dev__help__config__lint) - opts="" + wukong__dev__help__config) + opts="push" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -801,7 +883,7 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - wukong__dev__help__config__secrets__push) + wukong__dev__help__config__lint) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -829,6 +911,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__help__config__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -1012,7 +1108,7 @@ _wukong() { return 0 ;; wukong__help__dev) - opts="config-lint config-synthesizer config-secrets-push" + opts="config-lint config-synthesizer config" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1025,8 +1121,8 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - wukong__help__dev__config__lint) - opts="" + wukong__help__dev__config) + opts="push" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1039,7 +1135,7 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - wukong__help__dev__config__secrets__push) + wukong__help__dev__config__lint) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) @@ -1067,6 +1163,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__help__dev__config__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/completions/fish/wukong.fish b/completions/fish/wukong.fish index d02c52898..579becf25 100644 --- a/completions/fish/wukong.fish +++ b/completions/fish/wukong.fish @@ -155,20 +155,20 @@ complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_s complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "execute" -d 'Start the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "rollback" -d 'Rollback the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. By default, it\'ll only report errors. `-v` show warnings `-vv` show info `-vvv` show debug `-vvvv` show trace' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-secrets-push" -d 'Edit the config file from the vault' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config" -d 'This command group contains the commands to interact with the config secrets with bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-lint" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-lint" -s v -l verbose -d 'Use verbos output. More output per occurrence. @@ -189,20 +189,35 @@ By default, it\'ll only report errors. `-vvvv` show trace' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-synthesizer" -s q -l quiet -d 'Do not print log message' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-synthesizer" -s h -l help -d 'Print help' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s v -l verbose -d 'Use verbos output. More output per occurrence. +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. By default, it\'ll only report errors. `-v` show warnings `-vv` show info `-vvv` show debug `-vvvv` show trace' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s q -l quiet -d 'Do not print log message' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-secrets-push" -s h -l help -d 'Print help' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "config-secrets-push" -d 'Edit the config file from the vault' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "push" -d 'Push the current configuration changes to the Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s v -l verbose -d 'Use verbos output. More output per occurrence. + +By default, it\'ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "push" -d 'Push the current configuration changes to the Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config" -d 'This command group contains the commands to interact with the config secrets with bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push" -f -a "push" -d 'Push the current configuration changes to the Bunker' complete -c wukong -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r complete -c wukong -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. @@ -287,9 +302,10 @@ complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcomm complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "list" -d 'List the current available deployment pipelines of an application' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "execute" -d 'Start the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "rollback" -d 'Rollback the deployment pipeline' -complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' -complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config-secrets-push" -f -a "config-secrets-push" -d 'Edit the config file from the vault' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config" -f -a "config" -d 'This command group contains the commands to interact with the config secrets with bunker' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push" -f -a "push" -d 'Push the current configuration changes to the Bunker' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "list" -d 'List the configurations' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "set" -d 'Set the value of a configuration' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "get" -d 'Print the value of a configuration' diff --git a/completions/zsh/_wukong b/completions/zsh/_wukong index 1c035b684..7c137577f 100644 --- a/completions/zsh/_wukong +++ b/completions/zsh/_wukong @@ -524,7 +524,39 @@ By default, it'\''ll only report errors. '::path -- The path to the project:_files' \ && ret=0 ;; -(config-secrets-push) +(config) +_arguments "${_arguments_options[@]}" \ +'-a+[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'--application=[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'*-v[Use verbos output. More output per occurrence. + +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'*--verbose[Use verbos output. More output per occurrence. + +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'(-v --verbose)*-q[Do not print log message]' \ +'(-v --verbose)*--quiet[Do not print log message]' \ +'-h[Print help]' \ +'--help[Print help]' \ +":: :_wukong__dev__config_commands" \ +"*::: :->config" \ +&& ret=0 + + case $state in + (config) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-dev-config-command-$line[1]:" + case $line[1] in + (push) _arguments "${_arguments_options[@]}" \ '-a+[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ '--application=[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ @@ -551,6 +583,34 @@ By default, it'\''ll only report errors. ;; (help) _arguments "${_arguments_options[@]}" \ +":: :_wukong__dev__config__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-dev-config-help-command-$line[1]:" + case $line[1] in + (push) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; +(help) +_arguments "${_arguments_options[@]}" \ ":: :_wukong__dev__help_commands" \ "*::: :->help" \ && ret=0 @@ -569,9 +629,25 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; -(config-secrets-push) +(config) +_arguments "${_arguments_options[@]}" \ +":: :_wukong__dev__help__config_commands" \ +"*::: :->config" \ +&& ret=0 + + case $state in + (config) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-dev-help-config-command-$line[1]:" + case $line[1] in + (push) _arguments "${_arguments_options[@]}" \ && ret=0 +;; + esac + ;; +esac ;; (help) _arguments "${_arguments_options[@]}" \ @@ -889,13 +965,29 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; -(config-secrets-push) +(config) +_arguments "${_arguments_options[@]}" \ +":: :_wukong__help__dev__config_commands" \ +"*::: :->config" \ +&& ret=0 + + case $state in + (config) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-help-dev-config-command-$line[1]:" + case $line[1] in + (push) _arguments "${_arguments_options[@]}" \ && ret=0 ;; esac ;; esac +;; + esac + ;; +esac ;; (config) _arguments "${_arguments_options[@]}" \ @@ -1011,6 +1103,21 @@ _wukong__config_commands() { ) _describe -t commands 'wukong config commands' commands "$@" } +(( $+functions[_wukong__dev__config_commands] )) || +_wukong__dev__config_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'wukong dev config commands' commands "$@" +} +(( $+functions[_wukong__dev__help__config_commands] )) || +_wukong__dev__help__config_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ + ) + _describe -t commands 'wukong dev help config commands' commands "$@" +} (( $+functions[_wukong__help__config_commands] )) || _wukong__help__config_commands() { local commands; commands=( @@ -1020,6 +1127,13 @@ _wukong__help__config_commands() { ) _describe -t commands 'wukong help config commands' commands "$@" } +(( $+functions[_wukong__help__dev__config_commands] )) || +_wukong__help__dev__config_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ + ) + _describe -t commands 'wukong help dev config commands' commands "$@" +} (( $+functions[_wukong__dev__config-lint_commands] )) || _wukong__dev__config-lint_commands() { local commands; commands=() @@ -1035,21 +1149,6 @@ _wukong__help__dev__config-lint_commands() { local commands; commands=() _describe -t commands 'wukong help dev config-lint commands' commands "$@" } -(( $+functions[_wukong__dev__config-secrets-push_commands] )) || -_wukong__dev__config-secrets-push_commands() { - local commands; commands=() - _describe -t commands 'wukong dev config-secrets-push commands' commands "$@" -} -(( $+functions[_wukong__dev__help__config-secrets-push_commands] )) || -_wukong__dev__help__config-secrets-push_commands() { - local commands; commands=() - _describe -t commands 'wukong dev help config-secrets-push commands' commands "$@" -} -(( $+functions[_wukong__help__dev__config-secrets-push_commands] )) || -_wukong__help__dev__config-secrets-push_commands() { - local commands; commands=() - _describe -t commands 'wukong help dev config-secrets-push commands' commands "$@" -} (( $+functions[_wukong__dev__config-synthesizer_commands] )) || _wukong__dev__config-synthesizer_commands() { local commands; commands=() @@ -1104,7 +1203,7 @@ _wukong__dev_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ -'config-secrets-push:Edit the config file from the vault' \ +'config:This command group contains the commands to interact with the config secrets with bunker' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'wukong dev commands' commands "$@" @@ -1114,7 +1213,7 @@ _wukong__help__dev_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ -'config-secrets-push:Edit the config file from the vault' \ +'config:This command group contains the commands to interact with the config secrets with bunker' \ ) _describe -t commands 'wukong help dev commands' commands "$@" } @@ -1191,12 +1290,25 @@ _wukong__deployment__help__help_commands() { local commands; commands=() _describe -t commands 'wukong deployment help help commands' commands "$@" } +(( $+functions[_wukong__dev__config__help_commands] )) || +_wukong__dev__config__help_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'wukong dev config help commands' commands "$@" +} +(( $+functions[_wukong__dev__config__help__help_commands] )) || +_wukong__dev__config__help__help_commands() { + local commands; commands=() + _describe -t commands 'wukong dev config help help commands' commands "$@" +} (( $+functions[_wukong__dev__help_commands] )) || _wukong__dev__help_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ -'config-secrets-push:Edit the config file from the vault' \ +'config:This command group contains the commands to interact with the config secrets with bunker' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'wukong dev help commands' commands "$@" @@ -1340,6 +1452,26 @@ _wukong__pipeline_commands() { ) _describe -t commands 'wukong pipeline commands' commands "$@" } +(( $+functions[_wukong__dev__config__help__push_commands] )) || +_wukong__dev__config__help__push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev config help push commands' commands "$@" +} +(( $+functions[_wukong__dev__config__push_commands] )) || +_wukong__dev__config__push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev config push commands' commands "$@" +} +(( $+functions[_wukong__dev__help__config__push_commands] )) || +_wukong__dev__help__config__push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev help config push commands' commands "$@" +} +(( $+functions[_wukong__help__dev__config__push_commands] )) || +_wukong__help__dev__config__push_commands() { + local commands; commands=() + _describe -t commands 'wukong help dev config push commands' commands "$@" +} (( $+functions[_wukong__deployment__help__rollback_commands] )) || _wukong__deployment__help__rollback_commands() { local commands; commands=() diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index e470584a1..55400205b 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -166,11 +166,7 @@ fn has_diff(old_secret_config: &str, new_secret_config: &str) -> bool { changeset .iter_all_changes() - .any(|change| match change.tag() { - ChangeTag::Delete => true, - ChangeTag::Insert => true, - _ => false, - }) + .any(|change| matches!(change.tag(), ChangeTag::Delete | ChangeTag::Insert)) } async fn select_config( diff --git a/tests/snapshots/dev__wukong_dev_help.snap b/tests/snapshots/dev__wukong_dev_help.snap index 008041f85..d01e082d2 100644 --- a/tests/snapshots/dev__wukong_dev_help.snap +++ b/tests/snapshots/dev__wukong_dev_help.snap @@ -10,8 +10,6 @@ Commands: config-lint Linting the config and show possible warnings, as well as suggestion how to fix the config file config-synthesizer Synthesize the development config with secrets file from Bunker - config-secret-edit Linting the config and show possible warnings, as well as suggestion how - to fix the config file help Print this message or the help of the given subcommand(s) Options: From 1ea3b3f245b5aedfb7b9ab60633a795691b225b6 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 07:04:44 +0000 Subject: [PATCH 31/43] style: updated function names --- src/commands/dev/config/push.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 55400205b..b572b2151 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -21,7 +21,7 @@ pub async fn handle_config_push(path: &Path) -> Result { progress_bar.set_message("🔍 Finding config with annotation"); let available_files = get_available_files(path)?; - let config_files = filter_vault_secret_annotations(available_files)?; + let config_files = filter_config_with_secret_annotations(available_files)?; progress_bar.finish_and_clear(); @@ -47,10 +47,7 @@ pub async fn handle_config_push(path: &Path) -> Result { return Ok(false); } - if updated_configs.len() != 1 { - let config_to_update = select_config(&updated_configs).await; - update_secrets(&vault, &vault_token, &config_to_update).await?; - } else { + if updated_configs.len() == 1 { println!( "{}", "There is only one config file to update...".bright_yellow() @@ -63,6 +60,9 @@ pub async fn handle_config_push(path: &Path) -> Result { &(config_path.clone(), annotation.clone()), ) .await?; + } else { + let config_to_update = select_config(&updated_configs).await; + update_secrets(&vault, &vault_token, &config_to_update).await?; } Ok(true) @@ -226,7 +226,7 @@ fn get_available_files(path: &Path) -> Result, CliError> { Ok(available_files) } -fn filter_vault_secret_annotations( +fn filter_config_with_secret_annotations( available_files: Vec, ) -> Result, CliError> { let mut filtered_annotations: HashMap = HashMap::new(); From b6c674058896fa591b0bfefd4e0f374f5e64c5db Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 07:31:14 +0000 Subject: [PATCH 32/43] test: fix autocompletion failed test cases --- .../completion__wukong_completion_bash.snap | 175 ++++++++++++++++- .../completion__wukong_completion_fish.snap | 53 +++-- .../completion__wukong_completion_zsh.snap | 183 ++++++++++++++++++ tests/snapshots/dev__wukong_dev_help.snap | 2 + 4 files changed, 398 insertions(+), 15 deletions(-) diff --git a/tests/snapshots/completion__wukong_completion_bash.snap b/tests/snapshots/completion__wukong_completion_bash.snap index 784c69dac..e66ae5ff2 100644 --- a/tests/snapshots/completion__wukong_completion_bash.snap +++ b/tests/snapshots/completion__wukong_completion_bash.snap @@ -103,6 +103,9 @@ _wukong() { wukong__deployment__help,rollback) cmd="wukong__deployment__help__rollback" ;; + wukong__dev,config) + cmd="wukong__dev__config" + ;; wukong__dev,config-lint) cmd="wukong__dev__config__lint" ;; @@ -112,6 +115,21 @@ _wukong() { wukong__dev,help) cmd="wukong__dev__help" ;; + wukong__dev__config,help) + cmd="wukong__dev__config__help" + ;; + wukong__dev__config,push) + cmd="wukong__dev__config__push" + ;; + wukong__dev__config__help,help) + cmd="wukong__dev__config__help__help" + ;; + wukong__dev__config__help,push) + cmd="wukong__dev__config__help__push" + ;; + wukong__dev__help,config) + cmd="wukong__dev__help__config" + ;; wukong__dev__help,config-lint) cmd="wukong__dev__help__config__lint" ;; @@ -121,6 +139,9 @@ _wukong() { wukong__dev__help,help) cmd="wukong__dev__help__help" ;; + wukong__dev__help__config,push) + cmd="wukong__dev__help__config__push" + ;; wukong__help,application) cmd="wukong__help__application" ;; @@ -169,12 +190,18 @@ _wukong() { wukong__help__deployment,rollback) cmd="wukong__help__deployment__rollback" ;; + wukong__help__dev,config) + cmd="wukong__help__dev__config" + ;; wukong__help__dev,config-lint) cmd="wukong__help__dev__config__lint" ;; wukong__help__dev,config-synthesizer) cmd="wukong__help__dev__config__synthesizer" ;; + wukong__help__dev__config,push) + cmd="wukong__help__dev__config__push" + ;; wukong__help__pipeline,ci-status) cmd="wukong__help__pipeline__ci__status" ;; @@ -681,7 +708,7 @@ _wukong() { return 0 ;; wukong__dev) - opts="-a -v -q -h --application --verbose --quiet --help config-lint config-synthesizer help" + opts="-a -v -q -h --application --verbose --quiet --help config-lint config-synthesizer config help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -702,6 +729,28 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__config) + opts="-a -v -q -h --application --verbose --quiet --help push help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --application) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -a) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__config__lint) opts="-a -v -q -h --application --verbose --quiet --help [PATH]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then @@ -746,8 +795,72 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__config__help) + opts="push help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + wukong__dev__config__help__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + wukong__dev__config__help__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + wukong__dev__config__push) + opts="-a -v -q -h --application --verbose --quiet --help [PATH]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --application) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -a) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__help) - opts="config-lint config-synthesizer help" + opts="config-lint config-synthesizer config help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -760,6 +873,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__help__config) + opts="push" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__help__config__lint) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -788,6 +915,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__dev__help__config__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__dev__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -971,7 +1112,7 @@ _wukong() { return 0 ;; wukong__help__dev) - opts="config-lint config-synthesizer" + opts="config-lint config-synthesizer config" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -984,6 +1125,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__help__dev__config) + opts="push" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__help__dev__config__lint) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then @@ -1012,6 +1167,20 @@ _wukong() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + wukong__help__dev__config__push) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 5 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; wukong__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/tests/snapshots/completion__wukong_completion_fish.snap b/tests/snapshots/completion__wukong_completion_fish.snap index b8bfff189..ae99bcf59 100644 --- a/tests/snapshots/completion__wukong_completion_fish.snap +++ b/tests/snapshots/completion__wukong_completion_fish.snap @@ -159,19 +159,20 @@ complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_s complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "execute" -d 'Start the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "rollback" -d 'Rollback the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from deployment; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. By default, it\'ll only report errors. `-v` show warnings `-vv` show info `-vvv` show debug `-vvvv` show trace' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' -complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config" -d 'This command group contains the commands to interact with the config secrets with bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-lint" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-lint" -s v -l verbose -d 'Use verbos output. More output per occurrence. @@ -192,9 +193,35 @@ By default, it\'ll only report errors. `-vvvv` show trace' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-synthesizer" -s q -l quiet -d 'Do not print log message' complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config-synthesizer" -s h -l help -d 'Print help' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' -complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. + +By default, it\'ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "push" -d 'Push the current configuration changes to the Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s v -l verbose -d 'Use verbos output. More output per occurrence. + +By default, it\'ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s q -l quiet -d 'Do not print log message' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from push" -s h -l help -d 'Print help' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "push" -d 'Push the current configuration changes to the Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from push; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config" -d 'This command group contains the commands to interact with the config secrets with bunker' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c wukong -n "__fish_seen_subcommand_from dev; and __fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push" -f -a "push" -d 'Push the current configuration changes to the Bunker' complete -c wukong -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from help" -s a -l application -d 'Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config' -r complete -c wukong -n "__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get; and not __fish_seen_subcommand_from help" -s v -l verbose -d 'Use verbos output. More output per occurrence. @@ -279,8 +306,10 @@ complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcomm complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "list" -d 'List the current available deployment pipelines of an application' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "execute" -d 'Start the deployment pipeline' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from execute; and not __fish_seen_subcommand_from rollback" -f -a "rollback" -d 'Rollback the deployment pipeline' -complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' -complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config" -f -a "config-lint" -d 'Linting the config and show possible warnings, as well as suggestion how to fix the config file' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config" -f -a "config-synthesizer" -d 'Synthesize the development config with secrets file from Bunker' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and not __fish_seen_subcommand_from config-lint; and not __fish_seen_subcommand_from config-synthesizer; and not __fish_seen_subcommand_from config" -f -a "config" -d 'This command group contains the commands to interact with the config secrets with bunker' +complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from dev; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from push" -f -a "push" -d 'Push the current configuration changes to the Bunker' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "list" -d 'List the configurations' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "set" -d 'Set the value of a configuration' complete -c wukong -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from set; and not __fish_seen_subcommand_from get" -f -a "get" -d 'Print the value of a configuration' diff --git a/tests/snapshots/completion__wukong_completion_zsh.snap b/tests/snapshots/completion__wukong_completion_zsh.snap index 8c33fc784..b3fd60d1e 100644 --- a/tests/snapshots/completion__wukong_completion_zsh.snap +++ b/tests/snapshots/completion__wukong_completion_zsh.snap @@ -516,6 +516,63 @@ By default, it'\''ll only report errors. `-vvvv` show trace]' \ '*--verbose[Use verbos output. More output per occurrence. +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'(-v --verbose)*-q[Do not print log message]' \ +'(-v --verbose)*--quiet[Do not print log message]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'::path -- The path to the project:_files' \ +&& ret=0 +;; +(config) +_arguments "${_arguments_options[@]}" \ +'-a+[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'--application=[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'*-v[Use verbos output. More output per occurrence. + +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'*--verbose[Use verbos output. More output per occurrence. + +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'(-v --verbose)*-q[Do not print log message]' \ +'(-v --verbose)*--quiet[Do not print log message]' \ +'-h[Print help]' \ +'--help[Print help]' \ +":: :_wukong__dev__config_commands" \ +"*::: :->config" \ +&& ret=0 + + case $state in + (config) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-dev-config-command-$line[1]:" + case $line[1] in + (push) +_arguments "${_arguments_options[@]}" \ +'-a+[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'--application=[Override the application name that the CLI will perform the command against. If the flag is not used, then the CLI will use the default application name from the config]:APPLICATION: ' \ +'*-v[Use verbos output. More output per occurrence. + +By default, it'\''ll only report errors. +`-v` show warnings +`-vv` show info +`-vvv` show debug +`-vvvv` show trace]' \ +'*--verbose[Use verbos output. More output per occurrence. + By default, it'\''ll only report errors. `-v` show warnings `-vv` show info @@ -530,6 +587,34 @@ By default, it'\''ll only report errors. ;; (help) _arguments "${_arguments_options[@]}" \ +":: :_wukong__dev__config__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-dev-config-help-command-$line[1]:" + case $line[1] in + (push) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; +(help) +_arguments "${_arguments_options[@]}" \ ":: :_wukong__dev__help_commands" \ "*::: :->help" \ && ret=0 @@ -548,6 +633,26 @@ _arguments "${_arguments_options[@]}" \ _arguments "${_arguments_options[@]}" \ && ret=0 ;; +(config) +_arguments "${_arguments_options[@]}" \ +":: :_wukong__dev__help__config_commands" \ +"*::: :->config" \ +&& ret=0 + + case $state in + (config) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-dev-help-config-command-$line[1]:" + case $line[1] in + (push) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac +;; (help) _arguments "${_arguments_options[@]}" \ && ret=0 @@ -863,6 +968,26 @@ _arguments "${_arguments_options[@]}" \ (config-synthesizer) _arguments "${_arguments_options[@]}" \ && ret=0 +;; +(config) +_arguments "${_arguments_options[@]}" \ +":: :_wukong__help__dev__config_commands" \ +"*::: :->config" \ +&& ret=0 + + case $state in + (config) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:wukong-help-dev-config-command-$line[1]:" + case $line[1] in + (push) +_arguments "${_arguments_options[@]}" \ +&& ret=0 +;; + esac + ;; +esac ;; esac ;; @@ -982,6 +1107,21 @@ _wukong__config_commands() { ) _describe -t commands 'wukong config commands' commands "$@" } +(( $+functions[_wukong__dev__config_commands] )) || +_wukong__dev__config_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'wukong dev config commands' commands "$@" +} +(( $+functions[_wukong__dev__help__config_commands] )) || +_wukong__dev__help__config_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ + ) + _describe -t commands 'wukong dev help config commands' commands "$@" +} (( $+functions[_wukong__help__config_commands] )) || _wukong__help__config_commands() { local commands; commands=( @@ -991,6 +1131,13 @@ _wukong__help__config_commands() { ) _describe -t commands 'wukong help config commands' commands "$@" } +(( $+functions[_wukong__help__dev__config_commands] )) || +_wukong__help__dev__config_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ + ) + _describe -t commands 'wukong help dev config commands' commands "$@" +} (( $+functions[_wukong__dev__config-lint_commands] )) || _wukong__dev__config-lint_commands() { local commands; commands=() @@ -1060,6 +1207,7 @@ _wukong__dev_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ +'config:This command group contains the commands to interact with the config secrets with bunker' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'wukong dev commands' commands "$@" @@ -1069,6 +1217,7 @@ _wukong__help__dev_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ +'config:This command group contains the commands to interact with the config secrets with bunker' \ ) _describe -t commands 'wukong help dev commands' commands "$@" } @@ -1145,11 +1294,25 @@ _wukong__deployment__help__help_commands() { local commands; commands=() _describe -t commands 'wukong deployment help help commands' commands "$@" } +(( $+functions[_wukong__dev__config__help_commands] )) || +_wukong__dev__config__help_commands() { + local commands; commands=( +'push:Push the current configuration changes to the Bunker' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'wukong dev config help commands' commands "$@" +} +(( $+functions[_wukong__dev__config__help__help_commands] )) || +_wukong__dev__config__help__help_commands() { + local commands; commands=() + _describe -t commands 'wukong dev config help help commands' commands "$@" +} (( $+functions[_wukong__dev__help_commands] )) || _wukong__dev__help_commands() { local commands; commands=( 'config-lint:Linting the config and show possible warnings, as well as suggestion how to fix the config file' \ 'config-synthesizer:Synthesize the development config with secrets file from Bunker' \ +'config:This command group contains the commands to interact with the config secrets with bunker' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'wukong dev help commands' commands "$@" @@ -1293,6 +1456,26 @@ _wukong__pipeline_commands() { ) _describe -t commands 'wukong pipeline commands' commands "$@" } +(( $+functions[_wukong__dev__config__help__push_commands] )) || +_wukong__dev__config__help__push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev config help push commands' commands "$@" +} +(( $+functions[_wukong__dev__config__push_commands] )) || +_wukong__dev__config__push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev config push commands' commands "$@" +} +(( $+functions[_wukong__dev__help__config__push_commands] )) || +_wukong__dev__help__config__push_commands() { + local commands; commands=() + _describe -t commands 'wukong dev help config push commands' commands "$@" +} +(( $+functions[_wukong__help__dev__config__push_commands] )) || +_wukong__help__dev__config__push_commands() { + local commands; commands=() + _describe -t commands 'wukong help dev config push commands' commands "$@" +} (( $+functions[_wukong__deployment__help__rollback_commands] )) || _wukong__deployment__help__rollback_commands() { local commands; commands=() diff --git a/tests/snapshots/dev__wukong_dev_help.snap b/tests/snapshots/dev__wukong_dev_help.snap index d01e082d2..039cb1dcd 100644 --- a/tests/snapshots/dev__wukong_dev_help.snap +++ b/tests/snapshots/dev__wukong_dev_help.snap @@ -10,6 +10,8 @@ Commands: config-lint Linting the config and show possible warnings, as well as suggestion how to fix the config file config-synthesizer Synthesize the development config with secrets file from Bunker + config This command group contains the commands to interact with the config + secrets with bunker help Print this message or the help of the given subcommand(s) Options: From b1d8f6af26e26d3e8545d2ee9f299260e27f046e Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Wed, 5 Apr 2023 07:47:39 +0000 Subject: [PATCH 33/43] test: added some test cases --- Cargo.lock | 37 ++++++++++++++++++++++++++--- src/commands/dev/config/push.rs | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23955c816..60ceec38b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1128,6 +1128,17 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -1729,7 +1740,7 @@ checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", + "rustix 0.36.9", "windows-sys 0.45.0", ] @@ -1951,6 +1962,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + [[package]] name = "lock_api" version = "0.4.9" @@ -2827,10 +2844,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", + "io-lifetimes", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +dependencies = [ + "bitflags", + "errno 0.3.0", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.1", "windows-sys 0.45.0", ] diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index b572b2151..ae800fd1a 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -310,3 +310,45 @@ fn get_dev_config_files(path: &Path) -> Vec { .map(|e| e.path().to_path_buf()) .collect() } + +// Test: +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_empty_string() { + let path = ""; + let result = remove_parent_directories(path); + assert_eq!(result, ""); + } + + #[test] + fn test_no_parent_directories() { + let path = "dir1/dir2/file.txt"; + let result = remove_parent_directories(path); + assert_eq!(result, "dir1/dir2/file.txt"); + } + + #[test] + fn test_single_parent_directory() { + let path = "dir1/../dir2/file.txt"; + let result = remove_parent_directories(path); + assert_eq!(result, "dir1/dir2/file.txt"); + } + + #[test] + fn test_invalid_characters() { + let path = "dir1/inv@lid/../dir2/file.txt"; + let result = remove_parent_directories(path); + assert_eq!(result, "dir1/inv@lid/dir2/file.txt"); + } + + #[test] + fn test_non_existent_file() { + let non_existent_path = "non_existent_file.txt"; + + let result = get_local_config_as_string("destination_file", non_existent_path); + assert!(result.is_err()); + } +} From 5e6843ce6319c8d1756d4e5408a7c0a689aa8ccb Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 05:03:25 +0000 Subject: [PATCH 34/43] fix: updated cargo.lock to fix merge conflicts --- Cargo.lock | 63 ++++++++++++++---------------------------------------- 1 file changed, 16 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60ceec38b..8e32300b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -862,7 +862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -971,7 +971,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.109", ] [[package]] @@ -982,7 +982,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1128,17 +1128,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "errno" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.45.0", -] - [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -1406,7 +1395,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn", + "syn 1.0.109", ] [[package]] @@ -1417,7 +1406,7 @@ checksum = "d52fc9cde811f44b15ec0692b31e56a3067f6f431c5ace712f286e47c1dacc98" dependencies = [ "graphql_client_codegen", "proc-macro2", - "syn", + "syn 1.0.109", ] [[package]] @@ -1740,7 +1729,7 @@ checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix 0.36.9", + "rustix", "windows-sys 0.45.0", ] @@ -1962,12 +1951,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" -[[package]] -name = "linux-raw-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" - [[package]] name = "lock_api" version = "0.4.9" @@ -2498,7 +2481,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2618,7 +2601,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -2844,24 +2827,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ "bitflags", - "errno 0.2.8", - "io-lifetimes", - "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.45.0", -] - -[[package]] -name = "rustix" -version = "0.37.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" -dependencies = [ - "bitflags", - "errno 0.3.0", + "errno", "io-lifetimes", "libc", - "linux-raw-sys 0.3.1", + "linux-raw-sys", "windows-sys 0.45.0", ] @@ -3070,7 +3039,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -3272,7 +3241,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -3558,7 +3527,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -3813,7 +3782,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -3847,7 +3816,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4178,7 +4147,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] From ba17fa809bc28d5e36c76f1bd3d7494cd95c81f1 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 06:44:08 +0000 Subject: [PATCH 35/43] feat: updated error codes --- src/commands/dev/config/mod.rs | 9 +---- src/commands/dev/config/push.rs | 52 +++++++++++++----------- src/config/dev.exs | 72 +++++++++++++++++++++++++++++++++ src/config/dev.secrets.exs | 28 +++++++++++++ src/error.rs | 24 +++++++++++ 5 files changed, 154 insertions(+), 31 deletions(-) create mode 100644 src/config/dev.exs create mode 100644 src/config/dev.secrets.exs diff --git a/src/commands/dev/config/mod.rs b/src/commands/dev/config/mod.rs index 740c8f954..93b408935 100644 --- a/src/commands/dev/config/mod.rs +++ b/src/commands/dev/config/mod.rs @@ -3,7 +3,6 @@ mod push; use crate::error::CliError; use clap::{Args, Subcommand}; use push::handle_config_push; -use std::path::PathBuf; #[derive(Debug, Args)] pub struct Config { @@ -14,17 +13,13 @@ pub struct Config { #[derive(Debug, Subcommand)] pub enum ConfigSubcommand { /// Push the current configuration changes to the Bunker. - Push { - /// The path to the project - #[arg(default_value = ".")] - path: PathBuf, - }, + Push, } impl Config { pub async fn handle_command(&self) -> Result { match &self.subcommand { - ConfigSubcommand::Push { path } => handle_config_push(path).await, + ConfigSubcommand::Push => handle_config_push().await, } } } diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index ae800fd1a..0573158a9 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -1,3 +1,4 @@ +use crate::error::DevConfigError; use crate::loader::new_spinner_progress_bar; use crate::utils::annotations::VaultSecretAnnotation; use crate::{ @@ -8,26 +9,26 @@ use dialoguer::console::{style, Style}; use dialoguer::Confirm; use dialoguer::{theme::ColorfulTheme, Select}; use ignore::{overrides::OverrideBuilder, WalkBuilder}; +use log::debug; use owo_colors::OwoColorize; use similar::{ChangeTag, TextDiff}; -use std::{collections::HashMap, io::ErrorKind}; +use std::collections::HashMap; use std::{ env::current_dir, path::{Path, PathBuf}, }; -pub async fn handle_config_push(path: &Path) -> Result { +pub async fn handle_config_push() -> Result { let progress_bar = new_spinner_progress_bar(); progress_bar.set_message("🔍 Finding config with annotation"); - let available_files = get_available_files(path)?; + let available_files = get_available_files()?; let config_files = filter_config_with_secret_annotations(available_files)?; progress_bar.finish_and_clear(); if config_files.is_empty() { - eprintln!("No config files found!"); - return Ok(false); + return Err(CliError::DevConfigError(DevConfigError::ConfigNotFound)); } if config_files.len() != 1 { @@ -43,8 +44,7 @@ pub async fn handle_config_push(path: &Path) -> Result { let updated_configs = get_updated_configs(&vault, &vault_token, &config_files).await?; if updated_configs.is_empty() { - eprintln!("No config files need to be updated!"); - return Ok(false); + return Err(CliError::DevConfigError(DevConfigError::UpToDateError)); } if updated_configs.len() == 1 { @@ -85,13 +85,27 @@ async fn get_updated_configs( .await? .data; + // Handle and throw InvalidSecretPath if No such file or directory (os error 2): let config_string = - get_local_config_as_string(&vault_secret_annotation.destination_file, config_path)?; + get_local_config_as_string(&vault_secret_annotation.destination_file, config_path) + .map_err(|error| { + debug!("Error: {:?}", error); + CliError::DevConfigError(DevConfigError::InvalidSecretPath { + path: vault_secret_annotation.secret_name.clone(), + }) + })?; // Get only one key from hashmap - let remote_config = remote_secrets - .get(&vault_secret_annotation.secret_name) - .unwrap(); + let remote_config = match remote_secrets.get(&vault_secret_annotation.secret_name) { + Some(config) => config, + None => { + return Err(CliError::DevConfigError( + DevConfigError::InvalidSecretPath { + path: vault_secret_annotation.secret_name.clone(), + }, + )) + } + }; if has_diff(remote_config, &config_string) { updated_configs.insert(config_path.clone(), vault_secret_annotation.clone()); @@ -209,19 +223,9 @@ async fn select_config( }; } -fn get_available_files(path: &Path) -> Result, CliError> { - let path = path.try_exists().map(|value| match value { - true => match path.to_string_lossy() == "." { - true => current_dir(), - false => Ok(path.to_path_buf()), - }, - false => Err(std::io::Error::new( - ErrorKind::NotFound, - format!("path '{}' does not exist", path.to_string_lossy()), - )), - })??; - - let available_files = get_dev_config_files(&path); +fn get_available_files() -> Result, CliError> { + let current_path = current_dir()?; + let available_files = get_dev_config_files(¤t_path); Ok(available_files) } diff --git a/src/config/dev.exs b/src/config/dev.exs new file mode 100644 index 000000000..dea23d41f --- /dev/null +++ b/src/config/dev.exs @@ -0,0 +1,72 @@ +import Config + +# For development, we disable any cache and enable +# debugging and code reloading. +# +# The watchers configuration can be used to run external +# watchers to your application. For example, we use it +# with esbuild to bundle .js and .css sources. +config :wukong_api_proxy, WukongApiProxyWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. + # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. + http: [ip: {127, 0, 0, 1}, port: 4000], + check_origin: false, + code_reloader: true, + debug_errors: true, + secret_key_base: "f08E8/lkFpFQzpe6xLWhIdzOhZcFp0MSyfyfTxWLx+RssO2fqrvSSeXPbOqzzutM", + watchers: [] + +database = + System.get_env("POSTGRES_DATABASE") || "wukong_api_test#{System.get_env("MIX_TEST_PARTITION")}" + +database_hostname = System.get_env("POSTGRES_HOSTNAME") || "localhost" +database_port = System.get_env("POSTGRES_PORT") || 5432 +database_username = System.get_env("POSTGRES_USERNAME") || "postgres" +database_password = System.get_env("POSTGRES_PASSWORD") || "postgres" + +config :wukong_api_proxy, WukongApiProxy.Repo, + username: database_username, + password: database_password, + hostname: database_hostname, + port: database_port, + database: database, + show_sensitive_data_on_connection_error: true, + pool_size: 10 + +# ## SSL Support +# +# In order to use HTTPS in development, a self-signed +# certificate can be generated by running the following +# Mix task: +# +# mix phx.gen.cert +# +# Note that this task requires Erlang/OTP 20 or later. +# Run `mix help phx.gen.cert` for more information. +# +# The `http:` config above can be replaced with: +# +# https: [ +# port: 4001, +# cipher_suite: :strong, +# keyfile: "priv/cert/selfsigned_key.pem", +# certfile: "priv/cert/selfsigned.pem" +# ], +# +# If desired, both `http:` and `https:` keys can be +# configured to run both http and https servers on +# different ports. + +# Do not include metadata nor timestamps in development logs +config :logger, :console, format: "[$level] $message\n" + +# Set a higher stacktrace during development. Avoid configuring such +# in production as building large stacktraces may be expensive. +config :phoenix, :stacktrace_depth, 20 + +# Initialize plugs at runtime for faster development compilation +config :phoenix, :plug_init_mode, :runtime + +# Import development secrets +# wukong.mindvalley.dev/config-secrets-location: vault:secret/wukong-cli/sandboxes#dev.secrets.exs +import_config("dev.secrets.exs") diff --git a/src/config/dev.secrets.exs b/src/config/dev.secrets.exs new file mode 100644 index 000000000..6caf14fd6 --- /dev/null +++ b/src/config/dev.secrets.exs @@ -0,0 +1,28 @@ +use Mix.Config + +# Configure your database. +config :academy, Academy.Repo, + adapter: Ecto.Adapters.Postgres, + username: "postgres", + password: "", + database: "academy_core_dev", + hostname: "localhosts", + pool_size: 10 + +# Play store. +config :academy, :play_store, + public_key: + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApcjVcosS6VWUPwDBo6640p9djX6PnLicsKvRF11UQlPL2oKClAvHmY10FqAFVa7FbFcMqJloq3H/bQPHfNnZxelYruiFAlG1C51sDEo244AvMn2Frto9g86uGTAGETywKAPkPffiMltgezmpNwJy1Q4hfLrmxZnmUPcdg98+pElnsdR7ev3uspFIYB12kPo0yDuJsEJ8AhmVJGocE2jp6C3rnrcbyosYxcknoJyFXP/MDE7MP1fhWDLk3Mw3Vy8YilTkHuxPeR6id7/00Rprgs57jkLSgBvkCG+qdLpJhYId8QsonrW5VI34JHQ4aYahwRFbznOzPkkwK4K9dQP5gQIDAQAB" + +# Get this service key to ensure that asset uploading is working. +config :academy, :fineuploader, + key: "", + secret: "", + bucket: "", + s3endpoint: "s3-accelerate.amazonaws.com", + upload_dir: "tmp/", + notify_url: "" + +# ??? +config :receipt_verifier, + shared_secret: "" diff --git a/src/error.rs b/src/error.rs index b42c3ac03..bd7a3efc6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,6 +23,8 @@ pub enum CliError { DeploymentError(#[from] DeploymentError), #[error(transparent)] VaultError(#[from] VaultError), + #[error(transparent)] + DevConfigError(#[from] DevConfigError), } #[derive(Debug, ThisError)] @@ -63,6 +65,19 @@ pub enum APIError { Timeout { domain: String }, } +#[derive(Debug, ThisError)] +pub enum DevConfigError { + #[error("No config files found!")] + ConfigNotFound, + #[error( + "The config file is already up to date with the Vault Bunker. There are no changes to push." + )] + UpToDateError, + // Invalid secret path in the annotation in config file: + #[error("Invalid secret path in the config file")] + InvalidSecretPath { path: String }, +} + #[derive(Debug, ThisError)] pub enum ConfigError { #[error("Config file not found at \"{path}\".")] @@ -145,6 +160,15 @@ If none of the above steps work for you, please contact the following people on ), _ => None, }, + CliError::DevConfigError(error) => match error { + DevConfigError::ConfigNotFound => Some( + "Run \"wukong config dev pull\" to pull the latest dev config.".to_string() + ), + DevConfigError::InvalidSecretPath { path } => Some(format!( + "Please check the secret path in the config file: config/{path}" + )), + _ => None, + }, _ => None, } } From 6a92bc4545171e936c9b4a22c32604afe8199f12 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 06:44:33 +0000 Subject: [PATCH 36/43] reverted config file --- src/config/dev.exs | 72 -------------------------------------- src/config/dev.secrets.exs | 28 --------------- 2 files changed, 100 deletions(-) delete mode 100644 src/config/dev.exs delete mode 100644 src/config/dev.secrets.exs diff --git a/src/config/dev.exs b/src/config/dev.exs deleted file mode 100644 index dea23d41f..000000000 --- a/src/config/dev.exs +++ /dev/null @@ -1,72 +0,0 @@ -import Config - -# For development, we disable any cache and enable -# debugging and code reloading. -# -# The watchers configuration can be used to run external -# watchers to your application. For example, we use it -# with esbuild to bundle .js and .css sources. -config :wukong_api_proxy, WukongApiProxyWeb.Endpoint, - # Binding to loopback ipv4 address prevents access from other machines. - # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. - http: [ip: {127, 0, 0, 1}, port: 4000], - check_origin: false, - code_reloader: true, - debug_errors: true, - secret_key_base: "f08E8/lkFpFQzpe6xLWhIdzOhZcFp0MSyfyfTxWLx+RssO2fqrvSSeXPbOqzzutM", - watchers: [] - -database = - System.get_env("POSTGRES_DATABASE") || "wukong_api_test#{System.get_env("MIX_TEST_PARTITION")}" - -database_hostname = System.get_env("POSTGRES_HOSTNAME") || "localhost" -database_port = System.get_env("POSTGRES_PORT") || 5432 -database_username = System.get_env("POSTGRES_USERNAME") || "postgres" -database_password = System.get_env("POSTGRES_PASSWORD") || "postgres" - -config :wukong_api_proxy, WukongApiProxy.Repo, - username: database_username, - password: database_password, - hostname: database_hostname, - port: database_port, - database: database, - show_sensitive_data_on_connection_error: true, - pool_size: 10 - -# ## SSL Support -# -# In order to use HTTPS in development, a self-signed -# certificate can be generated by running the following -# Mix task: -# -# mix phx.gen.cert -# -# Note that this task requires Erlang/OTP 20 or later. -# Run `mix help phx.gen.cert` for more information. -# -# The `http:` config above can be replaced with: -# -# https: [ -# port: 4001, -# cipher_suite: :strong, -# keyfile: "priv/cert/selfsigned_key.pem", -# certfile: "priv/cert/selfsigned.pem" -# ], -# -# If desired, both `http:` and `https:` keys can be -# configured to run both http and https servers on -# different ports. - -# Do not include metadata nor timestamps in development logs -config :logger, :console, format: "[$level] $message\n" - -# Set a higher stacktrace during development. Avoid configuring such -# in production as building large stacktraces may be expensive. -config :phoenix, :stacktrace_depth, 20 - -# Initialize plugs at runtime for faster development compilation -config :phoenix, :plug_init_mode, :runtime - -# Import development secrets -# wukong.mindvalley.dev/config-secrets-location: vault:secret/wukong-cli/sandboxes#dev.secrets.exs -import_config("dev.secrets.exs") diff --git a/src/config/dev.secrets.exs b/src/config/dev.secrets.exs deleted file mode 100644 index 6caf14fd6..000000000 --- a/src/config/dev.secrets.exs +++ /dev/null @@ -1,28 +0,0 @@ -use Mix.Config - -# Configure your database. -config :academy, Academy.Repo, - adapter: Ecto.Adapters.Postgres, - username: "postgres", - password: "", - database: "academy_core_dev", - hostname: "localhosts", - pool_size: 10 - -# Play store. -config :academy, :play_store, - public_key: - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApcjVcosS6VWUPwDBo6640p9djX6PnLicsKvRF11UQlPL2oKClAvHmY10FqAFVa7FbFcMqJloq3H/bQPHfNnZxelYruiFAlG1C51sDEo244AvMn2Frto9g86uGTAGETywKAPkPffiMltgezmpNwJy1Q4hfLrmxZnmUPcdg98+pElnsdR7ev3uspFIYB12kPo0yDuJsEJ8AhmVJGocE2jp6C3rnrcbyosYxcknoJyFXP/MDE7MP1fhWDLk3Mw3Vy8YilTkHuxPeR6id7/00Rprgs57jkLSgBvkCG+qdLpJhYId8QsonrW5VI34JHQ4aYahwRFbznOzPkkwK4K9dQP5gQIDAQAB" - -# Get this service key to ensure that asset uploading is working. -config :academy, :fineuploader, - key: "", - secret: "", - bucket: "", - s3endpoint: "s3-accelerate.amazonaws.com", - upload_dir: "tmp/", - notify_url: "" - -# ??? -config :receipt_verifier, - shared_secret: "" From 3426fd00d01116b85e2b8ba78bfcf6a3d8692472 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 06:50:56 +0000 Subject: [PATCH 37/43] fix: updated config code to throw error if dev secret not found --- src/commands/dev/config/push.rs | 4 +--- src/error.rs | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 0573158a9..3d7616028 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -90,9 +90,7 @@ async fn get_updated_configs( get_local_config_as_string(&vault_secret_annotation.destination_file, config_path) .map_err(|error| { debug!("Error: {:?}", error); - CliError::DevConfigError(DevConfigError::InvalidSecretPath { - path: vault_secret_annotation.secret_name.clone(), - }) + CliError::DevConfigError(DevConfigError::ConfigSecretNotFound) })?; // Get only one key from hashmap diff --git a/src/error.rs b/src/error.rs index bd7a3efc6..3b3b7a6ac 100644 --- a/src/error.rs +++ b/src/error.rs @@ -69,6 +69,8 @@ pub enum APIError { pub enum DevConfigError { #[error("No config files found!")] ConfigNotFound, + #[error("No dev secret config files found!")] + ConfigSecretNotFound, #[error( "The config file is already up to date with the Vault Bunker. There are no changes to push." )] @@ -161,7 +163,7 @@ If none of the above steps work for you, please contact the following people on _ => None, }, CliError::DevConfigError(error) => match error { - DevConfigError::ConfigNotFound => Some( + DevConfigError::ConfigSecretNotFound => Some( "Run \"wukong config dev pull\" to pull the latest dev config.".to_string() ), DevConfigError::InvalidSecretPath { path } => Some(format!( From a2d8dc80bbd084a6626f8dc6c723923a982a3c07 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 07:05:31 +0000 Subject: [PATCH 38/43] test: updated test snapshots --- completions/bash/wukong.bash | 2 +- completions/zsh/_wukong | 1 - tests/snapshots/completion__wukong_completion_bash.snap | 2 +- tests/snapshots/completion__wukong_completion_zsh.snap | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/completions/bash/wukong.bash b/completions/bash/wukong.bash index 2bdd4de6f..63a7a9af5 100644 --- a/completions/bash/wukong.bash +++ b/completions/bash/wukong.bash @@ -834,7 +834,7 @@ _wukong() { return 0 ;; wukong__dev__config__push) - opts="-a -v -q -h --application --verbose --quiet --help [PATH]" + opts="-a -v -q -h --application --verbose --quiet --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/zsh/_wukong b/completions/zsh/_wukong index 7c137577f..43b5c7271 100644 --- a/completions/zsh/_wukong +++ b/completions/zsh/_wukong @@ -578,7 +578,6 @@ By default, it'\''ll only report errors. '(-v --verbose)*--quiet[Do not print log message]' \ '-h[Print help]' \ '--help[Print help]' \ -'::path -- The path to the project:_files' \ && ret=0 ;; (help) diff --git a/tests/snapshots/completion__wukong_completion_bash.snap b/tests/snapshots/completion__wukong_completion_bash.snap index e66ae5ff2..4c2db4c4f 100644 --- a/tests/snapshots/completion__wukong_completion_bash.snap +++ b/tests/snapshots/completion__wukong_completion_bash.snap @@ -838,7 +838,7 @@ _wukong() { return 0 ;; wukong__dev__config__push) - opts="-a -v -q -h --application --verbose --quiet --help [PATH]" + opts="-a -v -q -h --application --verbose --quiet --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/tests/snapshots/completion__wukong_completion_zsh.snap b/tests/snapshots/completion__wukong_completion_zsh.snap index b3fd60d1e..ab3b1ca29 100644 --- a/tests/snapshots/completion__wukong_completion_zsh.snap +++ b/tests/snapshots/completion__wukong_completion_zsh.snap @@ -582,7 +582,6 @@ By default, it'\''ll only report errors. '(-v --verbose)*--quiet[Do not print log message]' \ '-h[Print help]' \ '--help[Print help]' \ -'::path -- The path to the project:_files' \ && ret=0 ;; (help) From c4c6d9d94416f131360f0dcf0119c3af002e3c43 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 07:45:09 +0000 Subject: [PATCH 39/43] style: change upto date error to a simple println --- src/commands/dev/config/push.rs | 4 +++- src/error.rs | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 3d7616028..3e0f383c3 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -44,7 +44,9 @@ pub async fn handle_config_push() -> Result { let updated_configs = get_updated_configs(&vault, &vault_token, &config_files).await?; if updated_configs.is_empty() { - return Err(CliError::DevConfigError(DevConfigError::UpToDateError)); + println!( + "The config file is already up to date with the Vault Bunker. There are no changes to push." + ); } if updated_configs.len() == 1 { diff --git a/src/error.rs b/src/error.rs index 3b3b7a6ac..4b5047ff9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -71,10 +71,6 @@ pub enum DevConfigError { ConfigNotFound, #[error("No dev secret config files found!")] ConfigSecretNotFound, - #[error( - "The config file is already up to date with the Vault Bunker. There are no changes to push." - )] - UpToDateError, // Invalid secret path in the annotation in config file: #[error("Invalid secret path in the config file")] InvalidSecretPath { path: String }, From ce4e54b5831fa53720e39cdfc9d3eb71c841d116 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 08:32:51 +0000 Subject: [PATCH 40/43] fix: updated error path to show config path instead of secret path --- src/commands/dev/config/push.rs | 53 +++++++++------------------------ src/error.rs | 6 ++-- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 3e0f383c3..e3be10d36 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -47,6 +47,8 @@ pub async fn handle_config_push() -> Result { println!( "The config file is already up to date with the Vault Bunker. There are no changes to push." ); + + return Ok(true); } if updated_configs.len() == 1 { @@ -87,7 +89,6 @@ async fn get_updated_configs( .await? .data; - // Handle and throw InvalidSecretPath if No such file or directory (os error 2): let config_string = get_local_config_as_string(&vault_secret_annotation.destination_file, config_path) .map_err(|error| { @@ -99,11 +100,11 @@ async fn get_updated_configs( let remote_config = match remote_secrets.get(&vault_secret_annotation.secret_name) { Some(config) => config, None => { + let test = remove_parent_directories(&config_path); + return Err(CliError::DevConfigError( - DevConfigError::InvalidSecretPath { - path: vault_secret_annotation.secret_name.clone(), - }, - )) + DevConfigError::InvalidSecretPath { config_path: test }, + )); } }; @@ -293,13 +294,15 @@ fn print_diff(old_secret_config: &str, new_secret_config: &str, secret_path: &st } fn remove_parent_directories(path: &str) -> String { - let file = Path::new(path); - file.components() - .filter(|component| component.as_os_str() != "..") - .collect::() - .to_str() + let current_dir = current_dir().unwrap(); + let path = Path::new(path); + + path.strip_prefix(current_dir) + .map(|p| p.to_owned()) + .unwrap_or(path.to_owned()) + .into_os_string() + .into_string() .unwrap() - .to_string() } fn get_dev_config_files(path: &Path) -> Vec { @@ -320,34 +323,6 @@ fn get_dev_config_files(path: &Path) -> Vec { mod test { use super::*; - #[test] - fn test_empty_string() { - let path = ""; - let result = remove_parent_directories(path); - assert_eq!(result, ""); - } - - #[test] - fn test_no_parent_directories() { - let path = "dir1/dir2/file.txt"; - let result = remove_parent_directories(path); - assert_eq!(result, "dir1/dir2/file.txt"); - } - - #[test] - fn test_single_parent_directory() { - let path = "dir1/../dir2/file.txt"; - let result = remove_parent_directories(path); - assert_eq!(result, "dir1/dir2/file.txt"); - } - - #[test] - fn test_invalid_characters() { - let path = "dir1/inv@lid/../dir2/file.txt"; - let result = remove_parent_directories(path); - assert_eq!(result, "dir1/inv@lid/dir2/file.txt"); - } - #[test] fn test_non_existent_file() { let non_existent_path = "non_existent_file.txt"; diff --git a/src/error.rs b/src/error.rs index 4b5047ff9..234099d1f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -73,7 +73,7 @@ pub enum DevConfigError { ConfigSecretNotFound, // Invalid secret path in the annotation in config file: #[error("Invalid secret path in the config file")] - InvalidSecretPath { path: String }, + InvalidSecretPath { config_path: String }, } #[derive(Debug, ThisError)] @@ -162,8 +162,8 @@ If none of the above steps work for you, please contact the following people on DevConfigError::ConfigSecretNotFound => Some( "Run \"wukong config dev pull\" to pull the latest dev config.".to_string() ), - DevConfigError::InvalidSecretPath { path } => Some(format!( - "Please check the secret path in the config file: config/{path}" + DevConfigError::InvalidSecretPath { config_path } => Some(format!( + "Please check the secret path in the config file: {config_path}" )), _ => None, }, From 5d7a6ca771c42d25f96d7450632a574bf1cbacb0 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 08:38:05 +0000 Subject: [PATCH 41/43] test: updated test cases for remove_parent_directories function --- src/commands/dev/config/push.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index e3be10d36..6f9114362 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -324,10 +324,25 @@ mod test { use super::*; #[test] - fn test_non_existent_file() { - let non_existent_path = "non_existent_file.txt"; - - let result = get_local_config_as_string("destination_file", non_existent_path); - assert!(result.is_err()); + fn test_remove_parent_directories() { + let current_dir = std::env::current_dir().unwrap(); + + let path = current_dir.join("some_directory/some_file.txt"); + let input = path.to_str().unwrap(); + let expected_output = "some_directory/some_file.txt"; + assert_eq!(remove_parent_directories(input), expected_output); + + let path = current_dir.join("another_directory/another_file.txt"); + let input = path.to_str().unwrap(); + let expected_output = "another_directory/another_file.txt"; + assert_eq!(remove_parent_directories(input), expected_output); + + let input = "/absolute/path/to/some/file.txt"; + let expected_output = "/absolute/path/to/some/file.txt"; + assert_eq!(remove_parent_directories(input), expected_output); + + let input = "relative/path/to/some/file.txt"; + let expected_output = "relative/path/to/some/file.txt"; + assert_eq!(remove_parent_directories(input), expected_output); } } From 38714f362a3c11ffd9a701626757492fcb564d78 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 08:46:01 +0000 Subject: [PATCH 42/43] fix: reverted tmp tested variable --- src/commands/dev/config/push.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 6f9114362..1ce91e9ba 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -100,10 +100,10 @@ async fn get_updated_configs( let remote_config = match remote_secrets.get(&vault_secret_annotation.secret_name) { Some(config) => config, None => { - let test = remove_parent_directories(&config_path); - return Err(CliError::DevConfigError( - DevConfigError::InvalidSecretPath { config_path: test }, + DevConfigError::InvalidSecretPath { + config_path: remove_parent_directories(&config_path), + }, )); } }; From 62d17485cd3fbd6e63f17679aa7fab1743fb5e90 Mon Sep 17 00:00:00 2001 From: Mohamed Fauzaan Date: Thu, 6 Apr 2023 08:46:29 +0000 Subject: [PATCH 43/43] style: fix clippy --- src/commands/dev/config/push.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/dev/config/push.rs b/src/commands/dev/config/push.rs index 1ce91e9ba..326dc237d 100644 --- a/src/commands/dev/config/push.rs +++ b/src/commands/dev/config/push.rs @@ -102,7 +102,7 @@ async fn get_updated_configs( None => { return Err(CliError::DevConfigError( DevConfigError::InvalidSecretPath { - config_path: remove_parent_directories(&config_path), + config_path: remove_parent_directories(config_path), }, )); }