Skip to content

Commit

Permalink
Add support for allowable exit codes from command lines
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian May committed Aug 27, 2024
1 parent 2f66a84 commit e9a2a62
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 25 deletions.
47 changes: 39 additions & 8 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ impl Display for CommandSuccess {
f.write_str(&summary)?;
f.write_str("\n")?;

f.write_str("exit code: ")?;
f.write_str(&self.exit_code.to_string())?;
f.write_str("\n")?;

f.write_str("command: ")?;
f.write_str(&self.cmd.to_string())?;
f.write_str("\n")?;
Expand Down Expand Up @@ -101,6 +105,10 @@ impl Display for CommandError {
f.write_str(&summary)?;
f.write_str("\n")?;

f.write_str("exit code: ")?;
f.write_str(&self.exit_code.to_string())?;
f.write_str("\n")?;

f.write_str("command: ")?;
f.write_str(&self.cmd.to_string())?;
f.write_str("\n")?;
Expand All @@ -126,7 +134,26 @@ impl Error for CommandError {}
pub type CommandResult = Result<CommandSuccess, CommandError>;

#[derive(Clone, Eq, PartialEq)]
pub struct CommandLine(pub OsString, pub Vec<OsString>);
pub struct CommandLine {
cmd: OsString,
args: Vec<OsString>,
allowed_exit_codes: Vec<i32>,
}

impl CommandLine {
pub fn new(cmd: OsString, args: Vec<OsString>) -> Self {
CommandLine {
cmd,
args,
allowed_exit_codes: vec![0],
}
}

pub fn with_allowed_exit_codes(mut self, allowed_exit_codes: Vec<i32>) -> Self {
self.allowed_exit_codes = allowed_exit_codes;
self
}
}

fn get_exit_code(output: &Result<Output, io::Error>) -> i32 {
output
Expand All @@ -148,7 +175,11 @@ impl CommandLine {
pub async fn run(&self) -> CommandResult {
let start = Instant::now();

let CommandLine(cmd, args) = &self;
let CommandLine {
cmd,
args,
allowed_exit_codes,
} = &self;
let output = Command::new(cmd)
.args(args)
.stdin(Stdio::null())
Expand Down Expand Up @@ -176,8 +207,8 @@ impl CommandLine {

let kind = match output {
Err(err) => Err(CommandErrorKind::FailedToStart { err }),
Ok(output) => {
if output.status.success() || exit_code == 2 {
Ok(_output) => {
if allowed_exit_codes.contains(&exit_code) {
Ok(())
} else {
Err(CommandErrorKind::BadExitCode {})
Expand Down Expand Up @@ -207,8 +238,8 @@ impl CommandLine {

impl Display for CommandLine {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.to_string_lossy())?;
for arg in &self.1 {
write!(f, "{}", self.cmd.to_string_lossy())?;
for arg in &self.args {
write!(f, " {}", arg.to_string_lossy())?;
}
Ok(())
Expand All @@ -217,8 +248,8 @@ impl Display for CommandLine {

impl std::fmt::Debug for CommandLine {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CommandLine(\"{:?}", self.0)?;
for arg in &self.1 {
write!(f, "CommandLine(\"{:?}", self.cmd)?;
for arg in &self.args {
write!(f, " {arg:?}")?;
}
write!(f, "\")")?;
Expand Down
31 changes: 16 additions & 15 deletions src/helm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ 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 @@ -132,7 +130,6 @@ impl HelmResult {
installation: installation.clone(),
result,
command,
exit_code: 0,
}
}

Expand Down Expand Up @@ -174,6 +171,13 @@ impl HelmResult {
Err(err) => err.result_line(),
}
}

pub const fn exit_code(&self) -> i32 {
match &self.result {
Ok(success) => success.exit_code,
Err(err) => err.exit_code,
}
}
}

/// Request to add a repo to helm.
Expand All @@ -185,7 +189,7 @@ pub async fn add_repo(
) -> Result<()> {
debug!("Add helm repo {} at {}... ", repo_name, repo_url);

let command: CommandLine = CommandLine(
let command: CommandLine = CommandLine::new(
"helm".into(),
vec![
"repo".into(),
Expand Down Expand Up @@ -216,7 +220,7 @@ pub async fn remove_repo(
) -> Result<()> {
debug!("Remove helm repo {} at {}... ", repo_name, repo_url);

let command: CommandLine = CommandLine(
let command: CommandLine = CommandLine::new(
"helm".into(),
vec!["repo".into(), "remove".into(), repo_name.into()],
);
Expand Down Expand Up @@ -247,7 +251,7 @@ pub async fn lint(installation: &Arc<Installation>, tx: &MultiOutput) -> Result<
args.push(path.clone().into_os_string());
args.append(&mut get_template_parameters(installation));

let command_line = CommandLine(helm_path(), args);
let command_line = CommandLine::new(helm_path(), args);
let result = command_line.run().await;
let has_errors = result.is_err();
let i_result = HelmResult::from_result(installation, result, Command::Lint);
Expand Down Expand Up @@ -355,7 +359,7 @@ pub async fn template(
args.append(&mut chart_args);
args.append(&mut get_template_parameters(installation));

let command_line = CommandLine(helm_path(), args);
let command_line = CommandLine::new(helm_path(), args);
let result = command_line.run().await;
let has_errors = result.is_err();
let i_result = HelmResult::from_result(installation, result, Command::Template);
Expand Down Expand Up @@ -413,17 +417,14 @@ pub async fn diff(
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);
let command_line = CommandLine::new(helm_path(), args).with_allowed_exit_codes(vec![0, 2]);
// Run the command and await the result.
let result = command_line.run().await;
// 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);
let 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 diff_result = if let Ok(command_success) = &i_result.result {
i_result.exit_code = command_success.exit_code;
match command_success.exit_code {
0 => {
log_debug_message(tx, "No changes detected!").await; // Exit code 0 indicates no changes.
Expand Down Expand Up @@ -487,7 +488,7 @@ pub async fn upgrade(
args.push("--dry-run".into());
}

let command_line = CommandLine(helm_path(), args);
let command_line = CommandLine::new(helm_path(), args);
let result = command_line.run().await;
let has_errors = result.is_err();
let command = if dry_run {
Expand Down Expand Up @@ -561,7 +562,7 @@ async fn outdated_helm_chart(
format!("{}/{chart_name}", repo.name).into(),
];

let command_line = CommandLine(helm_path(), args);
let command_line = CommandLine::new(helm_path(), args);
let result = command_line.run().await;
let has_errors = result.is_err();

Expand Down Expand Up @@ -699,7 +700,7 @@ impl ParsedOci {
path.into(),
];

let command_line = CommandLine(aws_path(), args);
let command_line = CommandLine::new(aws_path(), args);
let result = command_line.run().await;

let rc = match &result {
Expand Down
2 changes: 0 additions & 2 deletions src/output/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,6 @@ fn process_message(msg: &Arc<Message>, state: &mut State) {
command,
result,
installation,
#[allow(unused_variables)] // Suppress warning for this variable
exit_code,
} = hr.as_ref();
let result_str = hr.result_line();

Expand Down
2 changes: 2 additions & 0 deletions src/output/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ impl HasMultilineText for HelmResult {

fn get_text(&self, _state: &State) -> Vec<Spans> {
let mut lines = vec![key_value_space("Result", self.result_line())];
lines.push(key_value_space("Exit Code", self.exit_code().to_string()));

lines.push(key_value_space("Cmd", self.command_line().to_string()));

let stdout = self.stdout();
Expand Down

0 comments on commit e9a2a62

Please sign in to comment.