fluidattacks-core-git 0.45.0

Fluid Attacks Core Git
Documentation
use std::process::Output;
use tokio::process::Command;

use crate::errors::GitCallError;

pub async fn run(command: &'static str, git: &mut Command) -> Result<Output, GitCallError> {
    let output = git
        .output()
        .await
        .map_err(|source| GitCallError::NotStarted { command, source })?;
    if output.status.success() {
        return Ok(output);
    }
    Err(GitCallError::Refused {
        command,
        status: output.status,
        stderr: String::from_utf8_lossy(&output.stderr).trim().to_owned(),
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn a_git_that_cannot_start_is_told_apart_from_one_that_refused() {
        let outcome = run("log", &mut Command::new("git-that-is-not-installed")).await;

        assert!(matches!(
            outcome,
            Err(GitCallError::NotStarted { command: "log", source }) if source.kind() == std::io::ErrorKind::NotFound
        ));
    }

    #[tokio::test]
    async fn a_git_that_exits_with_failure_is_refused() {
        let mut failing = Command::new("sh");
        failing.args(["-c", "echo nope >&2; exit 3"]);

        let outcome = run("config", &mut failing).await;

        assert!(matches!(
            outcome,
            Err(GitCallError::Refused { command: "config", status, stderr })
                if status.code() == Some(3) && stderr == "nope"
        ));
    }
}