Make CDH great (...not again) #3

Merged
allanger merged 7 commits from refs/pull/3/head into main 2023-01-16 20:05:07 +00:00
5 changed files with 126 additions and 52 deletions
Showing only changes of commit acb073a915 - Show all commits

10
Cargo.lock generated
View File

@ -56,6 +56,7 @@ version = "0.1.0"
dependencies = [
"build_html",
"clap",
"clap_complete",
"env_logger",
"handlebars",
"log",
@ -87,6 +88,15 @@ dependencies = [
"termcolor",
]
[[package]]
name = "clap_complete"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce8955d4e8cd4f28f9a01c93a050194c4d131e73ca02f6636bcddbed867014d7"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.1.0"

View File

@ -16,3 +16,5 @@ serde_yaml = "0.9.16"
tabled = "0.10.0"
build_html = "2.1.0"
handlebars = "4.3.1"
clap_complete = "4.0.6"

View File

@ -1,10 +1,10 @@
mod connectors;
mod output;
mod types;
use clap::{Parser, ValueEnum};
use clap::{arg, command, Parser, Subcommand, ValueEnum};
use connectors::{Argo, Connector, Helm, Helmfile};
use handlebars::Handlebars;
use log::{debug, error, info, warn};
use output::Output;
use serde::{Deserialize, Serialize};
use serde_json::from_str;
use std::{
@ -12,7 +12,7 @@ use std::{
io::Result,
process::{exit, Command},
};
use tabled::Tabled;
use types::ExecResult;
use version_compare::{Cmp, Version};
use crate::types::{HelmChart, Status};
@ -24,13 +24,22 @@ enum Kinds {
Helmfile,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum Outputs {
Yaml,
HTML,
}
/// Check you helm releaseas managed by Argo
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Type of the
/// How do you install your helm charts
#[clap(long, value_enum)]
kind: Kinds,
/// What kind of output would you like to receive?
#[clap(long, value_enum, default_value = "yaml")]
output: Outputs,
/// Path to the helmfile
#[clap(short, long, value_parser, default_value = "./")]
path: String,
@ -42,6 +51,14 @@ struct Args {
no_sync: bool,
}
#[derive(Debug, Subcommand)]
enum Commands {
#[command(arg_required_else_help = true)]
Generate {
#[arg(value_name = "SHELL", default_missing_value = "zsh")]
shell: clap_complete::shells::Shell,
},
}
/// A struct to write helm repo description to
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
struct Repo {
@ -57,25 +74,7 @@ struct LocalCharts {
version: Option<String>,
}
#[derive(Clone, Tabled, Serialize)]
struct ExecResult {
name: String,
latest_version: String,
current_version: String,
status: Status,
}
// Implementation for the ExecResult struct
impl ExecResult {
fn new(name: String, latest_version: String, current_version: String, status: Status) -> Self {
Self {
name,
latest_version,
current_version,
status,
}
}
}
fn main() {
// Preparations step
@ -109,7 +108,7 @@ fn main() {
// Parse the helmfile
// Handling the result
match handle_result(&result, args.outdated_fail) {
match handle_result(&result, args.outdated_fail, args.output) {
Ok(result) => {
if result {
exit(1);
@ -197,7 +196,11 @@ fn check_chart(result: &mut Vec<ExecResult>, local_chart: &types::HelmChart) ->
}
/// Handle result
fn handle_result(result: &Vec<ExecResult>, outdated_fail: bool) -> Result<bool> {
fn handle_result(
result: &Vec<ExecResult>,
outdated_fail: bool,
output_kind: Outputs,
) -> Result<bool> {
let mut failed = false;
for r in result.clone() {
match r.status {
@ -220,34 +223,12 @@ fn handle_result(result: &Vec<ExecResult>, outdated_fail: bool) -> Result<bool>
}
}
}
let template = r#"
<table>
<tr>
<th>Chart Name</th>
<th>Current Version</th>
<th>Latest Version</th>
<th>Status</th>
</tr>
{{#each this as |tr|}}
<tr>
<th>{{tr.name}}</th>
<th>{{tr.current_version}}</th>
<th>{{tr.latest_version}}</th>
<th>{{tr.status}}</th>
</tr>
{{/each}}
</table>
"#;
let mut reg = Handlebars::new();
// TODO: Handle this error
reg.register_template_string("html_table", template)
.unwrap();
match reg.render("html_table", &result) {
Ok(res) => println!("{}", res),
Err(err) => error!("{}", err),
match output_kind {
Outputs::Yaml => print!("{}", output::YAML::print(result)?),
Outputs::HTML => print!("{}", output::HTML::print(result)?),
};
Ok(failed)
}

61
src/output/mod.rs Normal file
View File

@ -0,0 +1,61 @@
use std::io::{Result, Error, ErrorKind};
use handlebars::Handlebars;
use log::error;
use crate::types::ExecResult;
pub(crate) trait Output {
fn print(data: &Vec<ExecResult>) -> Result<String>;
}
pub(crate) struct HTML;
impl Output for HTML {
fn print(data: &Vec<ExecResult>) -> Result<String> {
// To generate htlm output, I have to use templates because I haven't found any other good
// solution
let template = r#"
<table>
<tr>
<th>Chart Name</th>
<th>Current Version</th>
<th>Latest Version</th>
<th>Status</th>
</tr>
{{#each this as |tr|}}
<tr>
<th>{{tr.name}}</th>
<th>{{tr.current_version}}</th>
<th>{{tr.latest_version}}</th>
<th>{{tr.status}}</th>
</tr>
{{/each}}
</table>
"#;
let mut reg = Handlebars::new();
// TODO: Handle this error
reg.register_template_string("html_table", template)
.unwrap();
match reg.render("html_table", &data) {
Ok(res) => Ok(res),
Err(err) => {
error!("{}", err);
return Err(Error::new(ErrorKind::InvalidInput, err.to_string()));
}
}
}
}
pub(crate) struct YAML;
impl Output for YAML {
fn print(data: &Vec<ExecResult>) -> Result<String> {
match serde_yaml::to_string(&data) {
Ok(res) => return Ok(res),
Err(err) => return Err(Error::new(ErrorKind::InvalidData, err.to_string())),
}
}
}

View File

@ -1,5 +1,6 @@
use serde::{Deserialize, Serialize};
use std::fmt;
use tabled::Tabled;
/// Struct for parsing charts info from helmfile
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
@ -15,7 +16,7 @@ pub(crate) struct HelmRepo {
pub(crate) url: String,
}
#[derive(Clone, Serialize)]
#[derive(Clone, Serialize, Deserialize)]
pub(crate) enum Status {
Uptodate,
Outdated,
@ -31,3 +32,22 @@ impl fmt::Display for Status {
}
}
}
#[derive(Clone, Tabled, Serialize, Deserialize)]
pub(crate) struct ExecResult {
pub(crate) name: String,
pub(crate) latest_version: String,
pub(crate) current_version: String,
pub(crate) status: Status,
}
impl ExecResult {
pub(crate) fn new(name: String, latest_version: String, current_version: String, status: Status) -> Self {
Self {
name,
latest_version,
current_version,
status,
}
}
}