Skip to content

Commit

Permalink
include_tasks like ansible
Browse files Browse the repository at this point in the history
  • Loading branch information
flawiddsouza committed Nov 13, 2024
1 parent 1627a61 commit adb41e9
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 76 deletions.
15 changes: 15 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Debug, Deserialize)]
pub struct Debug(pub IndexMap<String, String>);
Expand All @@ -10,3 +11,17 @@ pub struct Register {
pub stderr: String,
pub rc: i32,
}

#[derive(Debug, Deserialize)]
pub struct Task {
pub name: String,
pub shell: Option<String>,
pub command: Option<String>,
pub register: Option<String>,
pub debug: Option<Debug>,
pub vars: Option<IndexMap<String, String>>,
pub chdir: Option<String>,
pub when: Option<String>,
pub r#loop: Option<Vec<Value>>,
pub include_tasks: Option<String>,
}
179 changes: 103 additions & 76 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use colored::Colorize;
use indexmap::IndexMap;
use serde::Deserialize;
use serde_json::Value;
use ssh2::Session;
use std::path::Path;
use std::process::exit;

Expand All @@ -29,21 +30,99 @@ struct Deployment {
name: String,
hosts: String,
chdir: Option<String>,
tasks: Vec<Task>,
tasks: Vec<common::Task>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
struct Task {
name: String,
shell: Option<String>,
command: Option<String>,
register: Option<String>,
debug: Option<common::Debug>,
vars: Option<IndexMap<String, String>>,
chdir: Option<String>,
when: Option<String>,
r#loop: Option<Vec<Value>>,
fn process_tasks(
tasks: &[common::Task],
is_localhost: bool,
session: Option<&Session>,
dep_chdir: Option<&str>,
vars_map: &mut IndexMap<String, Value>,
deploy_file_dir: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
for task in tasks {
if !modules::when::process(&task.when, vars_map) {
println!("{}", format!("Skipping task: {}\n", task.name).yellow());
continue;
}

println!("{}", format!("Executing task: {}", task.name).cyan());

let task_chdir = task.chdir.as_deref().or(dep_chdir); // Use task-level chdir if present, otherwise use top-level chdir

if let Some(vars) = &task.vars {
for (key, value) in vars {
let evaluated_value = utils::replace_placeholders_vars(&value, vars_map);
vars_map.insert(key.clone(), evaluated_value);
}
}

// Debug print to verify vars_map
// println!("Vars map: {:?}", vars_map);

let loop_items = task.r#loop.clone().unwrap_or_else(|| vec![Value::Null]);

for item in loop_items {
vars_map.shift_remove("item");

if !item.is_null() {
vars_map.insert("item".to_string(), item.clone());
}

if let Some(debug) = &task.debug {
modules::debug::process(debug, vars_map);
}

if let Some(shell_command) = &task.shell {
let commands = utils::split_commands(shell_command);
modules::command::process(
commands,
is_localhost,
session,
true,
task_chdir,
task.register.as_ref(),
vars_map,
)?;
}

if let Some(command) = &task.command {
let commands = utils::split_commands(command);
modules::command::process(
commands,
is_localhost,
session,
false,
task_chdir,
task.register.as_ref(),
vars_map,
)?;
}

if let Some(include_file) = &task.include_tasks {
println!(
"{}",
format!("Including tasks from: {}\n", include_file).blue()
);
let include_file_path = deploy_file_dir.join(include_file);
let included_tasks =
modules::include_tasks::process(include_file_path.to_str().unwrap())?;
process_tasks(
&included_tasks,
is_localhost,
session,
task_chdir,
vars_map,
deploy_file_dir,
)?;
}
}

println!();
}

Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand Down Expand Up @@ -114,6 +193,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}

let deploy_file_path = Path::new(deploy_file);
let deploy_file_dir = deploy_file_path.parent().unwrap_or(Path::new("."));

for dep in deployments {
println!("{}", format!("Starting deployment: {}\n", dep.name).green());

Expand Down Expand Up @@ -148,69 +230,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
None
};

for task in &dep.tasks {
if !modules::when::process(&task.when, &vars_map) {
println!("{}", format!("Skipping task: {}\n", task.name).yellow());
continue;
}

println!("{}", format!("Executing task: {}", task.name).cyan());

let task_chdir = task.chdir.as_deref().or(dep.chdir.as_deref()); // Use task-level chdir if present, otherwise use top-level chdir

if let Some(vars) = &task.vars {
for (key, value) in vars {
let evaluated_value =
utils::replace_placeholders_vars(&value, &vars_map);
vars_map.insert(key.clone(), evaluated_value);
}
}

// Debug print to verify vars_map
// println!("Vars map: {:?}", vars_map);

let loop_items = task.r#loop.clone().unwrap_or_else(|| vec![Value::Null]);

for item in loop_items {
vars_map.shift_remove("item");

if !item.is_null() {
vars_map.insert("item".to_string(), item.clone());
}

if let Some(debug) = &task.debug {
modules::debug::process(debug, &vars_map);
}

if let Some(shell_command) = &task.shell {
let commands = utils::split_commands(shell_command);
modules::command::process(
commands,
is_localhost,
session.as_ref(),
true,
task_chdir,
task.register.as_ref(),
&mut vars_map,
)?;
}

if let Some(command) = &task.command {
let commands = utils::split_commands(command);
modules::command::process(
commands,
is_localhost,
session.as_ref(),
false,
task_chdir,
task.register.as_ref(),
&mut vars_map,
)?;
}
}

println!();
}
process_tasks(
&dep.tasks,
is_localhost,
session.as_ref(),
dep.chdir.as_deref(),
&mut vars_map,
deploy_file_dir,
)?;
} else {
eprintln!(
"{}",
Expand Down
7 changes: 7 additions & 0 deletions src/modules/include_tasks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use crate::common::Task;
use crate::utils;

pub fn process(include_file: &str) -> Result<Vec<Task>, Box<dyn std::error::Error>> {
let included_tasks: Vec<Task> = utils::read_yaml(include_file)?;
Ok(included_tasks)
}
1 change: 1 addition & 0 deletions src/modules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod command;
pub mod debug;
pub mod include_tasks;
pub mod when;
7 changes: 7 additions & 0 deletions test-ymls/include-tasks.include.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-
name: Task 1
command: echo "Include Task 1"

-
name: Task 2
command: echo "Include Task 2"
8 changes: 8 additions & 0 deletions test-ymls/include-tasks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- name: Test
hosts: test
tasks:
- name: Include tasks
include_tasks: include-tasks.include.yml

- name: Task after include tasks
command: echo "Task after include tasks"
18 changes: 18 additions & 0 deletions test-ymls/include-tasks.yml.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Starting deployment: Test

Executing task: Include tasks
Including tasks from: include-tasks.include.yml

Executing task: Task 1
> echo "Include Task 1"
Include Task 1

Executing task: Task 2
> echo "Include Task 2"
Include Task 2


Executing task: Task after include tasks
> echo "Task after include tasks"
Task after include tasks

6 changes: 6 additions & 0 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,9 @@ fn loop_item() {
setup();
run_tests_for_both_inventories("test-ymls/loop-item.yml", false, "");
}

#[test]
fn include_tasks() {
setup();
run_tests_for_both_inventories("test-ymls/include-tasks.yml", false, "");
}

0 comments on commit adb41e9

Please sign in to comment.