use std::path::{Path, PathBuf};
use tracing::info;
use crate::shared::command::{CommandError, CommandExecutor};
pub struct AnsibleClient {
working_dir: PathBuf,
command_executor: CommandExecutor,
}
impl AnsibleClient {
#[must_use]
pub fn new<P: Into<PathBuf>>(working_dir: P) -> Self {
Self {
working_dir: working_dir.into(),
command_executor: CommandExecutor::new(),
}
}
pub fn run_playbook(
&self,
playbook: &str,
extra_args: &[&str],
) -> Result<String, CommandError> {
info!(
"Running Ansible playbook '{}' in directory: {}",
playbook,
self.working_dir.display()
);
let playbook_file = format!("{playbook}.yml");
let mut args = vec!["-v", &playbook_file];
args.extend_from_slice(extra_args);
self.command_executor
.run_command("ansible-playbook", &args, Some(&self.working_dir))
.map(|result| result.stdout)
}
#[must_use]
pub fn working_dir(&self) -> &Path {
&self.working_dir
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_should_create_ansible_client_with_valid_parameters() {
let client = AnsibleClient::new("/path/to/config");
assert_eq!(client.working_dir.to_string_lossy(), "/path/to/config");
}
#[test]
fn it_should_create_ansible_client_with_working_directory() {
let client = AnsibleClient::new("/path/to/config");
assert_eq!(client.working_dir.to_string_lossy(), "/path/to/config");
}
#[test]
fn it_should_return_working_directory_path() {
let client = AnsibleClient::new("/test/path");
assert_eq!(client.working_dir(), Path::new("/test/path"));
}
#[test]
fn it_should_construct_pathbuf_from_string() {
let path_str = "/some/test/path";
let client = AnsibleClient::new(path_str);
assert_eq!(client.working_dir(), Path::new(path_str));
}
#[test]
fn it_should_construct_pathbuf_from_path() {
let path = Path::new("/another/test/path");
let client = AnsibleClient::new(path);
assert_eq!(client.working_dir(), path);
}
#[test]
fn it_should_accept_playbook_name_without_extension() {
let client = AnsibleClient::new("/test/path");
let result = client.run_playbook("install-docker", &[]);
assert!(result.is_err());
}
}