Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PXP-678: [CLI] Integrate application init name validation #205

Merged
merged 11 commits into from
Mar 14, 2024
72 changes: 61 additions & 11 deletions cli/src/commands/application/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,55 @@ use crate::{
};
use crossterm::style::Stylize;
use heck::ToSnakeCase;
use inquire::{required, CustomType, Text};
use inquire::{required, CustomType};
use std::fs;
use wukong_sdk::graphql::appsignal_apps_query::AppsignalAppsQueryAppsignalApps;
use wukong_sdk::{
error::{APIError, WKError},
graphql::{
application_config_query::{self, ApplicationConfigQueryApplicationConfig},
appsignal_apps_query::AppsignalAppsQueryAppsignalApps,
},
};

pub async fn handle_application_init(context: Context) -> Result<bool, WKCliError> {
let config = Config::load_from_default_path()?;
let mut wk_client = WKClient::for_channel(&config, &context.channel)?;
let mut appsignall_apps = None;
let mut appsignal_apps = None;

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

let mut application_configs = ApplicationConfigs::new();
let mut name: String;

let name = Text::new("Name of your application")
.with_render_config(inquire_render_config())
.with_validator(required!("Application name is required"))
.with_placeholder("my-first-application")
.prompt()?;
loop {
name = inquire::Text::new("Name of your application")
.with_render_config(inquire_render_config())
.with_validator(required!("Application name is required"))
.with_placeholder("my-first-application")
.prompt()?;

let fetch_loader = new_spinner();
fetch_loader.set_message("Validating application name ...");

let has_application_config = get_application_config(&mut wk_client, &name)
.await?
.is_some();

fetch_loader.finish_and_clear();

if has_application_config {
println!(
"{}",
format!(
" Application '{}' already exists. Please choose a different name",
name
)
.red()
);
} else {
break;
}
}

let workflows = get_workflows_from_current_dir()?;
let mut excluded_workflows = Vec::new();
Expand All @@ -51,7 +82,7 @@ pub async fn handle_application_init(context: Context) -> Result<bool, WKCliErro

let mut namespaces: Vec<ApplicationNamespaceConfig> = Vec::new();
namespaces
.push(configure_namespace("prod".to_string(), &mut wk_client, &mut appsignall_apps).await?);
.push(configure_namespace("prod".to_string(), &mut wk_client, &mut appsignal_apps).await?);

let addons = ["Elixir Livebook"];
let selected_addons = inquire::MultiSelect::new("Addons", addons.to_vec())
Expand All @@ -71,8 +102,7 @@ pub async fn handle_application_init(context: Context) -> Result<bool, WKCliErro

if configure_staging_namespace {
namespaces.push(
configure_namespace("staging".to_string(), &mut wk_client, &mut appsignall_apps)
.await?,
configure_namespace("staging".to_string(), &mut wk_client, &mut appsignal_apps).await?,
);
}

Expand Down Expand Up @@ -295,3 +325,23 @@ fn get_workflows_from_current_dir() -> Result<Vec<String>, WKCliError> {

Ok(workflow_names)
}

async fn get_application_config(
wk_client: &mut WKClient,
name: &str,
) -> Result<Option<ApplicationConfigQueryApplicationConfig>, WKCliError> {
let application_config = match wk_client.fetch_application_config(name).await {
Ok(resp) => Ok(resp),
Err(err) => match &err {
WKCliError::WKSdkError(WKError::APIError(APIError::ApplicationConfigNotFound)) => {
Ok(application_config_query::ResponseData {
application_config: None,
})
}
_ => Err(err),
},
}?
.application_config;

Ok(application_config)
}
24 changes: 17 additions & 7 deletions cli/src/wukong_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ use log::debug;
use std::collections::HashMap;
use wukong_sdk::{
graphql::{
application_query, application_with_k8s_cluster_query, applications_query,
appsignal_apps_query, appsignal_average_error_rate_query, appsignal_average_latency_query,
appsignal_average_throughput_query, appsignal_deploy_markers_query,
appsignal_exception_incidents_query, cd_pipeline_for_rollback_query,
cd_pipeline_github_query, cd_pipeline_query, cd_pipelines_query, changelogs_query,
ci_status_query, deploy_livebook, deployment::cd_pipeline_status_query, destroy_livebook,
execute_cd_pipeline, is_authorized_query, kubernetes_pods_query, livebook_resource_query,
application_config_query, application_query, application_with_k8s_cluster_query,
applications_query, appsignal_apps_query, appsignal_average_error_rate_query,
appsignal_average_latency_query, appsignal_average_throughput_query,
appsignal_deploy_markers_query, appsignal_exception_incidents_query,
cd_pipeline_for_rollback_query, cd_pipeline_github_query, cd_pipeline_query,
cd_pipelines_query, changelogs_query, ci_status_query, deploy_livebook,
deployment::cd_pipeline_status_query, destroy_livebook, execute_cd_pipeline,
is_authorized_query, kubernetes_pods_query, livebook_resource_query,
multi_branch_pipeline_query, pipeline_query, pipelines_query, AppsignalTimeFrame,
},
services::{
Expand Down Expand Up @@ -452,4 +453,13 @@ impl WKClient {
.fetch_gcloud_database_metrics(project_id, access_token)
.await
}

#[wukong_telemetry(api_event = "fetch_application_config")]
pub async fn fetch_application_config(
&mut self,
name: &str,
) -> Result<application_config_query::ResponseData, WKCliError> {
self.check_and_refresh_tokens().await?;
self.inner.fetch_application_config(name).await
}
}
2 changes: 1 addition & 1 deletion sdk/proto/googleapis
Submodule googleapis updated 3739 files
2 changes: 2 additions & 0 deletions sdk/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ pub enum APIError {
BuildNotFound,
#[error("Github Workflow not found.")]
GithubWorkflowNotFound,
#[error("Failed to get the application config.")]
ApplicationConfigNotFound,
}

#[derive(Debug, ThisError)]
Expand Down
8 changes: 8 additions & 0 deletions sdk/src/graphql/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ pub struct ApplicationWithK8sClusterQuery;
)]
pub struct ApplicationsQuery;

