docker_wrapper/compose/
run.rs

1//! Docker Compose run command implementation.
2
3use super::{execute_compose_command, ComposeCommand, ComposeConfig, ComposeOutput};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Docker Compose run command builder
8#[derive(Debug, Clone, Default)]
9#[allow(dead_code)] // Stub implementation
10pub struct ComposeRunCommand {
11    config: ComposeConfig,
12    service: String,
13    command: Vec<String>,
14    detach: bool,
15    rm: bool,
16}
17
18impl ComposeRunCommand {
19    /// Create a new compose run command
20    #[must_use]
21    pub fn new(service: impl Into<String>) -> Self {
22        Self {
23            service: service.into(),
24            ..Self::default()
25        }
26    }
27
28    /// Execute the run command
29    ///
30    /// # Errors
31    ///
32    /// Returns an error if the docker compose run command fails
33    pub async fn run(&self) -> Result<ComposeOutput> {
34        self.execute().await
35    }
36}
37
38#[async_trait]
39impl ComposeCommand for ComposeRunCommand {
40    type Output = ComposeOutput;
41
42    fn subcommand(&self) -> &'static str {
43        "run"
44    }
45
46    fn build_args(&self) -> Vec<String> {
47        let mut args = vec![self.service.clone()];
48        args.extend(self.command.clone());
49        args
50    }
51
52    async fn execute(&self) -> Result<Self::Output> {
53        execute_compose_command(&self.config, self.subcommand(), self.build_args()).await
54    }
55
56    fn config(&self) -> &ComposeConfig {
57        &self.config
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_compose_run_basic() {
67        let cmd = ComposeRunCommand::new("web");
68        assert_eq!(cmd.service, "web");
69        assert_eq!(cmd.subcommand(), "run");
70        let args = cmd.build_args();
71        assert_eq!(args, vec!["web"]);
72    }
73
74    #[test]
75    fn test_compose_run_with_command() {
76        let mut cmd = ComposeRunCommand::new("worker");
77        cmd.command = vec!["python".to_string(), "script.py".to_string()];
78
79        let args = cmd.build_args();
80        assert_eq!(args, vec!["worker", "python", "script.py"]);
81    }
82
83    #[test]
84    fn test_compose_run_with_config() {
85        let config = ComposeConfig::new()
86            .file("docker-compose.yml")
87            .project_name("myproject");
88
89        let mut cmd = ComposeRunCommand::new("test");
90        cmd.config = config;
91        cmd.command = vec!["npm".to_string(), "test".to_string()];
92
93        assert_eq!(cmd.config().project_name, Some("myproject".to_string()));
94        assert_eq!(cmd.build_args(), vec!["test", "npm", "test"]);
95    }
96
97    #[test]
98    fn test_compose_run_future_options() {
99        // Test that fields exist for future implementation
100        let cmd = ComposeRunCommand {
101            config: ComposeConfig::new(),
102            service: "app".to_string(),
103            command: vec!["echo".to_string(), "hello".to_string()],
104            detach: true,
105            rm: true,
106        };
107
108        // Currently only includes service and command
109        let args = cmd.build_args();
110        assert_eq!(args, vec!["app", "echo", "hello"]);
111
112        // When fully implemented, it should include options:
113        // assert!(args.contains(&"--detach".to_string()));
114        // assert!(args.contains(&"--rm".to_string()));
115    }
116}