Skip to content

Commit

Permalink
refactor some functions into methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas La Piana committed Jan 7, 2024
1 parent 891f8e0 commit a93b659
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 76 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ name = "rox"
path = "src/lib.rs"

[dependencies]
anyhow = "1.0.79"
chrono = "0.4.31"
clap = { version = "4.4.4", features = ["string", "cargo"] }
cli-table = "0.4.7"
Expand Down
66 changes: 21 additions & 45 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ mod utils;

use crate::cli::{cli_builder, construct_cli};
use crate::execution::{execute_stages, execute_tasks};
use crate::model_injection::{
inject_pipeline_metadata, inject_task_metadata, inject_template_values,
};
use crate::models::{AllResults, Validate};
use crate::models::{PassFail, TaskResult};
use crate::models::JobResults;
use crate::models::TaskResult;
use std::collections::HashMap;
use std::error::Error;

Expand Down Expand Up @@ -42,35 +39,22 @@ pub async fn rox() -> RoxResult<()> {

// Get the file arg from the CLI if set
let file_path = get_filepath_arg_value();
let roxfile = utils::parse_file_contents(utils::load_file(&file_path));
roxfile.validate()?;
let roxfile = models::RoxFile::build(&file_path)?;
utils::print_horizontal_rule();

// Build & Generate the CLI based on the loaded Roxfile
let tasks = inject_task_metadata(roxfile.tasks, &file_path);
let pipelines = inject_pipeline_metadata(roxfile.pipelines);
let docs = roxfile.docs;
let ci = roxfile.ci;
let cli = construct_cli(&tasks, &pipelines, &docs, &ci);
let cli = construct_cli(
&roxfile.tasks,
&roxfile.pipelines,
&roxfile.docs,
&roxfile.ci,
);
let cli_matches = cli.get_matches();

// Build Hashmaps for Tasks, Templates and Pipelines
let template_map: HashMap<String, models::Template> = std::collections::HashMap::from_iter(
roxfile
.templates
.into_iter()
.flatten()
.map(|template| (template.name.to_owned(), template)),
);
let task_map: HashMap<String, models::Task> = std::collections::HashMap::from_iter(
tasks
roxfile
.tasks
.into_iter()
.map(|task| match task.uses.to_owned() {
Some(task_use) => {
inject_template_values(task, template_map.get(&task_use).unwrap())
}
None => task,
})
.map(|task| (task.name.to_owned(), task)),
);

Expand All @@ -82,7 +66,9 @@ pub async fn rox() -> RoxResult<()> {
let results: Vec<Vec<TaskResult>> = match cli_matches.subcommand_name().unwrap() {
"docs" => {
let docs_map: HashMap<String, models::Docs> = std::collections::HashMap::from_iter(
docs.into_iter()
roxfile
.docs
.into_iter()
.flatten()
.map(|doc| (doc.name.to_owned(), doc)),
);
Expand All @@ -95,14 +81,15 @@ pub async fn rox() -> RoxResult<()> {
std::process::exit(0);
}
"ci" => {
assert!(ci.is_some());
ci::display_ci_status(ci.unwrap()).await;
assert!(roxfile.ci.is_some());
ci::display_ci_status(roxfile.ci.unwrap()).await;
std::process::exit(0);
}
"pl" => {
let pipeline_map: HashMap<String, models::Pipeline> =
std::collections::HashMap::from_iter(
pipelines
roxfile
.pipelines
.into_iter()
.flatten()
.map(|pipeline| (pipeline.name.to_owned(), pipeline)),
Expand All @@ -126,32 +113,21 @@ pub async fn rox() -> RoxResult<()> {
}
_ => unreachable!("Invalid subcommand"),
};
let results = AllResults {
let results = JobResults {
job_name: subcommand_name.to_string(),
execution_time: execution_start,
results: results.into_iter().flatten().collect(),
};

let log_path = logs::write_logs(&results);
println!("> Log file written to: {}", log_path);
results.log_results();

output::display_execution_results(&results);
println!(
"> Total elapsed time: {}s | {}ms",
start.elapsed().as_secs(),
start.elapsed().as_millis(),
);
nonzero_exit_if_failure(&results);
results.check_results();

Ok(())
}

/// Throw a non-zero exit if any Task(s) had a failing result
pub fn nonzero_exit_if_failure(results: &AllResults) {
// TODO: Figure out a way to get this info without looping again
for result in results.results.iter() {
if result.result == PassFail::Fail {
std::process::exit(2)
}
}
}
6 changes: 3 additions & 3 deletions src/logs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::models::AllResults;
use crate::models::JobResults;
use crate::output::display_execution_results;

const LOG_DIR: &str = ".rox";
Expand All @@ -12,7 +12,7 @@ pub fn display_logs(number: &i8) {
.unwrap();
filenames.sort();

let results: Vec<AllResults> = filenames
let results: Vec<JobResults> = filenames
.iter()
.rev()
.take(*number as usize)
Expand All @@ -29,7 +29,7 @@ pub fn display_logs(number: &i8) {
}

/// Write the execution results to a log file
pub fn write_logs(results: &AllResults) -> String {
pub fn write_logs(results: &JobResults) -> String {
let filename = format!("rox-{}.log.yaml", chrono::Utc::now().to_rfc3339());
let filepath = format!("{}/{}", LOG_DIR, filename);

Expand Down
76 changes: 62 additions & 14 deletions src/models.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! Contains the Structs for the Schema of the Roxfile
//! as well as the validation logic.
use crate::logs;
use crate::model_injection::{
inject_pipeline_metadata, inject_task_metadata, inject_template_values,
};
use crate::utils::{color_print, ColorEnum};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::fmt;

Expand All @@ -15,12 +21,29 @@ pub struct CiInfo {

/// Format for completed executions
#[derive(Serialize, Deserialize, Debug)]
pub struct AllResults {
pub struct JobResults {
pub job_name: String,
pub execution_time: String,
pub results: Vec<TaskResult>,
}

impl JobResults {
pub fn log_results(&self) {
let log_path = logs::write_logs(self);
println!("> Log file written to: {}", log_path);
}

/// Triggers a non-zero exit if any job failed, otherwise passes.
pub fn check_results(&self) {
// TODO: Figure out a way to get this info without looping again
self.results.iter().for_each(|result| {
if result.result == PassFail::Fail {
std::process::exit(2)
}
});
}
}

/// Enum for task command status
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum PassFail {
Expand Down Expand Up @@ -194,20 +217,45 @@ pub struct RoxFile {
pub additional_files: Option<Vec<String>>,
}

impl Validate for RoxFile {
fn validate(&self) -> Result<(), ValidationError> {
// Task Validation
for task in &self.tasks {
task.validate()?
}
impl RoxFile {
/// Create a new instance of RoxFile from a file path and
/// run all additional validation and metadata injection.
pub fn build(file_path: &str) -> Result<Self> {
let file_string = std::fs::read_to_string(file_path)?;
let mut roxfile: RoxFile = serde_yaml::from_str(&file_string)?;

// Template Validation
if let Some(templates) = &self.templates {
for template in templates {
template.validate()?
}
}
// Templates
let _ = roxfile
.templates
.iter()
.flatten()
.try_for_each(|template| template.validate());
let template_map: HashMap<String, &Template> = std::collections::HashMap::from_iter(
roxfile
.templates
.as_deref()
.into_iter()
.flatten()
.map(|template| (template.name.to_owned(), template)),
);

Ok(())
// Tasks
let _ = roxfile.tasks.iter().try_for_each(|task| task.validate());
roxfile.tasks = inject_task_metadata(roxfile.tasks, file_path);
roxfile.tasks = roxfile
.tasks
.into_iter()
.map(|task| match task.uses.to_owned() {
Some(task_use) => {
inject_template_values(task, template_map.get(&task_use).unwrap())
}
None => task,
})
.collect();

// Pipelines
roxfile.pipelines = inject_pipeline_metadata(roxfile.pipelines);

Ok(roxfile)
}
}
4 changes: 2 additions & 2 deletions src/output.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::models::{AllResults, PassFail};
use crate::models::{JobResults, PassFail};
use cli_table::{format::Justify, print_stdout, Cell, Style, Table};
use colored::Colorize;

/// Print the execution results in a pretty table format
pub fn display_execution_results(results: &AllResults) {
pub fn display_execution_results(results: &JobResults) {
let mut table = Vec::new();

for result in results.results.iter() {
Expand Down
12 changes: 0 additions & 12 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
//! Utility Functions
use crate::models::RoxFile;
use std::fmt::Display;

use colored::Colorize;

/// Load a file into a String
pub fn load_file(file_path: &str) -> String {
std::fs::read_to_string(file_path).expect("Failed to read the Roxfile!")
}

/// Parse a Roxfile into Rust structs
pub fn parse_file_contents(contents: String) -> RoxFile {
let roxfile: RoxFile = serde_yaml::from_str(&contents).expect("Failed to parse the Roxfile!");
roxfile
}

pub enum ColorEnum {
Red,
}
Expand Down

0 comments on commit a93b659

Please sign in to comment.