Skip to content

Commit

Permalink
Merge pull request #198 from mindvalley/feat/deployment-status
Browse files Browse the repository at this point in the history
PXP-670: [CLI] Implement the AppSignal integration to the deployment status command
  • Loading branch information
onimsha authored Mar 8, 2024
2 parents 152ca22 + 292f870 commit 05ac637
Show file tree
Hide file tree
Showing 59 changed files with 2,219 additions and 787 deletions.
279 changes: 270 additions & 9 deletions cli/completions/bash/wukong.bash

Large diffs are not rendered by default.

150 changes: 106 additions & 44 deletions cli/completions/fish/wukong.fish

Large diffs are not rendered by default.

258 changes: 258 additions & 0 deletions cli/completions/zsh/_wukong

Large diffs are not rendered by default.

214 changes: 173 additions & 41 deletions cli/src/application_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
};

/// The application config.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct ApplicationConfig {
pub name: String,
pub enable: bool,
Expand Down Expand Up @@ -79,68 +79,137 @@ pub struct ApplicationAddonsConfig {

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct ApplicationConfigs {
pub application: Option<ApplicationConfig>,
pub application: ApplicationConfig,
#[serde(skip)]
config_path: PathBuf,
}

impl FromStr for ApplicationConfigs {
type Err = ApplicationConfigError;

fn from_str(application_config: &str) -> Result<Self, ApplicationConfigError> {
fn from_str(application_config: &str) -> Result<Self, Self::Err> {
toml::from_str::<ApplicationConfigs>(application_config)
.map_err(ApplicationConfigError::BadTomlData)
}
}

impl ApplicationConfigs {
pub fn new() -> Result<Self, ApplicationConfigError> {
pub fn new() -> Self {
let current_dir = std::env::current_dir().expect("Unable to get current working directory");
let config_path = std::path::Path::new(&current_dir).join(".wukong.toml");

if let Ok(file) = std::fs::read_to_string(
config_path
.to_str()
.expect("The config file path is not valid"),
) {
let mut config: ApplicationConfigs =
toml::from_str(&file).map_err(ApplicationConfigError::BadTomlData)?;
Self {
application: ApplicationConfig::default(),
config_path,
}
}

pub fn load() -> Result<Self, ApplicationConfigError> {
#[cfg(feature = "prod")]
{
let current_dir =
std::env::current_dir().expect("Unable to get current working directory");

config.config_path = config_path;
for dir in current_dir.ancestors() {
let config_path = dir.join(".wukong.toml");
if config_path.exists() {
let content = std::fs::read_to_string(
config_path
.to_str()
.expect("The config file path is not valid"),
)
.map_err(|err| match err.kind() {
io::ErrorKind::NotFound => ApplicationConfigError::NotFound {
path: ".wukong.toml",
source: err,
},
io::ErrorKind::PermissionDenied => {
ApplicationConfigError::PermissionDenied {
path: ".wukong.toml",
source: err,
}
}
_ => err.into(),
})?;

return Ok(config);
let mut config: ApplicationConfigs =
toml::from_str(&content).map_err(ApplicationConfigError::BadTomlData)?;
config.config_path = config_path;

return Ok(config);
}
}
}

Ok(Self {
application: None,
config_path,
})
}
#[cfg(not(feature = "prod"))]
{
match std::env::var("WUKONG_DEV_APP_CONFIG_FILE") {
Ok(config_path) => {
let content =
std::fs::read_to_string(&config_path).map_err(|err| match err.kind() {
io::ErrorKind::NotFound => ApplicationConfigError::NotFound {
path: ".wukong.toml",
source: err,
},
io::ErrorKind::PermissionDenied => {
ApplicationConfigError::PermissionDenied {
path: ".wukong.toml",
source: err,
}
}
_ => err.into(),
})?;

pub fn load() -> Result<Self, ApplicationConfigError> {
let current_dir = std::env::current_dir().expect("Unable to get current working directory");
let config_path = std::path::Path::new(&current_dir).join(".wukong.toml");
let mut config: ApplicationConfigs =
toml::from_str(&content).map_err(ApplicationConfigError::BadTomlData)?;
config.config_path = std::path::PathBuf::from(config_path);

return Ok(config);
}
Err(_) => {
let current_dir =
std::env::current_dir().expect("Unable to get current working directory");

let content = std::fs::read_to_string(
config_path
.to_str()
.expect("The config file path is not valid"),
)
.map_err(|err| match err.kind() {
io::ErrorKind::NotFound => ApplicationConfigError::NotFound {
path: ".wukong.toml",
source: err,
},
io::ErrorKind::PermissionDenied => ApplicationConfigError::PermissionDenied {
path: ".wukong.toml",
source: err,
},
_ => err.into(),
})?;

let config = toml::from_str(&content).map_err(ApplicationConfigError::BadTomlData)?;

Ok(config)
for dir in current_dir.ancestors() {
let config_path = dir.join(".wukong.toml");
if config_path.exists() {
let content = std::fs::read_to_string(
config_path
.to_str()
.expect("The config file path is not valid"),
)
.map_err(|err| match err.kind() {
io::ErrorKind::NotFound => ApplicationConfigError::NotFound {
path: ".wukong.toml",
source: err,
},
io::ErrorKind::PermissionDenied => {
ApplicationConfigError::PermissionDenied {
path: ".wukong.toml",
source: err,
}
}
_ => err.into(),
})?;

let mut config: ApplicationConfigs = toml::from_str(&content)
.map_err(ApplicationConfigError::BadTomlData)?;
config.config_path = config_path;

return Ok(config);
}
}
}
}
}

Err(ApplicationConfigError::NotFound {
path: ".wukong.toml",
source: io::Error::new(
io::ErrorKind::NotFound,
"The `.wukong.toml` file is not found in the current directory or any of its parent directories.",
),
})
}

pub fn save(&self) -> Result<(), ApplicationConfigError> {
Expand All @@ -164,3 +233,66 @@ impl ApplicationConfigs {
Ok(serialized)
}
}

#[cfg(test)]
mod test {
use serial_test::serial;

use super::*;

#[test]
#[serial]
fn save_and_load_application_config_file() {
let current_dir = std::env::current_dir().expect("Unable to get current working directory");
let config_path = std::path::Path::new(&current_dir).join(".wukong.toml");
let mut config = ApplicationConfigs::new();

config.config_path = config_path.clone();
config.application.name = "Wukong".to_string();

// 1. save the application config file
config.save().unwrap();

// 2. load the application config file
let saved_config = ApplicationConfigs::load().unwrap();

assert_eq!(saved_config.application.name, config.application.name);
assert_eq!(saved_config.config_path, config.config_path);

// remove the config file
std::fs::remove_file(config_path).unwrap();
}

#[test]
#[serial]
fn load_application_config_file_from_parent_directory() {
let current_dir = std::env::current_dir().expect("Unable to get current working directory");

let temp_dir = current_dir.join("test_temp");
println!("temp dir: {:?}", temp_dir);
std::fs::create_dir(&temp_dir).unwrap();

let config_path = std::path::Path::new(&current_dir).join(".wukong.toml");
let mut config = ApplicationConfigs::new();

config.config_path = config_path.clone();
config.application.name = "Wukong".to_string();

// 1. save the application config file
config.save().unwrap();

// 2. change to a child directory
std::env::set_current_dir(temp_dir.as_path().to_str().unwrap()).unwrap();

// 3. load the application config file
let saved_config = ApplicationConfigs::load().unwrap();

assert_eq!(saved_config.application.name, config.application.name);
assert_eq!(saved_config.config_path, config.config_path);

// remove the config file
std::fs::remove_dir(temp_dir).unwrap();
std::fs::remove_file(config_path).unwrap();
std::env::set_current_dir(current_dir.as_path().to_str().unwrap()).unwrap();
}
}
6 changes: 3 additions & 3 deletions cli/src/commands/application/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub async fn handle_application_init(context: Context) -> Result<bool, WKCliErro

println!("Welcome! Initializing per-repo configuration for your application.");

let mut application_configs = ApplicationConfigs::new()?;
let mut application_configs = ApplicationConfigs::new();

let name = Text::new("Name of your application")
.with_render_config(inquire_render_config())
Expand Down Expand Up @@ -85,7 +85,7 @@ pub async fn handle_application_init(context: Context) -> Result<bool, WKCliErro
.iter()
.find(|addon| addon == &&"Elixir livebook");

application_configs.application = Some(ApplicationConfig {
application_configs.application = ApplicationConfig {
name,
enable: true,
workflows: Some(workflows),
Expand All @@ -100,7 +100,7 @@ pub async fn handle_application_init(context: Context) -> Result<bool, WKCliErro
})
},
}),
});
};

