diff --git a/src/api/mod.rs b/src/api/mod.rs index 6331bbe..36ca94e 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -72,6 +72,7 @@ impl APIClient { match response.status() { StatusCode::CREATED => Ok(serde_json::from_str(&response.text()?).with_context(|| "Failed to deserialize org")?), StatusCode::UNAUTHORIZED => Err(anyhow!("Unauthorized, please login first")), + StatusCode::CONFLICT => Err(anyhow!("Organization already exists")), StatusCode::NOT_FOUND => Err(anyhow!("Org not found")), StatusCode::BAD_REQUEST => Err(anyhow!("Bad request: {}", response.text()?)), _ => Err(anyhow!("Failed to deploy service. API returned {} - {}", response.status(), response.text()?)) @@ -101,9 +102,25 @@ impl APIClient { match response.status() { StatusCode::CREATED => Ok(serde_json::from_str(&response.text()?).with_context(|| "Failed to deserialize env")?), StatusCode::UNAUTHORIZED => Err(anyhow!("Unauthorized, please login first")), + StatusCode::CONFLICT => Err(anyhow!("Environment already exists")), StatusCode::NOT_FOUND => Err(anyhow!("Org not found")), StatusCode::BAD_REQUEST => Err(anyhow!("Bad request: {}", response.text()?)), - _ => Err(anyhow!("Failed to deploy service. API returned {} - {}", response.status(), response.text()?)) + _ => Err(anyhow!("Failed to create environment. API returned {} - {}", response.status(), response.text()?)) + } + } + + pub fn delete_environment( + &self, + token: &str, + org_name: &str, + name: &str + ) -> anyhow::Result<()> { + let url = format!("{}/orgs/{}/envs/{}", self.base_url, org_name, name); + let response = self.delete(&url, token)?; + match response.status() { + StatusCode::NO_CONTENT => Ok(()), + StatusCode::NOT_FOUND => Err(anyhow!("Environment does not exist")), + _ => Err(anyhow!("Failed to delete environment. API returned {} - {}", response.status(), response.text()?)) } } diff --git a/src/commands/environments.rs b/src/commands/environments.rs index 36b1a59..e4df1bc 100644 --- a/src/commands/environments.rs +++ b/src/commands/environments.rs @@ -1,6 +1,7 @@ use super::CommandBase; use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; +use dialoguer::FuzzySelect; use tabled::Table; #[derive(Debug, Parser)] @@ -22,6 +23,7 @@ impl Environments { match &self.command { Some(Commands::Create(create)) => create.execute(base), Some(Commands::List(list)) => list.execute(base), + Some(Commands::Delete(delete)) => delete.execute(base), None => Ok(()), } } @@ -35,6 +37,8 @@ pub enum Commands { /// List environments #[command()] List(List), + /// Delete an environment + Delete(Delete), } #[derive(Debug, Parser)] @@ -80,3 +84,37 @@ impl List { Ok(()) } } + +#[derive(Debug, Parser)] +pub struct Delete { + #[arg(help = "Name of the environment")] + name: String, + #[arg(long, help = "Skip confirmation", default_missing_value("true"), default_value("false"), num_args(0..=1), require_equals(true))] + no_confirm: Option, +} + +impl Delete { + pub fn execute(&self, base: &CommandBase) -> Result<()> { + let org_name = base.get_org()?; + let token = base + .user_config() + .get_token() + .ok_or_else(|| anyhow!("No token found. Please login first."))?; + + if let Some(false) = self.no_confirm { + let prompt = format!("Org: {}, Environment: {}. Are you sure you want to delete this environment and everything in it?", org_name, self.name); + FuzzySelect::with_theme(&dialoguer::theme::ColorfulTheme::default()) + .with_prompt(prompt) + .items(&["no", "yes"]) + .default(0) + .interact() + .unwrap(); + } + + base.api_client() + .delete_environment(token, &org_name, &self.name)?; + + println!("Environment {} deleted", self.name); + Ok(()) + } +}