From b2cde4c0550dba2ad2ec7632d0cdeca01396e2d0 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Fri, 11 Oct 2024 17:22:43 +0200 Subject: [PATCH 01/17] Also use environment variable service for comparison. Add dry run mode --- src/clap_app.rs | 3 ++- src/clap_models.rs | 4 ++++ src/models.rs | 28 ++++++++++++++++++++++-- src/variables.rs | 54 +++++++++++++++++++++++++++++----------------- 4 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/clap_app.rs b/src/clap_app.rs index fb60fce..7ce79d1 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -71,7 +71,8 @@ pub async fn init_cli() { "🚀 Patching environment variables from input file {}\n", input ); - set_env_vars_from_file(input, &mut cm_client, cli.ci_mode).await; + set_env_vars_from_file(input, &mut cm_client, cli.ci_mode, cli.dry_run_mode) + .await; process::exit(0); } } diff --git a/src/clap_models.rs b/src/clap_models.rs index 46e7c89..c608f9b 100644 --- a/src/clap_models.rs +++ b/src/clap_models.rs @@ -35,6 +35,10 @@ pub struct Cli { #[clap(long = "ci", global = true, action = ArgAction::SetTrue )] pub ci_mode: bool, + /// Only log but to not apply any changes + #[clap(long = "dry-run", global = true, action = ArgAction::SetTrue )] + pub dry_run_mode: bool, + #[clap(subcommand)] pub command: Option, } diff --git a/src/models.rs b/src/models.rs index e73e8b7..c5d7f5f 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,5 +1,6 @@ use chrono::NaiveDate; use serde::{Deserialize, Serialize}; +use std::fmt; use strum_macros::{EnumString, IntoStaticStr}; // Common models used across multiple modules @@ -49,8 +50,8 @@ pub struct Variable { pub value: Option, #[serde(rename(deserialize = "type", serialize = "type"))] pub variable_type: VariableType, - #[serde(skip_serializing_if = "Option::is_none")] - pub service: Option, + #[serde(default = "VariableServiceType::all")] + pub service: VariableServiceType, #[serde(skip_serializing_if = "Option::is_none")] pub status: Option, } @@ -63,6 +64,29 @@ pub enum VariableType { SecretString, } +/// Possible types that a service can have +#[derive(Clone, Debug, Deserialize, Serialize, IntoStaticStr, EnumString, PartialEq, Eq)] +#[strum(serialize_all = "lowercase")] +#[serde(rename_all = "lowercase")] +pub enum VariableServiceType { + All, + Author, + Publish, + Preview, +} + +impl fmt::Display for VariableServiceType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}", format!("{:?}", self).to_lowercase()) + } +} + +impl VariableServiceType { + fn all() -> Self { + VariableServiceType::All + } +} + /// Model for the necessary JWT claims to retrieve an Adobe access token #[derive(Deserialize, Serialize)] pub struct JwtClaims { diff --git a/src/variables.rs b/src/variables.rs index 1e6e876..6dfa04d 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -11,10 +11,10 @@ use std::process; use std::thread::sleep; use std::time::Duration; -// Make variables comparable - if they have the same name, they are the same. +// Make variables comparable - if they have the same name and same service they are equal. impl PartialEq for Variable { fn eq(&self, other: &Self) -> bool { - self.name == other.name + self.name == other.name && self.service == other.service } } @@ -103,6 +103,7 @@ pub async fn set_env_vars_from_file( file_path: &str, client: &mut CloudManagerClient, ci_mode: bool, + dry_run: bool, ) { let input = std::fs::read_to_string(file_path).expect("Unable to read file"); let input: YamlConfig = serde_yaml::from_str(input.as_str()).unwrap_or_else(|err| { @@ -190,31 +191,44 @@ pub async fn set_env_vars_from_file( for vf in &vars_final { match vf.value { None => { - println!("{:>8} DELETING '{}'", "✍", vf.name); + println!( + "{:>8} DELETING '{}', service: {}", + "✍", vf.name, vf.service + ); } Some(_) => { - println!("{:>8} UPDATING '{}'", "✍", vf.name) + println!( + "{:>8} UPDATING '{}', service: {}", + "✍", vf.name, vf.service + ) } } } - match set_env_vars(client, p.id, e.id, &vars_final).await { - Ok(status) => match status { - StatusCode::NO_CONTENT => { - println!("{:>8} Success", "✔"); - } - _ => { - eprintln!( - "{:>8} {}", - "Error, check output above".red(), - "❌".red() - ); - process::exit(2); + if dry_run { + println!( + "{:>8} --dry-run detected. Not performing any actions.", + "⚠️", + ); + } else { + match set_env_vars(client, p.id, e.id, &vars_final).await { + Ok(status) => match status { + StatusCode::NO_CONTENT => { + println!("{:>8} Success", "✔"); + } + _ => { + eprintln!( + "{:>8} {}", + "Error, check output above".red(), + "❌".red() + ); + process::exit(2); + } + }, + Err(error) => { + eprintln!("{} {}", "❌ API error: ".red().bold(), error); + process::exit(1); } - }, - Err(error) => { - eprintln!("{} {}", "❌ API error: ".red().bold(), error); - process::exit(1); } } break '_retry; From 1feb285eb9eefa22f58f8a1969047ec08e38aab2 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Fri, 11 Oct 2024 20:31:48 +0200 Subject: [PATCH 02/17] * Add specific models for environment and pipelines variables * add dry run mode pipeline vars * ensure default service value is not serialized for env-vars * ensure that service type of pipeline variables is also evaluated in PartialEq --- src/clap_app.rs | 2 +- src/models.rs | 77 ++++++++++++++++++++++++++++++++++++---------- src/variables.rs | 80 ++++++++++++++++++++++++++++-------------------- 3 files changed, 109 insertions(+), 50 deletions(-) diff --git a/src/clap_app.rs b/src/clap_app.rs index 7ce79d1..77505cc 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -207,7 +207,7 @@ pub async fn init_cli() { { if let PipelineVarsCommands::Set { input } = &pipeline_vars_command { println!("🚀 Patching pipeline variables from input file {}\n", input); - set_pipeline_vars_from_file(input, &mut cm_client, cli.ci_mode).await; + set_pipeline_vars_from_file(input, &mut cm_client, cli.ci_mode, cli.dry_run_mode).await; process::exit(0); } } diff --git a/src/models.rs b/src/models.rs index c5d7f5f..c09377b 100644 --- a/src/models.rs +++ b/src/models.rs @@ -31,7 +31,7 @@ pub struct DomainConfig { #[derive(Debug, Deserialize, Serialize)] pub struct EnvironmentsConfig { pub id: u32, - pub variables: Vec, + pub variables: Vec, pub domains: Option>, } @@ -39,21 +39,31 @@ pub struct EnvironmentsConfig { #[derive(Debug, Deserialize, Serialize)] pub struct PipelinesConfig { pub id: u32, - pub variables: Vec, + pub variables: Vec, } /// Model for all information about a Cloud Manager environment variable #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Variable { +pub struct PipelineVariable { pub name: String, #[serde(skip_serializing_if = "Option::is_none")] pub value: Option, #[serde(rename(deserialize = "type", serialize = "type"))] pub variable_type: VariableType, - #[serde(default = "VariableServiceType::all")] - pub service: VariableServiceType, + #[serde(default = "PipelineVariableServiceType::default")] + pub service: PipelineVariableServiceType +} + +/// Model for all information about a Cloud Manager environment variable +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EnvironmentVariable { + pub name: String, #[serde(skip_serializing_if = "Option::is_none")] - pub status: Option, + pub value: Option, + #[serde(rename(deserialize = "type", serialize = "type"))] + pub variable_type: VariableType, + #[serde(default = "EnvironmentVariableServiceType::default", skip_serializing_if = "env_var_service_type_is_default")] + pub service: EnvironmentVariableServiceType } /// Possible types that a variable can have @@ -64,26 +74,48 @@ pub enum VariableType { SecretString, } -/// Possible types that a service can have +/// Possible service types that an environment variable can have #[derive(Clone, Debug, Deserialize, Serialize, IntoStaticStr, EnumString, PartialEq, Eq)] #[strum(serialize_all = "lowercase")] #[serde(rename_all = "lowercase")] -pub enum VariableServiceType { +pub enum EnvironmentVariableServiceType { All, Author, Publish, Preview, } -impl fmt::Display for VariableServiceType { +impl fmt::Display for EnvironmentVariableServiceType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}", format!("{:?}", self).to_lowercase()) + } +} +fn env_var_service_type_is_default(t: &EnvironmentVariableServiceType) -> bool { + *t == EnvironmentVariableServiceType::All +} + +impl EnvironmentVariableServiceType { + fn default() -> Self { + EnvironmentVariableServiceType::All + } +} +/// Possible service types that an environment variable can have +#[derive(Clone, Debug, Deserialize, Serialize, IntoStaticStr, EnumString, PartialEq, Eq)] +#[strum(serialize_all = "lowercase")] +#[serde(rename_all = "lowercase")] +pub enum PipelineVariableServiceType { + Build, +} + +impl fmt::Display for crate::models::PipelineVariableServiceType { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "{}", format!("{:?}", self).to_lowercase()) } } -impl VariableServiceType { - fn all() -> Self { - VariableServiceType::All +impl PipelineVariableServiceType { + fn default() -> Self { + PipelineVariableServiceType::Build } } @@ -163,15 +195,28 @@ pub struct Environment { /// Struct to serialize the response of requesting /api/program/{id}/environment/{id}/variables #[derive(Debug, Deserialize, Serialize)] -pub struct VariablesResponse { +pub struct EnvironmentVariablesResponse { + #[serde(rename(deserialize = "_embedded", serialize = "_embedded"))] + pub variables_list: EnvironmentVariablesList, +} + +/// Struct to serialize the response of requesting /api/program/{id}/environment/{id}/variables +#[derive(Debug, Deserialize, Serialize)] +pub struct PipelineVariablesResponse { #[serde(rename(deserialize = "_embedded", serialize = "_embedded"))] - pub variables_list: VariablesList, + pub variables_list: PipelineVariablesList, +} + +/// Struct that holds a list of variables +#[derive(Debug, Deserialize, Serialize)] +pub struct EnvironmentVariablesList { + pub variables: Vec, } /// Struct that holds a list of variables #[derive(Debug, Deserialize, Serialize)] -pub struct VariablesList { - pub variables: Vec, +pub struct PipelineVariablesList { + pub variables: Vec, } // Models for representing Cloud Manager pipelines and descendant objects diff --git a/src/variables.rs b/src/variables.rs index 6dfa04d..84db5f9 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -2,7 +2,7 @@ use crate::client::{AdobeConnector, CloudManagerClient}; use crate::encryption::decrypt; use crate::environments::get_environment; use crate::errors::throw_adobe_api_error; -use crate::models::{Variable, VariableType, VariablesList, VariablesResponse, YamlConfig}; +use crate::models::{EnvironmentVariable, PipelineVariable, VariableType, EnvironmentVariablesList, EnvironmentVariablesResponse, YamlConfig, PipelineVariablesList, PipelineVariablesResponse}; use crate::pipelines::get_pipeline; use crate::HOST_NAME; use colored::*; @@ -11,8 +11,15 @@ use std::process; use std::thread::sleep; use std::time::Duration; -// Make variables comparable - if they have the same name and same service they are equal. -impl PartialEq for Variable { +// Make environment variables comparable - if they have the same name and same service they are equal. +impl PartialEq for EnvironmentVariable { + fn eq(&self, other: &Self) -> bool { + self.name == other.name && self.service == other.service + } +} + +// Make pipeline variables comparable - if they have the same name they are equal. +impl PartialEq for PipelineVariable { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.service == other.service } @@ -35,7 +42,7 @@ pub async fn get_env_vars( client: &mut CloudManagerClient, program_id: u32, env_id: u32, -) -> Result { +) -> Result { let request_path = format!( "{}/api/program/{}/environment/{}/variables", HOST_NAME, program_id, env_id @@ -45,7 +52,7 @@ pub async fn get_env_vars( .await? .text() .await?; - let variables: VariablesResponse = + let variables: EnvironmentVariablesResponse = serde_json::from_str(response.as_str()).unwrap_or_else(|_| { throw_adobe_api_error(response); process::exit(1); @@ -71,7 +78,7 @@ pub async fn set_env_vars( client: &mut CloudManagerClient, program_id: u32, env_id: u32, - variables: &[Variable], + variables: &[EnvironmentVariable], ) -> Result { let request_path = format!( "{}/api/program/{}/environment/{}/variables", @@ -125,7 +132,7 @@ pub async fn set_env_vars_from_file( // The vector that holds the final variables that will be set or deleted. Will be constructed // by comparing the variables that are currently set in Cloud Manager and those in the local // YAML config file. - let mut vars_final: Vec = vec![]; + let mut vars_final: Vec = vec![]; // Check if the targeted environment is ready '_retry: loop { @@ -177,12 +184,11 @@ pub async fn set_env_vars_from_file( let vars_cloud = get_env_vars(client, p.id, e.id).await.unwrap().variables; for vc in vars_cloud { if !vars_yaml.clone().contains(&vc) { - let variable_to_be_deleted = Variable { + let variable_to_be_deleted = EnvironmentVariable { name: vc.name, value: None, variable_type: vc.variable_type, - service: vc.service, - status: None, + service: vc.service }; vars_final.push(variable_to_be_deleted); } @@ -263,7 +269,7 @@ pub async fn get_pipeline_vars( client: &mut CloudManagerClient, program_id: u32, pipeline_id: &u32, -) -> Result { +) -> Result { let request_path = format!( "{}/api/program/{}/pipeline/{}/variables", HOST_NAME, program_id, pipeline_id @@ -273,7 +279,7 @@ pub async fn get_pipeline_vars( .await? .text() .await?; - let variables: VariablesResponse = + let variables: PipelineVariablesResponse = serde_json::from_str(response.as_str()).unwrap_or_else(|_| { throw_adobe_api_error(response); process::exit(1); @@ -299,7 +305,7 @@ pub async fn set_pipeline_vars( client: &mut CloudManagerClient, program_id: u32, pipeline_id: u32, - variables: &[Variable], + variables: &[PipelineVariable], ) -> Result { let request_path = format!( "{}/api/program/{}/pipeline/{}/variables", @@ -331,6 +337,7 @@ pub async fn set_pipeline_vars_from_file( file_path: &str, client: &mut CloudManagerClient, ci_mode: bool, + dry_run: bool, ) { let input = std::fs::read_to_string(file_path).expect("Unable to read file"); let input: YamlConfig = serde_yaml::from_str(input.as_str()).unwrap_or_else(|err| { @@ -352,7 +359,7 @@ pub async fn set_pipeline_vars_from_file( // The vector that holds the final variables that will be set or deleted. Will be constructed // by comparing the variables that are currently set in Cloud Manager and those in the local // YAML config file. - let mut vars_final: Vec = vec![]; + let mut vars_final: Vec = vec![]; // Check if the targeted environment is ready '_retry: loop { @@ -407,12 +414,11 @@ pub async fn set_pipeline_vars_from_file( .variables; for vc in vars_cloud { if !vars_yaml.clone().contains(&vc) { - let variable_to_be_deleted = Variable { + let variable_to_be_deleted = PipelineVariable { name: vc.name, value: None, variable_type: vc.variable_type, - service: vc.service, - status: None, + service: vc.service }; vars_final.push(variable_to_be_deleted); } @@ -429,25 +435,33 @@ pub async fn set_pipeline_vars_from_file( } } - match set_pipeline_vars(client, p.id, l.id, &vars_final).await { - Ok(status) => match status { - StatusCode::NO_CONTENT => { - println!("{:>8} Success", "✔"); - } - _ => { - eprintln!( - "{:>8} {}", - "Error, check output above".red(), - "❌".red() - ); - process::exit(2); + if dry_run { + println!( + "{:>8} --dry-run detected. Not performing any actions.", + "⚠️", + ); + } else { + match set_pipeline_vars(client, p.id, l.id, &vars_final).await { + Ok(status) => match status { + StatusCode::NO_CONTENT => { + println!("{:>8} Success", "✔"); + } + _ => { + eprintln!( + "{:>8} {}", + "Error, check output above".red(), + "❌".red() + ); + process::exit(2); + } + }, + Err(error) => { + eprintln!("{} {}", "❌ API error: ".red().bold(), error); + process::exit(1); } - }, - Err(error) => { - eprintln!("{} {}", "❌ API error: ".red().bold(), error); - process::exit(1); } } + break '_retry; } } From e0c44b368a747c521cb3ea5736fda379dd9ce225 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Fri, 11 Oct 2024 20:40:10 +0200 Subject: [PATCH 03/17] Update formatting --- src/clap_app.rs | 8 +++++++- src/models.rs | 9 ++++++--- src/variables.rs | 17 ++++++++++------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/clap_app.rs b/src/clap_app.rs index 77505cc..8c08c03 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -207,7 +207,13 @@ pub async fn init_cli() { { if let PipelineVarsCommands::Set { input } = &pipeline_vars_command { println!("🚀 Patching pipeline variables from input file {}\n", input); - set_pipeline_vars_from_file(input, &mut cm_client, cli.ci_mode, cli.dry_run_mode).await; + set_pipeline_vars_from_file( + input, + &mut cm_client, + cli.ci_mode, + cli.dry_run_mode, + ) + .await; process::exit(0); } } diff --git a/src/models.rs b/src/models.rs index c09377b..b1d6c0f 100644 --- a/src/models.rs +++ b/src/models.rs @@ -51,7 +51,7 @@ pub struct PipelineVariable { #[serde(rename(deserialize = "type", serialize = "type"))] pub variable_type: VariableType, #[serde(default = "PipelineVariableServiceType::default")] - pub service: PipelineVariableServiceType + pub service: PipelineVariableServiceType, } /// Model for all information about a Cloud Manager environment variable @@ -62,8 +62,11 @@ pub struct EnvironmentVariable { pub value: Option, #[serde(rename(deserialize = "type", serialize = "type"))] pub variable_type: VariableType, - #[serde(default = "EnvironmentVariableServiceType::default", skip_serializing_if = "env_var_service_type_is_default")] - pub service: EnvironmentVariableServiceType + #[serde( + default = "EnvironmentVariableServiceType::default", + skip_serializing_if = "env_var_service_type_is_default" + )] + pub service: EnvironmentVariableServiceType, } /// Possible types that a variable can have diff --git a/src/variables.rs b/src/variables.rs index 84db5f9..b940a9d 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -2,7 +2,10 @@ use crate::client::{AdobeConnector, CloudManagerClient}; use crate::encryption::decrypt; use crate::environments::get_environment; use crate::errors::throw_adobe_api_error; -use crate::models::{EnvironmentVariable, PipelineVariable, VariableType, EnvironmentVariablesList, EnvironmentVariablesResponse, YamlConfig, PipelineVariablesList, PipelineVariablesResponse}; +use crate::models::{ + EnvironmentVariable, EnvironmentVariablesList, EnvironmentVariablesResponse, PipelineVariable, + PipelineVariablesList, PipelineVariablesResponse, VariableType, YamlConfig, +}; use crate::pipelines::get_pipeline; use crate::HOST_NAME; use colored::*; @@ -52,8 +55,8 @@ pub async fn get_env_vars( .await? .text() .await?; - let variables: EnvironmentVariablesResponse = - serde_json::from_str(response.as_str()).unwrap_or_else(|_| { + let variables: EnvironmentVariablesResponse = serde_json::from_str(response.as_str()) + .unwrap_or_else(|_| { throw_adobe_api_error(response); process::exit(1); }); @@ -188,7 +191,7 @@ pub async fn set_env_vars_from_file( name: vc.name, value: None, variable_type: vc.variable_type, - service: vc.service + service: vc.service, }; vars_final.push(variable_to_be_deleted); } @@ -279,8 +282,8 @@ pub async fn get_pipeline_vars( .await? .text() .await?; - let variables: PipelineVariablesResponse = - serde_json::from_str(response.as_str()).unwrap_or_else(|_| { + let variables: PipelineVariablesResponse = serde_json::from_str(response.as_str()) + .unwrap_or_else(|_| { throw_adobe_api_error(response); process::exit(1); }); @@ -418,7 +421,7 @@ pub async fn set_pipeline_vars_from_file( name: vc.name, value: None, variable_type: vc.variable_type, - service: vc.service + service: vc.service, }; vars_final.push(variable_to_be_deleted); } From 2e4a38974db16888a9ed37b62b32b2473cd0ca43 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Fri, 11 Oct 2024 20:54:44 +0200 Subject: [PATCH 04/17] reorder models --- src/models.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/models.rs b/src/models.rs index b1d6c0f..7d9e747 100644 --- a/src/models.rs +++ b/src/models.rs @@ -42,16 +42,14 @@ pub struct PipelinesConfig { pub variables: Vec, } -/// Model for all information about a Cloud Manager environment variable +/// Model for common cloud manager variables + +/// Possible types that a variable can have #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct PipelineVariable { - pub name: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub value: Option, - #[serde(rename(deserialize = "type", serialize = "type"))] - pub variable_type: VariableType, - #[serde(default = "PipelineVariableServiceType::default")] - pub service: PipelineVariableServiceType, +#[serde(rename_all = "camelCase")] +pub enum VariableType { + String, + SecretString, } /// Model for all information about a Cloud Manager environment variable @@ -69,14 +67,6 @@ pub struct EnvironmentVariable { pub service: EnvironmentVariableServiceType, } -/// Possible types that a variable can have -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub enum VariableType { - String, - SecretString, -} - /// Possible service types that an environment variable can have #[derive(Clone, Debug, Deserialize, Serialize, IntoStaticStr, EnumString, PartialEq, Eq)] #[strum(serialize_all = "lowercase")] @@ -102,7 +92,21 @@ impl EnvironmentVariableServiceType { EnvironmentVariableServiceType::All } } -/// Possible service types that an environment variable can have + +/// Model for all information about a Cloud Manager pipeline variable +/// Model for all information about a Cloud Manager environment variable +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct PipelineVariable { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, + #[serde(rename(deserialize = "type", serialize = "type"))] + pub variable_type: VariableType, + #[serde(default = "PipelineVariableServiceType::default")] + pub service: PipelineVariableServiceType, +} + +/// Possible service types that an pipeline variable can have #[derive(Clone, Debug, Deserialize, Serialize, IntoStaticStr, EnumString, PartialEq, Eq)] #[strum(serialize_all = "lowercase")] #[serde(rename_all = "lowercase")] @@ -110,7 +114,7 @@ pub enum PipelineVariableServiceType { Build, } -impl fmt::Display for crate::models::PipelineVariableServiceType { +impl fmt::Display for PipelineVariableServiceType { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "{}", format!("{:?}", self).to_lowercase()) } From 6d277cf8a92b1e785fb2a3caa0985fa90cf7e478 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Fri, 11 Oct 2024 20:57:32 +0200 Subject: [PATCH 05/17] Update documentation --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d5f4e86..87a6d70 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,12 @@ pippo -c -p -e log save --service -p -e log tail --service --log ``` +### dry-run mode + +You can pass the flag `--dry-run` on the command line to preview the changes for +* environment variables +* pipeline variables + ### CI mode Since updating running pipelines or environments that are currently updating is not possible pippo will normally wait until it is possible. From 30dbd3e4ebf711088ee12e5b15605ee69c1e0e45 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Fri, 11 Oct 2024 21:01:25 +0200 Subject: [PATCH 06/17] Update comments --- src/variables.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/variables.rs b/src/variables.rs index b940a9d..ccd50dd 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -14,14 +14,14 @@ use std::process; use std::thread::sleep; use std::time::Duration; -// Make environment variables comparable - if they have the same name and same service they are equal. +// Make environment variables comparable - if they have the same name and same service they are the same. impl PartialEq for EnvironmentVariable { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.service == other.service } } -// Make pipeline variables comparable - if they have the same name they are equal. +// Make pipeline variables comparable - if they have the same name and same service they are the same. impl PartialEq for PipelineVariable { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.service == other.service From d342a0c00c5a312bb914d7f358e80dab689a01c8 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Mon, 14 Oct 2024 10:17:02 +0200 Subject: [PATCH 07/17] Add service to pipeline var log output --- src/variables.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/variables.rs b/src/variables.rs index ccd50dd..1ebc9e5 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -430,10 +430,16 @@ pub async fn set_pipeline_vars_from_file( for vf in &vars_final { match vf.value { None => { - println!("{:>8} DELETING '{}'", "✍", vf.name); + println!( + "{:>8} DELETING '{}', service: {}", + "✍", vf.name, vf.service + ); } Some(_) => { - println!("{:>8} UPDATING '{}'", "✍", vf.name) + println!( + "{:>8} UPDATING '{}', service: {}", + "✍", vf.name, vf.service + ) } } } From 1d1cade504f722d70e81da3e9b441ba92ac86559 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Mon, 14 Oct 2024 14:48:48 +0200 Subject: [PATCH 08/17] Add invalid variable service type for environments and pipelines --- src/models.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/models.rs b/src/models.rs index 7d9e747..d06da1e 100644 --- a/src/models.rs +++ b/src/models.rs @@ -62,7 +62,7 @@ pub struct EnvironmentVariable { pub variable_type: VariableType, #[serde( default = "EnvironmentVariableServiceType::default", - skip_serializing_if = "env_var_service_type_is_default" + skip_serializing_if = "environment_variable_skip_serializing" )] pub service: EnvironmentVariableServiceType, } @@ -76,6 +76,8 @@ pub enum EnvironmentVariableServiceType { Author, Publish, Preview, + #[serde(other)] + Invalid, } impl fmt::Display for EnvironmentVariableServiceType { @@ -83,7 +85,7 @@ impl fmt::Display for EnvironmentVariableServiceType { write!(formatter, "{}", format!("{:?}", self).to_lowercase()) } } -fn env_var_service_type_is_default(t: &EnvironmentVariableServiceType) -> bool { +fn environment_variable_skip_serializing(t: &EnvironmentVariableServiceType) -> bool { *t == EnvironmentVariableServiceType::All } @@ -102,7 +104,9 @@ pub struct PipelineVariable { pub value: Option, #[serde(rename(deserialize = "type", serialize = "type"))] pub variable_type: VariableType, - #[serde(default = "PipelineVariableServiceType::default")] + #[serde( + default = "PipelineVariableServiceType::default" + )] pub service: PipelineVariableServiceType, } @@ -112,6 +116,8 @@ pub struct PipelineVariable { #[serde(rename_all = "lowercase")] pub enum PipelineVariableServiceType { Build, + #[serde(other)] + Invalid } impl fmt::Display for PipelineVariableServiceType { From 44f7d1262a1f792e6f62adf64473a135945497dd Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Mon, 14 Oct 2024 15:49:24 +0200 Subject: [PATCH 09/17] Ensure formatting is performed using serde settings --- src/models.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/models.rs b/src/models.rs index d06da1e..d7260bd 100644 --- a/src/models.rs +++ b/src/models.rs @@ -82,7 +82,11 @@ pub enum EnvironmentVariableServiceType { impl fmt::Display for EnvironmentVariableServiceType { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", format!("{:?}", self).to_lowercase()) + write!( + formatter, + "{}", + format!("{}", serde_json::to_string(self).unwrap().to_string()) + ) } } fn environment_variable_skip_serializing(t: &EnvironmentVariableServiceType) -> bool { @@ -122,7 +126,11 @@ pub enum PipelineVariableServiceType { impl fmt::Display for PipelineVariableServiceType { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", format!("{:?}", self).to_lowercase()) + write!( + formatter, + "{}", + format!("{}", serde_json::to_string(self).unwrap().to_string()) + ) } } From ba547cbc5fd605ab5814976b7ccc48fcd474c9ad Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Mon, 14 Oct 2024 15:49:58 +0200 Subject: [PATCH 10/17] Add more service types for pipeline variables --- src/models.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/models.rs b/src/models.rs index d7260bd..7175656 100644 --- a/src/models.rs +++ b/src/models.rs @@ -116,12 +116,14 @@ pub struct PipelineVariable { /// Possible service types that an pipeline variable can have #[derive(Clone, Debug, Deserialize, Serialize, IntoStaticStr, EnumString, PartialEq, Eq)] -#[strum(serialize_all = "lowercase")] -#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "camelCase")] +#[serde(rename_all = "camelCase")] pub enum PipelineVariableServiceType { Build, + UiTest, + FunctionalTest, #[serde(other)] - Invalid + Invalid, } impl fmt::Display for PipelineVariableServiceType { From 62fe9f2cbc6e878403391be3cb53a7cc728240c3 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Mon, 14 Oct 2024 15:50:18 +0200 Subject: [PATCH 11/17] formatting --- src/models.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/models.rs b/src/models.rs index 7175656..26b406a 100644 --- a/src/models.rs +++ b/src/models.rs @@ -108,9 +108,7 @@ pub struct PipelineVariable { pub value: Option, #[serde(rename(deserialize = "type", serialize = "type"))] pub variable_type: VariableType, - #[serde( - default = "PipelineVariableServiceType::default" - )] + #[serde(default = "PipelineVariableServiceType::default")] pub service: PipelineVariableServiceType, } From 8165d0302184c60ed4c27fb34c3ec849a91a6b0b Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Mon, 14 Oct 2024 15:51:04 +0200 Subject: [PATCH 12/17] Check for invalid service types for pipeline and environment variables and exit with error if found --- src/variables.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/variables.rs b/src/variables.rs index 1ebc9e5..b4c25f6 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -198,6 +198,17 @@ pub async fn set_env_vars_from_file( } for vf in &vars_final { + // check if service is invalid and error exit when this is the case. + if vf.service == EnvironmentVariableServiceType::Invalid { + eprintln!( + "{:>8} {} '{}'", + "❌".red(), + "Error, invalid service type detected for variable ".red(), + vf.name + ); + process::exit(3); + } + match vf.value { None => { println!( @@ -428,6 +439,17 @@ pub async fn set_pipeline_vars_from_file( } for vf in &vars_final { + // check if service is invalid and error exit when this is the case. + if vf.service == PipelineVariableServiceType::Invalid { + eprintln!( + "{:>8} {} '{}'", + "❌".red(), + "Error, invalid service type detected for variable ".red(), + vf.name + ); + process::exit(3); + } + match vf.value { None => { println!( From cae84e3dc279ec469ff0a43b54d066fca2d27d97 Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Mon, 14 Oct 2024 15:51:15 +0200 Subject: [PATCH 13/17] Formatting --- src/variables.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/variables.rs b/src/variables.rs index b4c25f6..a23bef9 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -3,7 +3,8 @@ use crate::encryption::decrypt; use crate::environments::get_environment; use crate::errors::throw_adobe_api_error; use crate::models::{ - EnvironmentVariable, EnvironmentVariablesList, EnvironmentVariablesResponse, PipelineVariable, + EnvironmentVariable, EnvironmentVariableServiceType, EnvironmentVariablesList, + EnvironmentVariablesResponse, PipelineVariable, PipelineVariableServiceType, PipelineVariablesList, PipelineVariablesResponse, VariableType, YamlConfig, }; use crate::pipelines::get_pipeline; From 9fb7a5f742e45deaed8bfe645e3bbbafeac465c1 Mon Sep 17 00:00:00 2001 From: Benjamin Sommerfeld Date: Mon, 14 Oct 2024 16:51:08 +0200 Subject: [PATCH 14/17] feat: check complete list for invalid entries, instead each individual entry. Add warn message, if there are any invalid entries on CM already --- src/clap_app.rs | 16 +++++++++++++++- src/variables.rs | 50 +++++++++++++++++++++++++++--------------------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/clap_app.rs b/src/clap_app.rs index 8c08c03..58c4781 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -12,7 +12,7 @@ use crate::client::CloudManagerClient; use crate::config::CloudManagerConfig; use crate::encryption::{decrypt, encrypt}; use crate::logs::{download_log, tail_log}; -use crate::models::{Domain, LogType, ServiceType}; +use crate::models::{Domain, LogType, PipelineVariableServiceType, ServiceType}; use crate::variables::{ get_env_vars, get_pipeline_vars, set_env_vars_from_file, set_pipeline_vars_from_file, }; @@ -283,10 +283,24 @@ pub async fn init_cli() { get_pipeline_vars(&mut cm_client, program_id, &pipeline_id) .await .unwrap(); + println!( "{}", serde_json::to_string_pretty(&pipeline_vars).unwrap() ); + if let Some(vf) = pipeline_vars + .variables + .iter() + .find(|vf| vf.service == PipelineVariableServiceType::Invalid) + { + eprintln!( + "{:>8} {} '{}: {}'", + "⚠".yellow(), + "WARN, invalid service type detected for variable".yellow(), + vf.name, + vf.service + ); + } } } else { eprintln!("❌ You have to provide a valid Cloud Manager pipeline ID to run this command!"); diff --git a/src/variables.rs b/src/variables.rs index a23bef9..13df0d5 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -198,18 +198,21 @@ pub async fn set_env_vars_from_file( } } - for vf in &vars_final { - // check if service is invalid and error exit when this is the case. - if vf.service == EnvironmentVariableServiceType::Invalid { - eprintln!( - "{:>8} {} '{}'", - "❌".red(), - "Error, invalid service type detected for variable ".red(), - vf.name - ); - process::exit(3); - } + if let Some(vf) = vars_final + .iter() + .find(|vf| vf.service == EnvironmentVariableServiceType::Invalid) + { + eprintln!( + "{:>8} {} '{}: {}'", + "❌".red(), + "ERROR, invalid service type detected for variable".red(), + vf.name, + vf.service + ); + process::exit(3); + } + for vf in &vars_final { match vf.value { None => { println!( @@ -439,18 +442,21 @@ pub async fn set_pipeline_vars_from_file( } } - for vf in &vars_final { - // check if service is invalid and error exit when this is the case. - if vf.service == PipelineVariableServiceType::Invalid { - eprintln!( - "{:>8} {} '{}'", - "❌".red(), - "Error, invalid service type detected for variable ".red(), - vf.name - ); - process::exit(3); - } + if let Some(vf) = vars_final + .iter() + .find(|vf| vf.service == PipelineVariableServiceType::Invalid) + { + eprintln!( + "{:>8} {} '{}: {}'", + "❌".red(), + "ERROR, invalid service type detected for variable".red(), + vf.name, + vf.service + ); + process::exit(3); + } + for vf in &vars_final { match vf.value { None => { println!( From 3a6913c569d73c28d4ecdbe77dc88bf5626c5c56 Mon Sep 17 00:00:00 2001 From: Benjamin Sommerfeld Date: Tue, 15 Oct 2024 08:18:02 +0200 Subject: [PATCH 15/17] feat: add warn log for environment, if invalid types are present on CM --- src/clap_app.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/clap_app.rs b/src/clap_app.rs index 58c4781..357ca20 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -95,6 +95,17 @@ pub async fn init_cli() { .await .unwrap(); println!("{}", serde_json::to_string_pretty(&env_vars).unwrap()); + if let Some(vf) = env_vars.variables.iter().find(|vf| { + vf.service == EnvironmentVariableServiceType::Invalid + }) { + eprintln!( + "{:>8} {} '{}: {}'", + "⚠".yellow(), + "WARN, invalid service type detected for variable".yellow(), + vf.name, + vf.service + ); + } } } else { eprintln!("❌ You have to provide a valid Cloud Manager environment ID to run this command!"); From dd02ce9596c8d58cee8ebe2e208df143b328caf5 Mon Sep 17 00:00:00 2001 From: Benjamin Sommerfeld Date: Tue, 15 Oct 2024 08:45:36 +0200 Subject: [PATCH 16/17] fix: use crate --- src/clap_app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clap_app.rs b/src/clap_app.rs index 357ca20..39bbab0 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -12,7 +12,7 @@ use crate::client::CloudManagerClient; use crate::config::CloudManagerConfig; use crate::encryption::{decrypt, encrypt}; use crate::logs::{download_log, tail_log}; -use crate::models::{Domain, LogType, PipelineVariableServiceType, ServiceType}; +use crate::models::{Domain, LogType, PipelineVariableServiceType, EnvironmentVariableServiceType, ServiceType}; use crate::variables::{ get_env_vars, get_pipeline_vars, set_env_vars_from_file, set_pipeline_vars_from_file, }; From 2af667c09b219309bf5f7200c2663e2e144775fd Mon Sep 17 00:00:00 2001 From: Tobias Richter Date: Tue, 15 Oct 2024 09:12:55 +0200 Subject: [PATCH 17/17] Update src/clap_app.rs Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/clap_app.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/clap_app.rs b/src/clap_app.rs index 39bbab0..edda328 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -12,7 +12,9 @@ use crate::client::CloudManagerClient; use crate::config::CloudManagerConfig; use crate::encryption::{decrypt, encrypt}; use crate::logs::{download_log, tail_log}; -use crate::models::{Domain, LogType, PipelineVariableServiceType, EnvironmentVariableServiceType, ServiceType}; +use crate::models::{ + Domain, EnvironmentVariableServiceType, LogType, PipelineVariableServiceType, ServiceType, +}; use crate::variables::{ get_env_vars, get_pipeline_vars, set_env_vars_from_file, set_pipeline_vars_from_file, };