@smbcloud / cli / commits / 9f9a211

remove config error

Seto Elkahfi committed Jun 9, 2025 at 19:50 UTC 9f9a211d7ffc735561ad77db3ec634308135f85d
3 files changed +101 -47
crates/cli/src/deploy/config.rs
+16 -23
@@ -4,14 +4,17 @@ use crate::{
4 };
5 use git2::{Cred, CredentialType, Error};
6 use serde::{Deserialize, Serialize};
7 -use smbcloud_model::{account::User, project::Project};
7 +use smbcloud_model::{
8 + account::User,
9 + error_codes::{ErrorCode, ErrorResponse},
10 + project::Project,
11 +};
12 use smbcloud_networking::environment::Environment;
13 use smbcloud_networking_project::crud_project_read::get_project;
14 use spinners::Spinner;
15 use std::{fs, path::Path};
12 -use thiserror::Error;
16
14 -pub(crate) async fn check_config(env: Environment) -> Result<Config, ConfigError> {
17 +pub(crate) async fn check_config(env: Environment) -> Result<Config, ErrorResponse> {
18 let mut spinner: Spinner = Spinner::new(
19 spinners::Spinners::SimpleDotsScrolling,
20 succeed_message("Checking config"),
@@ -31,7 +34,10 @@ pub(crate) async fn check_config(env: Environment) -> Result<Config, ConfigError
34 }
35
36 // Parse toml file
34 - let config_content = fs::read_to_string(config_path).map_err(|_| ConfigError::MissingConfig)?;
37 + let config_content = fs::read_to_string(config_path).map_err(|_| ErrorResponse::Error {
38 + error_code: ErrorCode::MissingConfig,
39 + message: ErrorCode::MissingConfig.message(None).to_string(),
40 + })?;
41
42 let config: Config = match toml::from_str(&config_content) {
43 Ok(value) => value,
@@ -49,7 +55,7 @@ pub(crate) async fn check_config(env: Environment) -> Result<Config, ConfigError
55 Ok(config)
56 }
57
52 -fn handle_config_error() -> Result<Config, ConfigError> {
58 +fn handle_config_error() -> Result<Config, ErrorResponse> {
59 todo!()
60 }
61
@@ -57,7 +63,7 @@ pub(crate) async fn check_project(
63 env: Environment,
64 access_token: &str,
65 id: i32,
60 -) -> Result<(), ConfigError> {
66 +) -> Result<(), ErrorResponse> {
67 let mut spinner: Spinner = Spinner::new(
68 spinners::Spinners::Hamburger,
69 succeed_message("Validate project"),
@@ -69,7 +75,10 @@ pub(crate) async fn check_project(
75 }
76 Err(_) => {
77 spinner.stop_and_persist(&fail_symbol(), succeed_message("Project is unsynched"));
72 - Err(ConfigError::ProjectNotFound)
78 + Err(ErrorResponse::Error {
79 + error_code: ErrorCode::ProjectNotFound,
80 + message: ErrorCode::ProjectNotFound.message(None).to_string(),
81 + })
82 }
83 }
84 }
@@ -100,19 +109,3 @@ impl Config {
109 key_path_str
110 }
111 }
103 -
104 -#[derive(Error, Debug, PartialEq, Eq)]
105 -pub enum ConfigError {
106 - #[error("Missing token. Make sure you are logged in.")]
107 - MissingToken,
108 - #[error("Missing config file. Please regenerate with 'smb init'.")]
109 - MissingConfig,
110 - #[error("Missing id in repository. Please regenerate with 'smb init'.")]
111 - MissingId,
112 - #[error("Could not find project in your list. Make sure you have access to the project.")]
113 - ProjectNotFound,
114 - #[error("Cancel operation.")]
115 - Cancel,
116 - #[error("Input error.")]
117 - InputError,
118 -}
crates/cli/src/deploy/setup.rs
+68 -23
@@ -1,17 +1,17 @@
1 -use crate::{
2 - deploy::config::{Config, ConfigError},
3 - ui::highlight,
4 -};
1 +use crate::{deploy::config::Config, ui::highlight};
2 use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
3 use regex::Regex;
7 -use smbcloud_model::project::{Project, ProjectCreate};
4 +use smbcloud_model::{
5 + error_codes::{ErrorCode, ErrorResponse},
6 + project::{Project, ProjectCreate},
7 +};
8 use smbcloud_networking::{environment::Environment, get_smb_token};
9 use smbcloud_networking_project::{
10 crud_project_create::create_project, crud_project_read::get_projects,
11 };
12 use std::{env, fs, path::Path};
13
14 -pub async fn setup_project(env: Environment) -> Result<Config, ConfigError> {
14 +pub async fn setup_project(env: Environment) -> Result<Config, ErrorResponse> {
15 let path = env::current_dir().ok();
16 let path_str = path
17 .as_ref()
@@ -21,20 +21,36 @@ pub async fn setup_project(env: Environment) -> Result<Config, ConfigError> {
21 let confirm = Confirm::with_theme(&ColorfulTheme::default())
22 .with_prompt(format!("Setup project in {}? y/n", highlight(&path_str)))
23 .interact()
24 - .map_err(|_| ConfigError::InputError)?;
24 + .map_err(|_| ErrorResponse::Error {
25 + error_code: ErrorCode::InputError,
26 + message: ErrorCode::InputError.message(None).to_string(),
27 + })?;
28
29 if !confirm {
27 - return Err(ConfigError::Cancel);
30 + return Err(ErrorResponse::Error {
31 + error_code: ErrorCode::Cancel,
32 + message: ErrorCode::Cancel.message(None).to_string(),
33 + });
34 }
35
36 let access_token = match get_smb_token(env).await {
37 Ok(token) => token,
32 - Err(_) => return Err(ConfigError::MissingToken),
38 + Err(_) => {
39 + return Err(ErrorResponse::Error {
40 + error_code: ErrorCode::Unauthorized,
41 + message: ErrorCode::Unauthorized.message(None).to_string(),
42 + })
43 + }
44 };
45
46 let projects = match get_projects(env, access_token).await {
47 Ok(x) => x,
37 - Err(_) => return Err(ConfigError::InputError),
48 + Err(_) => {
49 + return Err(ErrorResponse::Error {
50 + error_code: ErrorCode::InputError,
51 + message: ErrorCode::InputError.message(None).to_string(),
52 + })
53 + }
54 };
55
56 let project: Project = if !projects.is_empty() {
@@ -56,12 +72,21 @@ pub async fn setup_project(env: Environment) -> Result<Config, ConfigError> {
72 // Ensure .smb directory exists
73 let smb_dir = Path::new(".smb");
74 if !smb_dir.exists() {
59 - fs::create_dir(smb_dir).map_err(|_| ConfigError::MissingConfig)?;
75 + fs::create_dir(smb_dir).map_err(|_| ErrorResponse::Error {
76 + error_code: ErrorCode::MissingConfig,
77 + message: ErrorCode::MissingConfig.message(None).to_string(),
78 + })?;
79 }
80
81 // Write config to .smb/config.toml
63 - let config_toml = toml::to_string(&config).map_err(|_| ConfigError::MissingConfig)?;
64 - fs::write(".smb/config.toml", config_toml).map_err(|_| ConfigError::MissingConfig)?;
82 + let config_toml = toml::to_string(&config).map_err(|_| ErrorResponse::Error {
83 + error_code: ErrorCode::MissingConfig,
84 + message: ErrorCode::MissingConfig.message(None).to_string(),
85 + })?;
86 + fs::write(".smb/config.toml", config_toml).map_err(|_| ErrorResponse::Error {
87 + error_code: ErrorCode::MissingConfig,
88 + message: ErrorCode::MissingConfig.message(None).to_string(),
89 + })?;
90
91 Ok(config)
92 }
@@ -70,11 +95,14 @@ async fn select_project(
95 env: Environment,
96 projects: Vec<Project>,
97 path: &str,
73 -) -> Result<Project, ConfigError> {
98 +) -> Result<Project, ErrorResponse> {
99 let confirm = Confirm::with_theme(&ColorfulTheme::default())
100 .with_prompt("Use existing project? y/n")
101 .interact()
77 - .map_err(|_| ConfigError::InputError)?;
102 + .map_err(|_| ErrorResponse::Error {
103 + error_code: ErrorCode::InputError,
104 + message: ErrorCode::InputError.message(None).to_string(),
105 + })?;
106
107 if !confirm {
108 return create_new_project(env, path).await;
@@ -83,20 +111,23 @@ async fn select_project(
111 .items(&projects)
112 .default(0)
113 .interact()
86 - .map_err(|_| ConfigError::InputError)?;
114 + .map_err(|_| ErrorResponse::Error {
115 + error_code: ErrorCode::InputError,
116 + message: ErrorCode::InputError.message(None).to_string(),
117 + })?;
118
119 let project = projects[selection].clone();
120
121 Ok(project)
122 }
123
93 -async fn create_new_project(env: Environment, path: &str) -> Result<Project, ConfigError> {
124 +async fn create_new_project(env: Environment, path: &str) -> Result<Project, ErrorResponse> {
125 let default_name = Path::new(path)
126 .file_name()
127 .and_then(|os_str| os_str.to_str())
128 .unwrap_or("project")
129 .to_lowercase()
99 - .replace(' ', "")
130 + .replace([' ', '-'], "")
131 .replace('-', "");
132
133 let name = match Input::<String>::with_theme(&ColorfulTheme::default())
@@ -106,7 +137,10 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
137 {
138 Ok(project_name) => project_name,
139 Err(_) => {
109 - return Err(ConfigError::InputError);
140 + return Err(ErrorResponse::Error {
141 + error_code: ErrorCode::InputError,
142 + message: ErrorCode::InputError.message(None).to_string(),
143 + });
144 }
145 };
146
@@ -126,7 +160,10 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
160 {
161 Ok(repo) => repo,
162 Err(_) => {
129 - return Err(ConfigError::InputError);
163 + return Err(ErrorResponse::Error {
164 + error_code: ErrorCode::InputError,
165 + message: ErrorCode::InputError.message(None).to_string(),
166 + });
167 }
168 };
169
@@ -136,13 +173,21 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
173 {
174 Ok(description) => description,
175 Err(_) => {
139 - return Err(ConfigError::InputError);
176 + return Err(ErrorResponse::Error {
177 + error_code: ErrorCode::InputError,
178 + message: ErrorCode::InputError.message(None).to_string(),
179 + });
180 }
181 };
182
183 let access_token = match get_smb_token(env).await {
184 Ok(token) => token,
145 - Err(_) => return Err(ConfigError::MissingToken),
185 + Err(_) => {
186 + return Err(ErrorResponse::Error {
187 + error_code: ErrorCode::Unauthorized,
188 + message: ErrorCode::Unauthorized.message(None).to_string(),
189 + })
190 + }
191 };
192
193 match create_project(
@@ -157,6 +202,6 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
202 .await
203 {
204 Ok(project) => Ok(project),
160 - Err(_) => Err(ConfigError::MissingConfig),
205 + Err(e) => Err(e),
206 }
207 }
crates/smbcloud-model/src/error_codes.rs
+17 -1
@@ -24,12 +24,21 @@ impl Display for ErrorResponse {
24 #[derive(Error, Serialize_repr, Deserialize_repr, Debug, EnumIter, IntoStaticStr)]
25 #[repr(i32)]
26 pub enum ErrorCode {
27 + // Generic errors
28 #[error("Unknown error.")]
29 Unknown = 0,
30 #[error("Parse error.")]
31 ParseError = 1,
32 #[error("Network error.")]
33 NetworkError = 2,
34 + #[error("Input error")]
35 + InputError = 3,
36 + #[error("Missing config file. Please regenerate with 'smb init'.")]
37 + MissingConfig = 4,
38 + // #[error("Missing id in repository. Please regenerate with 'smb init'.")]
39 + // MissingId,
40 + #[error("Cancel operation.")]
41 + Cancel = 5,
42 // Account
43 #[error("Unauthorized access.")]
44 Unauthorized = 100,
@@ -47,9 +56,13 @@ impl ErrorCode {
56 100 => ErrorCode::Unauthorized,
57 // Projects
58 1000 => ErrorCode::ProjectNotFound,
50 - // Fallback
59 + // Generic errors
60 + 5 => ErrorCode::Cancel,
61 + 4 => ErrorCode::MissingConfig,
62 + 3 => ErrorCode::InputError,
63 2 => ErrorCode::ParseError,
64 1 => ErrorCode::NetworkError,
65 + // Fallback
66 _ => ErrorCode::Unknown,
67 }
68 }
@@ -63,6 +76,9 @@ impl ErrorCode {
76 ErrorCode::ParseError => "Parse error.",
77 ErrorCode::NetworkError => "Network error.",
78 ErrorCode::Unauthorized => "Unauthorized access.",
79 + ErrorCode::InputError => "Input error.",
80 + ErrorCode::MissingConfig => "Missing config.",
81 + ErrorCode::Cancel => "Cancelled operation.",
82 }
83 }
84