use super::{CommandExecutor, CommandOutput, DockerCommand};
use crate::error::Result;
use async_trait::async_trait;
#[derive(Debug, Clone)]
pub struct PushCommand {
image: String,
all_tags: bool,
disable_content_trust: bool,
platform: Option<String>,
quiet: bool,
pub executor: CommandExecutor,
}
impl PushCommand {
#[must_use]
pub fn new<S: Into<String>>(image: S) -> Self {
Self {
image: image.into(),
all_tags: false,
disable_content_trust: false,
platform: None,
quiet: false,
executor: CommandExecutor::new(),
}
}
#[must_use]
pub fn all_tags(mut self) -> Self {
self.all_tags = true;
self
}
#[must_use]
pub fn disable_content_trust(mut self) -> Self {
self.disable_content_trust = true;
self
}
#[must_use]
pub fn platform<S: Into<String>>(mut self, platform: S) -> Self {
self.platform = Some(platform.into());
self
}
#[must_use]
pub fn quiet(mut self) -> Self {
self.quiet = true;
self
}
#[must_use]
pub fn get_image(&self) -> &str {
&self.image
}
#[must_use]
pub fn is_all_tags(&self) -> bool {
self.all_tags
}
#[must_use]
pub fn is_quiet(&self) -> bool {
self.quiet
}
#[must_use]
pub fn get_platform(&self) -> Option<&str> {
self.platform.as_deref()
}
#[must_use]
pub fn is_content_trust_disabled(&self) -> bool {
self.disable_content_trust
}
#[must_use]
pub fn get_executor(&self) -> &CommandExecutor {
&self.executor
}
#[must_use]
pub fn get_executor_mut(&mut self) -> &mut CommandExecutor {
&mut self.executor
}
}
impl Default for PushCommand {
fn default() -> Self {
Self::new("localhost/test:latest")
}
}
#[async_trait]
impl DockerCommand for PushCommand {
type Output = CommandOutput;
fn get_executor(&self) -> &CommandExecutor {
&self.executor
}
fn get_executor_mut(&mut self) -> &mut CommandExecutor {
&mut self.executor
}
fn build_command_args(&self) -> Vec<String> {
let mut args = vec!["push".to_string()];
if self.all_tags {
args.push("--all-tags".to_string());
}
if self.disable_content_trust {
args.push("--disable-content-trust".to_string());
}
if let Some(ref platform) = self.platform {
args.push("--platform".to_string());
args.push(platform.clone());
}
if self.quiet {
args.push("--quiet".to_string());
}
args.push(self.image.clone());
args.extend(self.executor.raw_args.clone());
args
}
async fn execute(&self) -> Result<Self::Output> {
let args = self.build_command_args();
self.execute_command(args).await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_push_command_basic() {
let push_cmd = PushCommand::new("myapp:latest");
let args = push_cmd.build_command_args();
assert_eq!(args, vec!["push", "myapp:latest"]);
assert_eq!(push_cmd.get_image(), "myapp:latest");
assert!(!push_cmd.is_all_tags());
assert!(!push_cmd.is_quiet());
assert!(!push_cmd.is_content_trust_disabled());
assert_eq!(push_cmd.get_platform(), None);
}
#[test]
fn test_push_command_with_all_tags() {
let push_cmd = PushCommand::new("myregistry.com/myapp").all_tags();
let args = push_cmd.build_command_args();
assert!(args.contains(&"--all-tags".to_string()));
assert!(args.contains(&"myregistry.com/myapp".to_string()));
assert_eq!(args[0], "push");
assert!(push_cmd.is_all_tags());
}
#[test]
fn test_push_command_with_platform() {
let push_cmd = PushCommand::new("myapp:latest").platform("linux/arm64");
let args = push_cmd.build_command_args();
assert!(args.contains(&"--platform".to_string()));
assert!(args.contains(&"linux/arm64".to_string()));
assert!(args.contains(&"myapp:latest".to_string()));
assert_eq!(args[0], "push");
assert_eq!(push_cmd.get_platform(), Some("linux/arm64"));
}
#[test]
fn test_push_command_with_quiet() {
let push_cmd = PushCommand::new("myapp:v1.0").quiet();
let args = push_cmd.build_command_args();
assert!(args.contains(&"--quiet".to_string()));
assert!(args.contains(&"myapp:v1.0".to_string()));
assert_eq!(args[0], "push");
assert!(push_cmd.is_quiet());
}
#[test]
fn test_push_command_disable_content_trust() {
let push_cmd = PushCommand::new("registry.com/myapp:stable").disable_content_trust();
let args = push_cmd.build_command_args();
assert!(args.contains(&"--disable-content-trust".to_string()));
assert!(args.contains(&"registry.com/myapp:stable".to_string()));
assert_eq!(args[0], "push");
assert!(push_cmd.is_content_trust_disabled());
}
#[test]
fn test_push_command_all_options() {
let push_cmd = PushCommand::new("myregistry.io/myapp")
.all_tags()
.platform("linux/amd64")
.quiet()
.disable_content_trust();
let args = push_cmd.build_command_args();
assert!(args.contains(&"--all-tags".to_string()));
assert!(args.contains(&"--platform".to_string()));
assert!(args.contains(&"linux/amd64".to_string()));
assert!(args.contains(&"--quiet".to_string()));
assert!(args.contains(&"--disable-content-trust".to_string()));
assert!(args.contains(&"myregistry.io/myapp".to_string()));
assert_eq!(args[0], "push");
assert!(push_cmd.is_all_tags());
assert!(push_cmd.is_quiet());
assert!(push_cmd.is_content_trust_disabled());
assert_eq!(push_cmd.get_platform(), Some("linux/amd64"));
assert_eq!(push_cmd.get_image(), "myregistry.io/myapp");
}
#[test]
fn test_push_command_with_registry_and_namespace() {
let push_cmd = PushCommand::new("registry.example.com:5000/namespace/myapp:v2.1");
let args = push_cmd.build_command_args();
assert_eq!(
args,
vec!["push", "registry.example.com:5000/namespace/myapp:v2.1"]
);
assert_eq!(
push_cmd.get_image(),
"registry.example.com:5000/namespace/myapp:v2.1"
);
}
#[test]
fn test_push_command_docker_hub_format() {
let push_cmd = PushCommand::new("username/repository:tag");
let args = push_cmd.build_command_args();
assert_eq!(args, vec!["push", "username/repository:tag"]);
assert_eq!(push_cmd.get_image(), "username/repository:tag");
}
#[test]
fn test_push_command_order() {
let push_cmd = PushCommand::new("myapp:latest")
.quiet()
.platform("linux/arm64")
.all_tags();
let args = push_cmd.build_command_args();
assert_eq!(args[0], "push");
assert_eq!(args.last(), Some(&"myapp:latest".to_string()));
assert!(args.contains(&"--all-tags".to_string()));
assert!(args.contains(&"--platform".to_string()));
assert!(args.contains(&"linux/arm64".to_string()));
assert!(args.contains(&"--quiet".to_string()));
}
#[test]
fn test_push_command_default() {
let push_cmd = PushCommand::default();
assert_eq!(push_cmd.get_image(), "localhost/test:latest");
}
#[test]
fn test_push_command_local_registry() {
let push_cmd = PushCommand::new("localhost:5000/myapp:dev");
let args = push_cmd.build_command_args();
assert_eq!(args, vec!["push", "localhost:5000/myapp:dev"]);
assert_eq!(push_cmd.get_image(), "localhost:5000/myapp:dev");
}
}