let updated_application_configs = inquire::Editor::new(
"Do you want to review the .wukong.toml file before writing to disk ?",
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/application/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub async fn handle_logs(
fetch_loader.set_message("Fetching log entries ... ");

let log = wk_client
.get_gcloud_log_entries(
.fetch_gcloud_log_entries(
LogEntriesOptions {
resource_names: Some(resource_names),
page_size: Some(*limit),
Expand Down
24 changes: 18 additions & 6 deletions cli/src/commands/application/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use clap::{command, Args, Subcommand, ValueEnum};

use crate::error::WKCliError;

use super::Context;
use super::{get_context, get_context_without_application, ClapApp};
use info::handle_info;

#[derive(Debug, Args)]
Expand Down Expand Up @@ -91,9 +91,9 @@ impl ToString for ApplicationNamespace {
}

impl Application {
pub async fn handle_command(&self, context: Context) -> Result<bool, WKCliError> {
pub async fn handle_command(&self, clap_app: &ClapApp) -> Result<bool, WKCliError> {
match &self.subcommand {
ApplicationSubcommand::Info => handle_info(context).await,
ApplicationSubcommand::Info => handle_info(get_context(clap_app)?).await,
ApplicationSubcommand::Logs {
namespace,
version,
Expand All @@ -106,13 +106,25 @@ impl Application {
url_mode,
} => {
handle_logs(
context, namespace, version, errors, since, until, limit, include, exclude,
get_context(clap_app)?,
namespace,
version,
errors,
since,
until,
limit,
include,
exclude,
url_mode,
)
.await
}
ApplicationSubcommand::Instances(instances) => instances.handle_command(context).await,
ApplicationSubcommand::Init => handle_application_init(context).await,
ApplicationSubcommand::Instances(instances) => {
instances.handle_command(get_context(clap_app)?).await
}
ApplicationSubcommand::Init => {
handle_application_init(get_context_without_application(clap_app)?).await
}
}
}
}
1 change: 0 additions & 1 deletion cli/src/commands/config/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ pub fn handle_get(config_name: &ConfigName) -> Result<bool, WKCliError> {
let config = CliConfig::load_from_default_path()?;
println!("{:?}", config_name);
match config_name {
ConfigName::Application => println!("{}", config.core.application),
ConfigName::WukongApiUrl => println!("{}", config.core.wukong_api_url),
ConfigName::OktaClientId => println!(
"{}",
Expand Down
1 change: 0 additions & 1 deletion cli/src/commands/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ pub enum ConfigSubcommand {

#[derive(Debug, ValueEnum, Clone)]
pub enum ConfigName {
Application,
WukongApiUrl,
OktaClientId,
}
Expand Down
5 changes: 0 additions & 5 deletions cli/src/commands/config/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ use super::ConfigName;
pub fn handle_set(config_name: &ConfigName, config_value: &str) -> Result<bool, WKCliError> {
let mut config = CliConfig::load_from_default_path()?;
match config_name {
ConfigName::Application => {
config.core.application = config_value.trim().to_string();
config.save_to_default_path()?;
println!("Updated property [core/application].");
}
ConfigName::WukongApiUrl => {
config.core.wukong_api_url = config_value.trim().to_string();
config.save_to_default_path()?;
Expand Down
Loading

0 comments on commit 05ac637

Please sign in to comment.