diff --git a/src/command.rs b/src/command.rs index a1e4dda..38f3978 100644 --- a/src/command.rs +++ b/src/command.rs @@ -22,6 +22,7 @@ pub struct CommandSuccess { pub stdout: String, pub stderr: String, pub duration: Duration, + pub exit_code: i32, // This field stores the exit code of the command to determine if it was successful or not, and whether or not there were any diffs. } impl CommandSuccess { @@ -189,6 +190,7 @@ impl CommandLine { cmd: self.clone(), stdout, stderr, + exit_code, duration, }), Err(kind) => Err(CommandError { diff --git a/src/helm.rs b/src/helm.rs index 53ee397..b6c5cdd 100644 --- a/src/helm.rs +++ b/src/helm.rs @@ -118,6 +118,8 @@ pub struct HelmResult { pub installation: Arc, pub result: CommandResult, pub command: Command, + // The exit code contains information about whether there were any diffs. + pub _exit_code: i32, } impl HelmResult { @@ -130,6 +132,7 @@ impl HelmResult { installation: installation.clone(), result, command, + _exit_code: 0, } } @@ -366,20 +369,29 @@ pub async fn template( } } +// The DiffResult struct is used to store the exit code of the diff command. +pub struct DiffResult { + pub _exit_code: i32, +} + /// Run the helm diff command. pub async fn diff( installation: &Arc, helm_repos: &HelmReposLock, tx: &MultiOutput, -) -> Result<()> { +) -> Result { + // Retrieve the helm chart for the given installation. let chart = helm_repos.get_helm_chart(&installation.chart_reference)?; + // Get the chart arguments from the chart. let (chart, mut chart_args) = get_args_from_chart(&chart); + // Construct the arguments for the helm diff command. let mut args = vec![ "diff".into(), "upgrade".into(), installation.name.clone().into(), chart, + "--detailed-exitcode".into(), // This flag ensures that the exit code will indicate if there are changes or errors. "--context=3".into(), "--no-color".into(), "--allow-unreleased".into(), @@ -389,22 +401,52 @@ pub async fn diff( installation.clone().context.clone().into(), ]; + // Append additional arguments from the installation configuration. args.append(&mut add_values_files(installation)); args.append(&mut chart_args); args.append(&mut get_template_parameters(installation)); + // Create a CommandLine instance with the helm path and the constructed arguments. let command_line = CommandLine(helm_path(), args); + // Run the command and await the result. let result = command_line.run().await; - let has_errors = result.is_err(); - let i_result = HelmResult::from_result(installation, result, Command::Diff); + // Check if there were any errors in the command execution. + let _has_errors = result.is_err(); + // Create a HelmResult instance from the command result. + let mut i_result = HelmResult::from_result(installation, result, Command::Diff); + + // Evaluate the detailed exit code - any non-zero exit code indicates changes (1) or errors (2). + let exit_code = if let Ok(command_success) = &i_result.result { + i_result._exit_code = command_success.exit_code; + match command_success.exit_code { + 0 => { + debug!("No changes detected!"); // Exit code 0 indicates no changes. + 0 + } + 1 => { + debug!("Errors encountered!"); // Exit code 1 indicates errors. + 1 + } + 2 => { + debug!("Changes detected!"); // Exit code 2 indicates changes. + 2 + } + _ => { + debug!("Unknown exit code"); // Any other exit code is considered unknown. + -1 + } + } + } else { + debug!("Other error encountered"); // If the command result is an error, return -1. + -1 + }; + + // Wrap the HelmResult in an Arc and send it via the MultiOutput channel. let i_result = Arc::new(i_result); tx.send(Message::InstallationResult(i_result)).await; - if has_errors { - Err(anyhow::anyhow!("diff operation failed")) - } else { - Ok(()) - } + // Return the exit code. Errors are no longer considered a failure and can be handled by the caller. + Ok(DiffResult { _exit_code: exit_code }) } /// Run the helm upgrade command. diff --git a/src/main.rs b/src/main.rs index c91d5aa..e6907ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,7 @@ mod duration; mod utils; + /// An individual update #[derive(Clone, Debug)] pub struct Update { @@ -184,26 +185,61 @@ where Ok(rc) } +// Define the possible results of a job. +enum JobResult { + Unit, // Represents a unit result. + Diff(helm::DiffResult), // Represents a diff result. +} + +// Asynchronously run a job based on the provided command. async fn run_job( - command: &Request, - helm_repos: &HelmReposLock, - installation: &Arc, - tx: &MultiOutput, -) -> Result<()> { + command: &Request, // The command to execute. + helm_repos: &HelmReposLock, // The helm repositories lock. + installation: &Arc, // The installation details. + tx: &MultiOutput, // The multi-output channel. +) -> Result { match command { + // Handle the Upgrade request. Request::Upgrade { .. } => { + // Run the helm diff command. + let diff_result = helm::diff(installation, helm_repos, tx).await?; + // Check the exit code of the diff command. + if diff_result._exit_code == 0 || diff_result._exit_code == 2 { + // If no changes or only changes detected, return Unit. + return Ok(JobResult::Unit); + } + // Perform a dry-run upgrade. helm::upgrade(installation, helm_repos, tx, true).await?; - helm::upgrade(installation, helm_repos, tx, false).await + // Perform the actual upgrade. + helm::upgrade(installation, helm_repos, tx, false).await?; + // Return Unit result. + Ok(JobResult::Unit) } - Request::Diff { .. } => helm::diff(installation, helm_repos, tx).await, + // Handle the Diff request. + Request::Diff { .. } => { + // Run the helm diff command. + let diff_result = helm::diff(installation, helm_repos, tx).await?; + // Return the diff result. + Ok(JobResult::Diff(helm::DiffResult { _exit_code: diff_result._exit_code })) + }, Request::Test { .. } => { helm::outdated(installation, helm_repos, tx).await?; helm::lint(installation, tx).await?; - helm::template(installation, helm_repos, tx).await + helm::template(installation, helm_repos, tx).await?; + Ok(JobResult::Unit) + } + Request::Template { .. } => { + helm::template(installation, helm_repos, tx).await?; + Ok(JobResult::Unit) + } + Request::Outdated { .. } => { + helm::outdated(installation, helm_repos, tx).await?; + Ok(JobResult::Unit) + } + Request::Update { updates, .. } => { + helm::update(installation, tx, updates).await?; + Ok(JobResult::Unit) } - Request::Template { .. } => helm::template(installation, helm_repos, tx).await, - Request::Outdated { .. } => helm::outdated(installation, helm_repos, tx).await, - Request::Update { updates, .. } => helm::update(installation, tx, updates).await, } } @@ -824,8 +860,15 @@ async fn worker_thread( // Execute the job let result = run_job(command, helm_repos, &install, output).await; match &result { - Ok(()) => { - // Tell dispatcher job is done so it can update the dependancies + Ok(JobResult::Unit) => { + // Handle the unit case + tx_dispatch + .send(Dispatch::Done(HashIndex::get_hash_index(&install))) + .await?; + } + Ok(JobResult::Diff(helm::DiffResult { _exit_code })) => { + // Handle the diff result case + // You might want to log or process the diff_result here tx_dispatch .send(Dispatch::Done(HashIndex::get_hash_index(&install))) .await?; @@ -846,7 +889,7 @@ async fn worker_thread( output .send(Message::FinishedJob( install.clone(), - result.map_err(|err| err.to_string()), + result.map(|_| ()).map_err(|err| err.to_string()), stop - start, )) .await; diff --git a/src/output/text.rs b/src/output/text.rs index 20c88a1..3a3b9a4 100644 --- a/src/output/text.rs +++ b/src/output/text.rs @@ -216,6 +216,7 @@ fn process_message(msg: &Arc, state: &mut State) { command, result, installation, + _exit_code // This field is not used in this function, but it is part of the HelmResult struct. } = hr.as_ref(); let result_str = hr.result_line();