mecha10-cli 0.8.0

Mecha10 CLI tool
Documentation
//! Stop command handler
//!
//! Stops a running target - pairs with `handlers::run` (see `commands::stop::StopCommand`'s doc
//! comment for the target-argument shape this mirrors).

use crate::commands::StopCommand;
use crate::context::CliContext;
use crate::handlers::run::RunTarget;
use crate::paths;
use crate::services::DockerService;
use anyhow::{Context, Result};

remote_dispatch_handler!(handle_stop, StopCommand, stop_remote_target);

/// Stop the remote target's Docker Compose stack (ported from the former `mecha10 remote down`)
async fn stop_remote_target(ctx: &mut CliContext) -> Result<()> {
    let target = RunTarget::Remote;

    let compose_path = ctx.working_dir.join(paths::docker::COMPOSE_REMOTE_FILE);
    if !compose_path.exists() {
        return Err(anyhow::anyhow!("No remote compose file found."));
    }

    let compose_file_path = compose_path.to_string_lossy().to_string();
    let docker = DockerService::with_compose_file(&compose_file_path);
    docker.check_installation()?;

    println!(
        "Stopping {} target ({})...",
        target.display_name(),
        target.description()
    );

    docker
        .compose_down()
        .await
        .context("Failed to stop remote Docker Compose stack")?;

    println!("Stopped.");

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::context::CliContextBuilder;
    use tempfile::tempdir;

    fn ctx_in(dir: &std::path::Path) -> CliContext {
        CliContextBuilder::new()
            .working_dir(dir.to_path_buf())
            .config_path(Some(dir.join("mecha10.json")))
            .build()
            .unwrap()
    }

    #[tokio::test]
    async fn handle_stop_remote_errors_when_no_compose_file() {
        let dir = tempdir().unwrap();
        let mut ctx = ctx_in(dir.path());

        let err = handle_stop(&mut ctx, &StopCommand::Remote).await.unwrap_err();
        assert!(err.to_string().contains("No remote compose file found"));
    }
}