Skip to content

Commit

Permalink
Merge pull request #1 from tylermaginnis/feature/TM_skip-upgrade-if-u…
Browse files Browse the repository at this point in the history
…nchanged

Add feature to skip upgrade if no changes detected
  • Loading branch information
tylermaginnis authored Aug 25, 2024
2 parents 45ae00d + f0fdbb3 commit 793ef69
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 22 deletions.
2 changes: 2 additions & 0 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -189,6 +190,7 @@ impl CommandLine {
cmd: self.clone(),
stdout,
stderr,
exit_code,
duration,
}),
Err(kind) => Err(CommandError {
Expand Down
58 changes: 50 additions & 8 deletions src/helm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ pub struct HelmResult {
pub installation: Arc<Installation>,
pub result: CommandResult,
pub command: Command,
// The exit code contains information about whether there were any diffs.
pub _exit_code: i32,
}

impl HelmResult {
Expand All @@ -130,6 +132,7 @@ impl HelmResult {
installation: installation.clone(),
result,
command,
_exit_code: 0,
}
}

Expand Down Expand Up @@ -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<Installation>,
helm_repos: &HelmReposLock,
tx: &MultiOutput,
) -> Result<()> {
) -> Result<DiffResult> {
// 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(),
Expand All @@ -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.
Expand Down
71 changes: 57 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ mod duration;

mod utils;


/// An individual update
#[derive(Clone, Debug)]
pub struct Update {
Expand Down Expand Up @@ -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<Installation>,
tx: &MultiOutput,
) -> Result<()> {
command: &Request, // The command to execute.
helm_repos: &HelmReposLock, // The helm repositories lock.
installation: &Arc<Installation>, // The installation details.
tx: &MultiOutput, // The multi-output channel.
) -> Result<JobResult> {
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,
}
}

Expand Down Expand Up @@ -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?;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/output/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ fn process_message(msg: &Arc<Message>, 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();

Expand Down

0 comments on commit 793ef69

Please sign in to comment.