releez 1.0.3

An utility tool to run application release-checklist safely.
Documentation
use crate::out;
use crate::prelude::*;
use crate::runner::executor::helpers;
use crate::types::{ReleaseConfig, Task};
use colored::*;
use std::collections::HashMap;
use std::env::consts::OS;
use std::path::Path;
use std::process::{ExitStatus, Stdio};
use tokio::process::Command;

pub async fn execute_auto_task(
    release_config: &ReleaseConfig,
    task_id: u64,
    task: &Task,
    start_sub_task_id: u64,
    root_dir: &Path,
    vars_data: &HashMap<String, String>,
) -> crate::Result<()> {
    out::print(format!("{} {}\n\n", "Running:".green().bold(), task.name.as_str())).await?;

    if let Some(ref confirm_msg) = task.confirm {
        let confirmation = helpers::ask_confirmation(confirm_msg, "yes", "").await?;

        if !confirmation {
            out::print("\nQuiting the process, run command again to resume the release.\n").await?;
            std::process::exit(0);
        }
        out::print("\n").await?;
    }

    let sub_tasks = task.sub_tasks().iter().skip(start_sub_task_id as usize);
    for (sub_task, idx) in sub_tasks.zip(start_sub_task_id..) {
        let command = sub_task.trim();

        out::print(format!("{} {}\n", "$".cyan(), command.cyan())).await?;

        let status = run_command(command, task, root_dir, vars_data).await?;

        if !status.success() {
            return Err(crate::Error::new(format!(
                "Failed to execute auto task command: '{}' with exit code: '{}' for task: '{}'",
                command,
                status.code().map(|code| code.to_string()).unwrap_or("na".to_owned()),
                task.name
            )));
        }

        helpers::save_last_checked(release_config, task_id, idx, root_dir).await?;
        out::print("\n").await?;
    }

    out::print(format!(
        "{}{}\n\n",
        "Checked: ".bright_black(),
        task.name.as_str().bright_black()
    ))
    .await?;

    Ok(())
}

async fn run_command(
    command: &str,
    task: &Task,
    root_dir: &Path,
    vars_data: &HashMap<String, String>,
) -> crate::Result<ExitStatus> {
    let (program, args) = if OS == "windows" {
        ("cmd", ["/C", command])
    } else {
        ("sh", ["-c", command])
    };

    let child = Command::new(program)
        .args(&args)
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .current_dir(root_dir)
        .envs(vars_data.iter())
        .kill_on_drop(true)
        .spawn()
        .context(format!(
            "Couldn't run the auto task command: '{}' for task: '{}', maybe the 'sh' or 'cmd' program not found on the system",
            command, task.name
        ))?;

    let status = child.await.wrap()?;

    Ok(status)
}