docker_wrapper/compose/
push.rs1use crate::compose::{ComposeCommandV2 as ComposeCommand, ComposeConfig};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone, Default)]
11pub struct ComposePushCommand {
12 pub config: ComposeConfig,
14 pub include_deps: bool,
16 pub ignore_push_failures: bool,
18 pub quiet: bool,
20 pub services: Vec<String>,
22}
23
24#[derive(Debug, Clone)]
26pub struct PushResult {
27 pub output: String,
29 pub success: bool,
31}
32
33impl ComposePushCommand {
34 #[must_use]
36 pub fn new() -> Self {
37 Self::default()
38 }
39
40 #[must_use]
42 pub fn file<P: Into<std::path::PathBuf>>(mut self, file: P) -> Self {
43 self.config.files.push(file.into());
44 self
45 }
46
47 #[must_use]
49 pub fn project_name(mut self, name: impl Into<String>) -> Self {
50 self.config.project_name = Some(name.into());
51 self
52 }
53
54 #[must_use]
56 pub fn include_deps(mut self) -> Self {
57 self.include_deps = true;
58 self
59 }
60
61 #[must_use]
63 pub fn ignore_push_failures(mut self) -> Self {
64 self.ignore_push_failures = true;
65 self
66 }
67
68 #[must_use]
70 pub fn quiet(mut self) -> Self {
71 self.quiet = true;
72 self
73 }
74
75 #[must_use]
77 pub fn service(mut self, service: impl Into<String>) -> Self {
78 self.services.push(service.into());
79 self
80 }
81
82 #[must_use]
84 pub fn services<I, S>(mut self, services: I) -> Self
85 where
86 I: IntoIterator<Item = S>,
87 S: Into<String>,
88 {
89 self.services.extend(services.into_iter().map(Into::into));
90 self
91 }
92
93 fn build_args(&self) -> Vec<String> {
94 let mut args = vec!["push".to_string()];
95
96 if self.include_deps {
98 args.push("--include-deps".to_string());
99 }
100 if self.ignore_push_failures {
101 args.push("--ignore-push-failures".to_string());
102 }
103 if self.quiet {
104 args.push("--quiet".to_string());
105 }
106
107 args.extend(self.services.clone());
109
110 args
111 }
112}
113
114#[async_trait]
115impl ComposeCommand for ComposePushCommand {
116 type Output = PushResult;
117
118 fn get_config(&self) -> &ComposeConfig {
119 &self.config
120 }
121
122 fn get_config_mut(&mut self) -> &mut ComposeConfig {
123 &mut self.config
124 }
125
126 async fn execute_compose(&self, args: Vec<String>) -> Result<Self::Output> {
127 let output = self.execute_compose_command(args).await?;
128
129 Ok(PushResult {
130 output: output.stdout,
131 success: output.success,
132 })
133 }
134
135 async fn execute(&self) -> Result<Self::Output> {
136 let args = self.build_args();
137 self.execute_compose(args).await
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn test_push_command_basic() {
147 let cmd = ComposePushCommand::new();
148 let args = cmd.build_args();
149 assert_eq!(args[0], "push");
150 }
151
152 #[test]
153 fn test_push_command_with_flags() {
154 let cmd = ComposePushCommand::new()
155 .include_deps()
156 .ignore_push_failures()
157 .quiet();
158 let args = cmd.build_args();
159 assert!(args.contains(&"--include-deps".to_string()));
160 assert!(args.contains(&"--ignore-push-failures".to_string()));
161 assert!(args.contains(&"--quiet".to_string()));
162 }
163
164 #[test]
165 fn test_push_command_with_services() {
166 let cmd = ComposePushCommand::new().service("web").service("api");
167 let args = cmd.build_args();
168 assert!(args.contains(&"web".to_string()));
169 assert!(args.contains(&"api".to_string()));
170 }
171}