Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
TreehouseFalcon committed Dec 21, 2023
2 parents 4a1ede2 + 2ce8b25 commit 71899ac
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 14 deletions.
7 changes: 4 additions & 3 deletions mantle/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mantle/logger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ where
S: Display,
{
let line_prefix = get_line_prefix();
println!("{}", with_prefix(&message, line_prefix));
eprintln!("{}", with_prefix(&message, line_prefix));
}

pub fn start_action<S>(title: S)
Expand Down
3 changes: 2 additions & 1 deletion mantle/mantle/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mantle"
version = "0.11.11"
version = "0.11.13"
edition = "2021"

[dependencies]
Expand All @@ -14,6 +14,7 @@ serde_json = { version = "1.0.59" }
serde_yaml = { version = "0.8" }
serde = { version = "1.0", features = ["derive"] }
clap = "2.33.0"
difference = "2.0.0"
tokio = { version = "1", features = ["full"] }
yansi = "0.5.0"
log = "0.4.14"
Expand Down
40 changes: 40 additions & 0 deletions mantle/mantle/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,37 @@ fn get_app() -> App<'static, 'static> {
Arg::with_name("allow_purchases")
.long("allow-purchases")
.help("Gives Mantle permission to make purchases with Robux."))
)
.subcommand(
SubCommand::with_name("diff")
.about("Prints the diff between the current state file and project configuration.")
.arg(
Arg::with_name("PROJECT")
.index(1)
.help("The Mantle project: either the path to a directory containing a 'mantle.yml' file or the path to a configuration file. Defaults to the current directory.")
.takes_value(true))
.arg(
Arg::with_name("environment")
.long("environment")
.short("e")
.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")
Expand Down Expand Up @@ -147,6 +178,15 @@ pub async fn run_with(args: Vec<String>) -> i32 {
)
.await
}
("diff", Some(diff_matches)) => {
commands::diff::run(
diff_matches.value_of("PROJECT"),
diff_matches.value_of("environment"),
diff_matches.value_of("output"),
diff_matches.value_of("format"),
)
.await
}
("destroy", Some(destroy_matches)) => {
commands::destroy::run(
destroy_matches.value_of("PROJECT"),
Expand Down
142 changes: 142 additions & 0 deletions mantle/mantle/src/commands/diff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use std::{fs, str};

use difference::Changeset;
use yansi::Paint;

use rbx_mantle::{
config::load_project_config,
project::{load_project, Project},
resource_graph::ResourceGraphDiff,
state::get_desired_graph,
};

fn get_changeset(previous_hash: &str, new_hash: &str) -> Changeset {
Changeset::new(previous_hash, new_hash, "\n")
}

fn print_diff(diff: ResourceGraphDiff) {
for (resource_id, r) in diff.removals.into_iter() {
logger::start_action(format!("{} Removed {}:", Paint::red("-"), resource_id));
logger::log("Inputs:");
logger::log_changeset(get_changeset(&r.previous_inputs_hash, ""));
logger::end_action_without_message();
}

for (resource_id, r) in diff.additions.into_iter() {
logger::start_action(format!("{} Added {}:", Paint::green("+"), resource_id));
logger::log("Inputs:");
logger::log_changeset(get_changeset("", &r.current_inputs_hash));
logger::end_action_without_message();
}

for (resource_id, r) in diff.changes.into_iter() {
logger::start_action(format!("{} Changed {}:", Paint::yellow("~"), resource_id));
logger::log("Inputs:");
logger::log_changeset(get_changeset(
&r.previous_inputs_hash,
&r.current_inputs_hash,
));
logger::end_action_without_message();
}

for (resource_id, r) in diff.dependency_changes.into_iter() {
logger::start_action(format!(
"{} Dependency Changed {}:",
Paint::new("○").dimmed(),
resource_id
));
logger::log("Changed dependencies:");
for dependency_id in r.changed_dependencies.into_iter() {
logger::log(format!(
" {} {}",
Paint::new("-").dimmed(),
Paint::yellow(dependency_id)
))
}
logger::end_action_without_message();
}
}

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,
Err(e) => {
logger::end_action(Paint::red(e));
return 1;
}
};
let Project {
current_graph,
target_config,
owner_config,
..
} = match load_project(project_path.clone(), config, environment).await {
Ok(Some(v)) => v,
Ok(None) => {
logger::end_action("No diff available");
return 0;
}
Err(e) => {
logger::end_action(Paint::red(e));
return 1;
}
};
let mut next_graph =
match get_desired_graph(project_path.as_path(), &target_config, &owner_config) {
Ok(v) => v,
Err(e) => {
logger::end_action(Paint::red(e));
return 1;
}
};
logger::end_action("Succeeded");

logger::start_action("Diffing resource graphs:");

let diff = next_graph.diff(&current_graph);

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;
}
}

0
}
Err(e) => {
logger::end_action(Paint::red(e));
1
}
}
}
1 change: 1 addition & 0 deletions mantle/mantle/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod deploy;
pub mod destroy;
pub mod diff;
pub mod download;
pub mod import;
pub mod outputs;
Expand Down
6 changes: 4 additions & 2 deletions mantle/mantle/src/commands/outputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ pub async fn run(
.collect::<BTreeMap<_, _>>();

let outputs_string = match match format {
"json" => serde_json::to_string_pretty(&outputs_map).map_err(|e| e.to_string()),
"json" => serde_json::to_string_pretty(&outputs_map)
.map(|x| x + "\n")
.map_err(|e| e.to_string()),
"yaml" => serde_yaml::to_string(&outputs_map).map_err(|e| e.to_string()),
_ => Err(format!("Unknown format: {}", format)),
} {
Expand All @@ -62,7 +64,7 @@ pub async fn run(
return 1;
}
} else {
logger::log(outputs_string);
print!("{}", outputs_string);
}

0
Expand Down
2 changes: 1 addition & 1 deletion mantle/rbx_api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "rbx_api"
description = "Make requests to Roblox's web APIs"
version = "0.4.8"
version = "0.4.9"
edition = "2021"
homepage = "https://github.com/blake-mealey/mantle/tree/main/rbx_api"
repository = "https://github.com/blake-mealey/mantle"
Expand Down
11 changes: 7 additions & 4 deletions mantle/rbx_api/src/game_passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ impl RobloxApi {
experience_id: AssetId,
page_cursor: Option<String>,
) -> RobloxApiResult<ListGamePassesResponse> {
let mut req = self.client.get(format!(
"https://games.roblox.com/v1/games/{}/game-passes",
experience_id
));
let mut req = self
.client
.get(format!(
"https://games.roblox.com/v1/games/{}/game-passes",
experience_id
))
.query(&[("limit", 100.to_string())]);
if let Some(page_cursor) = page_cursor {
req = req.query(&[("cursor", &page_cursor)]);
}
Expand Down
2 changes: 1 addition & 1 deletion mantle/rbx_mantle/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "rbx_mantle"
description = "Infra-as-code for Roblox"
version = "0.11.11"
version = "0.11.13"
homepage = "https://mantledeploy.vercel.app"
repository = "https://github.com/blake-mealey/mantle"
authors = ["Blake Mealey <[email protected]>"]
Expand Down
Loading

0 comments on commit 71899ac

Please sign in to comment.