From e2ecf2bfe63f3ac3f97b134d5899cbab72958a60 Mon Sep 17 00:00:00 2001 From: Blake Mealey Date: Fri, 15 Dec 2023 20:57:36 -0600 Subject: [PATCH] feat(mantle): add json and yaml formats to diff command --- mantle/mantle/src/cli.rs | 17 ++++++++++++ mantle/mantle/src/commands/diff.rs | 36 +++++++++++++++++++++++-- mantle/rbx_mantle/src/resource_graph.rs | 5 ++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/mantle/mantle/src/cli.rs b/mantle/mantle/src/cli.rs index 74e4739..c25aa6f 100644 --- a/mantle/mantle/src/cli.rs +++ b/mantle/mantle/src/cli.rs @@ -42,6 +42,21 @@ fn get_app() -> App<'static, 'static> { .help("The label of the environment to deploy to. If not specified, attempts to match the current git branch to each environment's `branches` property.") .value_name("ENVIRONMENT") .takes_value(true)) + .arg( + Arg::with_name("output") + .long("output") + .short("o") + .help("A file path to print the diff to, if a format is provided") + .value_name("FILE") + .takes_value(true)) + .arg( + Arg::with_name("format") + .long("format") + .short("f") + .help("The format to print the diff in") + .value_name("FORMAT") + .takes_value(true) + .possible_values(&["json","yaml"])) ) .subcommand( SubCommand::with_name("destroy") @@ -167,6 +182,8 @@ pub async fn run_with(args: Vec) -> i32 { commands::diff::run( diff_matches.value_of("PROJECT"), diff_matches.value_of("environment"), + diff_matches.value_of("output"), + diff_matches.value_of("format"), ) .await } diff --git a/mantle/mantle/src/commands/diff.rs b/mantle/mantle/src/commands/diff.rs index 4c61b7d..439de56 100644 --- a/mantle/mantle/src/commands/diff.rs +++ b/mantle/mantle/src/commands/diff.rs @@ -1,4 +1,4 @@ -use std::str; +use std::{fs, str}; use difference::Changeset; use yansi::Paint; @@ -57,7 +57,12 @@ fn print_diff(diff: ResourceGraphDiff) { } } -pub async fn run(project: Option<&str>, environment: Option<&str>) -> i32 { +pub async fn run( + project: Option<&str>, + environment: Option<&str>, + output: Option<&str>, + format: Option<&str>, +) -> i32 { logger::start_action("Loading project:"); let (project_path, config) = match load_project_config(project) { Ok(v) => v, @@ -98,8 +103,35 @@ pub async fn run(project: Option<&str>, environment: Option<&str>) -> i32 { match diff { Ok(diff) => { + let outputs_string = format.map(|format| match format { + "json" => serde_json::to_string_pretty(&diff) + .map(|x| x + "\n") + .map_err(|e| e.to_string()), + "yaml" => serde_yaml::to_string(&diff).map_err(|e| e.to_string()), + _ => Err(format!("Unknown format: {}", format)), + }); + print_diff(diff); logger::end_action("Succeeded"); + + if let Some(outputs_string) = outputs_string { + if let Ok(outputs_string) = outputs_string { + if let Some(output) = output { + if let Err(e) = fs::write(output, outputs_string).map_err(|e| { + format!("Unable to write outputs file: {}\n\t{}", output, e) + }) { + logger::log(Paint::red(e)); + return 1; + } + } else { + print!("{}", outputs_string); + } + } else { + logger::log(Paint::red("Failed to serialize outputs")); + return 1; + } + } + return 0; } Err(e) => { diff --git a/mantle/rbx_mantle/src/resource_graph.rs b/mantle/rbx_mantle/src/resource_graph.rs index e990c0c..93a1d02 100644 --- a/mantle/rbx_mantle/src/resource_graph.rs +++ b/mantle/rbx_mantle/src/resource_graph.rs @@ -646,6 +646,7 @@ where } } +#[derive(Serialize)] pub struct ResourceGraphDiff { pub removals: BTreeMap, pub additions: BTreeMap, @@ -653,21 +654,25 @@ pub struct ResourceGraphDiff { pub dependency_changes: BTreeMap, } +#[derive(Serialize)] pub struct ResourceRemoval { pub previous_inputs_hash: String, pub previous_outputs_hash: String, } +#[derive(Serialize)] pub struct ResourceAddition { pub current_inputs_hash: String, } +#[derive(Serialize)] pub struct ResourceChange { pub previous_inputs_hash: String, pub previous_outputs_hash: String, pub current_inputs_hash: String, } +#[derive(Serialize)] pub struct ResourceDependencyChange { pub previous_inputs_hash: String, pub previous_outputs_hash: String,