docker_wrapper/command/manifest/
push.rs1use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone)]
9pub struct ManifestPushResult {
10 pub manifest_list: String,
12 pub digest: Option<String>,
14 pub output: String,
16 pub success: bool,
18}
19
20impl ManifestPushResult {
21 fn parse(manifest_list: &str, output: &CommandOutput) -> Self {
23 let digest = output
25 .stdout
26 .lines()
27 .find(|line| line.starts_with("sha256:"))
28 .map(|s| s.trim().to_string());
29
30 Self {
31 manifest_list: manifest_list.to_string(),
32 digest,
33 output: output.stdout.clone(),
34 success: output.success,
35 }
36 }
37}
38
39#[derive(Debug, Clone)]
62pub struct ManifestPushCommand {
63 manifest_list: String,
65 insecure: bool,
67 purge: bool,
69 pub executor: CommandExecutor,
71}
72
73impl ManifestPushCommand {
74 #[must_use]
80 pub fn new(manifest_list: impl Into<String>) -> Self {
81 Self {
82 manifest_list: manifest_list.into(),
83 insecure: false,
84 purge: false,
85 executor: CommandExecutor::new(),
86 }
87 }
88
89 #[must_use]
91 pub fn insecure(mut self) -> Self {
92 self.insecure = true;
93 self
94 }
95
96 #[must_use]
98 pub fn purge(mut self) -> Self {
99 self.purge = true;
100 self
101 }
102
103 fn build_args(&self) -> Vec<String> {
105 let mut args = vec!["manifest".to_string(), "push".to_string()];
106
107 if self.insecure {
108 args.push("--insecure".to_string());
109 }
110
111 if self.purge {
112 args.push("--purge".to_string());
113 }
114
115 args.push(self.manifest_list.clone());
116
117 args.extend(self.executor.raw_args.clone());
118
119 args
120 }
121}
122
123#[async_trait]
124impl DockerCommand for ManifestPushCommand {
125 type Output = ManifestPushResult;
126
127 fn get_executor(&self) -> &CommandExecutor {
128 &self.executor
129 }
130
131 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
132 &mut self.executor
133 }
134
135 fn build_command_args(&self) -> Vec<String> {
136 self.build_args()
137 }
138
139 async fn execute(&self) -> Result<Self::Output> {
140 let args = self.build_args();
141 let output = self.execute_command(args).await?;
142 Ok(ManifestPushResult::parse(&self.manifest_list, &output))
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_manifest_push_basic() {
152 let cmd = ManifestPushCommand::new("myapp:latest");
153 let args = cmd.build_args();
154 assert_eq!(args, vec!["manifest", "push", "myapp:latest"]);
155 }
156
157 #[test]
158 fn test_manifest_push_with_insecure() {
159 let cmd = ManifestPushCommand::new("myapp:latest").insecure();
160 let args = cmd.build_args();
161 assert!(args.contains(&"--insecure".to_string()));
162 }
163
164 #[test]
165 fn test_manifest_push_with_purge() {
166 let cmd = ManifestPushCommand::new("myapp:latest").purge();
167 let args = cmd.build_args();
168 assert!(args.contains(&"--purge".to_string()));
169 }
170
171 #[test]
172 fn test_manifest_push_all_options() {
173 let cmd = ManifestPushCommand::new("myapp:latest").insecure().purge();
174 let args = cmd.build_args();
175 assert!(args.contains(&"--insecure".to_string()));
176 assert!(args.contains(&"--purge".to_string()));
177 }
178
179 #[test]
180 fn test_manifest_push_result_parse_with_digest() {
181 let output = CommandOutput {
182 stdout: "sha256:abc123def456".to_string(),
183 stderr: String::new(),
184 exit_code: 0,
185 success: true,
186 };
187 let result = ManifestPushResult::parse("myapp:latest", &output);
188 assert_eq!(result.digest, Some("sha256:abc123def456".to_string()));
189 }
190}