Skip to content

Commit

Permalink
feat: add manifest support
Browse files Browse the repository at this point in the history
  • Loading branch information
tmlye committed Feb 20, 2024
1 parent d0f2bb6 commit 8578c90
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 36 deletions.
121 changes: 86 additions & 35 deletions src/commands/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
use dialoguer::{FuzzySelect, Input};
use difference::{Difference, Changeset};
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::Path;
use super::CommandBase;
Expand Down Expand Up @@ -65,6 +67,8 @@ pub struct Deploy {
port: Option<u16>,
#[arg(long, help = "Organization to deploy to")]
org: Option<String>,
#[arg(short, long, help = "Path to molnett manifest")]
manifest: Option<String>,
}

impl Deploy {
Expand All @@ -86,58 +90,43 @@ impl Deploy {
&self.name
);

let existing_svc: Option<Service>;
if let Err(e) = response {
existing_svc = None;
if let Some(reqwest::StatusCode::NOT_FOUND) = e.status() {
// User needs to set every attribute if service does not exist yet
if self.image.is_none() || self.port.is_none() {
return Err(anyhow!("Image and port are mandatory if service does not exist"))
let existing_svc = match response {
Ok(svc) => svc,
Err(e) => match e.status() {
Some(reqwest::StatusCode::NOT_FOUND) => {
return self.create_new_service(base, token, &org_name)
},
Some(reqwest::StatusCode::UNAUTHORIZED) => {
return Err(anyhow!("Unauthorized, please login first"))
},
_ => {
return Err(anyhow!("Could not check whether service exists or not"))
}
} else if let Some(reqwest::StatusCode::UNAUTHORIZED) = e.status() {
return Err(anyhow!("Unauthorized, please login first"))
} else {
return Err(anyhow!("Could not check whether service exists or not"))
}
} else {
existing_svc = Some(response.unwrap());
}
};

let mut new_svc: Service;
if existing_svc.is_some() {
new_svc = existing_svc.clone().unwrap();
let new_svc = if self.manifest.is_some() {
self.construct_service_from_args()?
} else {
let mut new_svc = existing_svc.clone();
if let Some(image) = &self.image {
new_svc.image = image.to_string()
}
if let Some(port) = self.port {
new_svc.container_port = port
}
} else {
new_svc = Service {
name: self.name.clone(),
image: self.image.clone().unwrap(),
container_port: self.port.clone().unwrap()
}
new_svc
};

if let Some(false) = self.no_confirm {
if existing_svc.is_some() && existing_svc.clone().unwrap() == new_svc {
if existing_svc == new_svc {
println!("no changes detected");
return Ok(())
}
let existing_svc_yaml = if existing_svc.is_some() {
serde_yaml::to_string(&existing_svc)?
} else {
"".to_string()
};
let existing_svc_yaml = serde_yaml::to_string(&existing_svc)?;
let new_svc_yaml = serde_yaml::to_string(&new_svc)?;
self.render_diff(existing_svc_yaml, new_svc_yaml)?;
let selection = FuzzySelect::with_theme(&dialoguer::theme::ColorfulTheme::default())
.with_prompt("Do you want to apply the above changes?")
.items(&["no", "yes"])
.default(0)
.interact()
.unwrap();
let selection = self.user_confirmation();
if selection == 0 {
println!("Cancelling...");
return Ok(())
Expand All @@ -149,6 +138,68 @@ impl Deploy {
Ok(())
}

fn create_new_service(&self, base: &CommandBase, token: &str, org_name: &str) -> Result<()> {
let svc = self.construct_service_from_args()?;

if let Some(false) = self.no_confirm {
let new_svc_yaml = serde_yaml::to_string(&svc)?;
self.render_diff("".to_string(), new_svc_yaml)?;
}

let selection = self.user_confirmation();
if selection == 0 {
println!("Cancelling...");
return Ok(())
}

let result = base.api_client().deploy_service(token, org_name, &self.env, svc)?;
println!("Service {} deployed", result.name);
Ok(())
}

fn construct_service_from_args(&self) -> Result<Service> {
if self.manifest.is_some() {
if self.image.is_some() || self.port.is_some() {
return Err(anyhow!("CLI arguments for service attributes can not be used together with manifest"))
}

let svc = self.read_manifest()?;
if self.name != svc.name {
return Err(anyhow!("Name given as CLI argument needs to match name in manifest"))
}

return Ok(svc)
} else {
// User needs to set every attribute if service does not exist yet
if self.image.is_none() || self.port.is_none() {
return Err(anyhow!("Image and port are mandatory if service does not exist"))
}

return Ok(Service {
name: self.name.clone(),
image: self.image.clone().unwrap(),
container_port: self.port.clone().unwrap()
})
}
}

fn user_confirmation(&self) -> usize {
FuzzySelect::with_theme(&dialoguer::theme::ColorfulTheme::default())
.with_prompt("Do you want to apply the above changes?")
.items(&["no", "yes"])
.default(0)
.interact()
.unwrap()
}

fn read_manifest(&self) -> Result<Service> {
let file_path = self.manifest.clone().unwrap();
let mut file_content = String::new();
File::open(file_path)?.read_to_string(&mut file_content)?;
let svc = serde_yaml::from_str(&file_content)?;
Ok(svc)
}

fn render_diff(&self, a: String, b: String) -> Result<()> {
let Changeset { diffs, .. } = Changeset::new(&a, &b, "\n");
let mut t = term::stdout().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::Result;
use camino::Utf8PathBuf;
use clap::{Parser, Subcommand};
use crate::config::user::UserConfig;
use commands::{CommandBase, environments};
use commands::CommandBase;
mod api;
mod commands;
mod config;
Expand Down

0 comments on commit 8578c90

Please sign in to comment.