smbcloud-cli 0.4.2

smbCloud command line interface.
use crate::client;
use crate::token::{get_smb_token::get_smb_token, is_logged_in::is_logged_in};
use crate::{
    account::login::process_login,
    cli::CommandResult,
    project::deploy_target::{
        ensure_default_frontend_app_for_project, merge_project_with_frontend_app,
        resolve_frontend_app_for_project,
    },
    ui::{fail_message, succeed_message, succeed_symbol},
};
use anyhow::{anyhow, Result};
use console::style;
use dialoguer::console::Term;
use dialoguer::Select;
use dialoguer::{theme::ColorfulTheme, Input};
use smbcloud_model::project::{Project, ProjectCreate};
use smbcloud_model::runner::Runner;
use smbcloud_network::environment::Environment;
use smbcloud_networking_project::crud_project_create::create_project;
use smbcloud_utils::config::Config as DeployConfig;
use spinners::Spinner;

pub async fn process_project_init(
    env: Environment,
    should_init_project: bool,
) -> Result<CommandResult> {
    let is_logged_in = is_logged_in(env).await?;
    if !is_logged_in {
        let _ = process_login(env, Some(is_logged_in)).await;
    }

    let project_name = match Input::<String>::with_theme(&ColorfulTheme::default())
        .with_prompt("Project name")
        .interact()
    {
        Ok(project_name) => project_name,
        Err(_) => {
            return Err(anyhow!(fail_message("Invalid project name.")));
        }
    };

    let runners = vec![
        Runner::NodeJs,
        Runner::Static,
        Runner::Ruby,
        Runner::Swift,
        Runner::Rust,
    ];
    let runner = Select::with_theme(&ColorfulTheme::default())
        .items(&runners)
        .default(0)
        .interact_on_opt(&Term::stderr())
        .map(|i| runners[i.unwrap()])
        .unwrap();

    let repository = match Input::<String>::with_theme(&ColorfulTheme::default())
        .with_prompt("Repository name")
        .interact()
    {
        Ok(project_name) => project_name,
        Err(_) => {
            return Err(anyhow!(fail_message("Invalid repository name.")));
        }
    };
    let description = match Input::<String>::with_theme(&ColorfulTheme::default())
        .with_prompt("Description")
        .interact()
    {
        Ok(description) => description,
        Err(_) => {
            return Err(anyhow!(fail_message("Invalid description")));
        }
    };

    let spinner = Spinner::new(
        spinners::Spinners::SimpleDotsScrolling,
        style("Creating a project...").green().bold().to_string(),
    );

    let access_token = get_smb_token(env)?;
    match create_project(
        env,
        client(),
        access_token.clone(),
        ProjectCreate {
            name: project_name.clone(),
            runner,
            repository,
            description: description.clone(),
            deployment_method: Default::default(),
        },
    )
    .await
    {
        Ok(project) => {
            if should_init_project {
                let _ = ensure_default_frontend_app_for_project(env, &access_token, &project).await;
                write_smb_config(env, &access_token, project.clone()).await?;
            }

            Ok(CommandResult {
                spinner,
                symbol: succeed_symbol(),
                msg: succeed_message(&format!("{project_name} has been created.")),
            })
        }
        Err(e) => {
            println!("Error: {e:#?}");
            Err(anyhow!(fail_message("Failed to create project.")))
        }
    }
}

async fn write_smb_config(
    env: Environment,
    access_token: &str,
    workspace_project: Project,
) -> Result<()> {
    let deploy_target = match resolve_frontend_app_for_project(
        env,
        access_token,
        &workspace_project,
        false,
    )
    .await
    {
        Ok(Some(frontend_app)) => {
            merge_project_with_frontend_app(&workspace_project, &frontend_app)
        }
        _ => workspace_project.clone(),
    };

    let config = DeployConfig {
        name: workspace_project.name.clone(),
        description: workspace_project.description.clone(),
        project: deploy_target,
        projects: None,
    };

    std::fs::create_dir_all(".smb")?;
    std::fs::write(".smb/config.toml", toml::to_string(&config)?)?;
    Ok(())
}