#[derive(GraphQLQuery)]
#[graphql(
schema_path = "src/graphql/schema.json",
query_path = "src/graphql/query/application_config.graphql",
response_derives = "Debug, Serialize, Deserialize"
)]
pub struct ApplicationConfigQuery;

#[cfg(test)]
mod test {
use crate::{ApiChannel, WKClient, WKConfig};
Expand Down
27 changes: 24 additions & 3 deletions sdk/src/graphql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ pub mod deployment_github;
pub mod kubernetes;
pub mod pipeline;

use self::deployment::{cd_pipeline_status_query, CdPipelineStatusQuery};
use self::{
application::ApplicationConfigQuery,
deployment::{cd_pipeline_status_query, CdPipelineStatusQuery},
};
pub use self::{
application::{
application_query, application_with_k8s_cluster_query, applications_query,
ApplicationQuery, ApplicationWithK8sClusterQuery, ApplicationsQuery,
application_config_query, application_query, application_with_k8s_cluster_query,
applications_query, ApplicationQuery, ApplicationWithK8sClusterQuery, ApplicationsQuery,
},
appsignal::{
appsignal_apps_query, appsignal_average_error_rate_query, appsignal_average_latency_query,
Expand Down Expand Up @@ -747,6 +750,23 @@ impl WKClient {
.map_err(|err| err.into())
}

pub async fn fetch_application_config(
&self,
name: &str,
) -> Result<application_config_query::ResponseData, WKError> {
let gql_client = setup_gql_client(&self.access_token, &self.channel)?;

gql_client
.post_graphql::<ApplicationConfigQuery, _>(
&self.api_url,
application_config_query::Variables {
name: name.to_string(),
},
)
.await
.map_err(|err| err.into())
}

/// Fetch the deploy markers from Appsignal
/// the default value for `limit` is 1
pub async fn fetch_appsignal_deploy_markers(
Expand Down Expand Up @@ -890,6 +910,7 @@ impl ErrorHandler for CanaryErrorHandler {
// "github_ref_not_found" => {}
// "github_commit_history_not_found" => {}
"github_workflow_not_found" => APIError::GithubWorkflowNotFound,
"application_config_not_found" => APIError::ApplicationConfigNotFound,
// "slack_webhook_not_configured" => {}
_ => APIError::ResponseError {
code: original_error_code.to_string(),
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/graphql/query/application_config.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
query ApplicationConfigQuery($name: String!) {
applicationConfig(name: $name) {
name
}
}
Loading
Loading