docker_wrapper/command/compose/
push.rs1use crate::command::{CommandExecutor, ComposeCommand, ComposeConfig, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone)]
9pub struct ComposePushCommand {
10 pub executor: CommandExecutor,
12 pub config: ComposeConfig,
14 pub services: Vec<String>,
16 pub ignore_build_failures: bool,
18 pub include_deps: bool,
20 pub quiet: bool,
22}
23
24#[derive(Debug, Clone)]
26pub struct ComposePushResult {
27 pub stdout: String,
29 pub stderr: String,
31 pub success: bool,
33 pub services: Vec<String>,
35}
36
37impl ComposePushCommand {
38 #[must_use]
40 pub fn new() -> Self {
41 Self {
42 executor: CommandExecutor::new(),
43 config: ComposeConfig::new(),
44 services: Vec::new(),
45 ignore_build_failures: false,
46 include_deps: false,
47 quiet: false,
48 }
49 }
50
51 #[must_use]
53 pub fn service(mut self, service: impl Into<String>) -> Self {
54 self.services.push(service.into());
55 self
56 }
57
58 #[must_use]
60 pub fn services<I, S>(mut self, services: I) -> Self
61 where
62 I: IntoIterator<Item = S>,
63 S: Into<String>,
64 {
65 self.services.extend(services.into_iter().map(Into::into));
66 self
67 }
68
69 #[must_use]
71 pub fn ignore_build_failures(mut self) -> Self {
72 self.ignore_build_failures = true;
73 self
74 }
75
76 #[must_use]
78 pub fn include_deps(mut self) -> Self {
79 self.include_deps = true;
80 self
81 }
82
83 #[must_use]
85 pub fn quiet(mut self) -> Self {
86 self.quiet = true;
87 self
88 }
89}
90
91impl Default for ComposePushCommand {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97#[async_trait]
98impl DockerCommand for ComposePushCommand {
99 type Output = ComposePushResult;
100
101 fn get_executor(&self) -> &CommandExecutor {
102 &self.executor
103 }
104
105 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
106 &mut self.executor
107 }
108
109 fn build_command_args(&self) -> Vec<String> {
110 <Self as ComposeCommand>::build_command_args(self)
111 }
112
113 async fn execute(&self) -> Result<Self::Output> {
114 let args = <Self as ComposeCommand>::build_command_args(self);
115 let output = self.execute_command(args).await?;
116
117 Ok(ComposePushResult {
118 stdout: output.stdout,
119 stderr: output.stderr,
120 success: output.success,
121 services: self.services.clone(),
122 })
123 }
124}
125
126impl ComposeCommand for ComposePushCommand {
127 fn get_config(&self) -> &ComposeConfig {
128 &self.config
129 }
130
131 fn get_config_mut(&mut self) -> &mut ComposeConfig {
132 &mut self.config
133 }
134
135 fn subcommand(&self) -> &'static str {
136 "push"
137 }
138
139 fn build_subcommand_args(&self) -> Vec<String> {
140 let mut args = Vec::new();
141
142 if self.ignore_build_failures {
143 args.push("--ignore-build-failures".to_string());
144 }
145
146 if self.include_deps {
147 args.push("--include-deps".to_string());
148 }
149
150 if self.quiet {
151 args.push("--quiet".to_string());
152 }
153
154 args.extend(self.services.clone());
155 args
156 }
157}
158
159impl ComposePushResult {
160 #[must_use]
162 pub fn success(&self) -> bool {
163 self.success
164 }
165
166 #[must_use]
168 pub fn services(&self) -> &[String] {
169 &self.services
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn test_compose_push_basic() {
179 let cmd = ComposePushCommand::new();
180 let args = cmd.build_subcommand_args();
181 assert!(args.is_empty());
182
183 let full_args = ComposeCommand::build_command_args(&cmd);
184 assert_eq!(full_args[0], "compose");
185 assert!(full_args.contains(&"push".to_string()));
186 }
187
188 #[test]
189 fn test_compose_push_with_options() {
190 let cmd = ComposePushCommand::new()
191 .ignore_build_failures()
192 .include_deps()
193 .quiet()
194 .service("web");
195
196 let args = cmd.build_subcommand_args();
197 assert!(args.contains(&"--ignore-build-failures".to_string()));
198 assert!(args.contains(&"--include-deps".to_string()));
199 assert!(args.contains(&"--quiet".to_string()));
200 assert!(args.contains(&"web".to_string()));
201 }
202}