diff --git a/src/commands/secret/mod.rs b/src/commands/secret/mod.rs index d213e6cae..a17d3dc74 100644 --- a/src/commands/secret/mod.rs +++ b/src/commands/secret/mod.rs @@ -7,6 +7,7 @@ use crate::http; use crate::settings::global_user::GlobalUser; use crate::settings::toml::Target; use crate::terminal::{emoji, interactive, message}; +use crate::upload; fn format_error(e: ApiFailure) -> String { http::format_error(e, Some(&secret_errors)) @@ -35,25 +36,50 @@ fn validate_target(target: &Target) -> Result<(), failure::Error> { fn secret_errors(error_code: u16) -> &'static str { match error_code { 7003 | 7000 => { - "Your wrangler.toml is likely missing the field \"account_id\", which is required to write to Workers KV." + "Your wrangler.toml is likely missing the field \"account_id\", which is required to create a secret." } 10053 => "There is already another binding with a different type by this name. Check your wrangler.toml or your Cloudflare dashboard for conflicting bindings", - 10054 => "Your secret is too large, bindings must be 1kB or less", + 10054 => "Your secret is too large, it must be 1kB or less", 10055 => "You have exceeded the limit of 32 text bindings for this worker. Run `wrangler secret list` or go to your Cloudflare dashboard to clean up unused text/secret variables", _ => "", } } +// upload_draft_worker will attempt to upload a "draft" version of a worker script if it does not +// already exist in the API (API error code 10007 is returned). The function returns None if this draft +// script was uploaded, or else returns Some (with a Result type so we can return a potential script upload error +// up the call chain). +pub fn upload_draft_worker( + e: &ApiFailure, + user: &GlobalUser, + target: &Target, +) -> Option> { + match e { + ApiFailure::Error(_, api_errors) => { + for error in &api_errors.errors { + if error.code == 10007 { + message::working(&format!("Worker {} doesn't exist in the API yet. Creating a draft Worker so we can create new secret.", target.name)); + return Some(upload::script(user, target, None)); + } else { + return None; + } + } + return None; + } + ApiFailure::Invalid(_) => None, + } +} + pub fn create_secret(name: &str, user: &GlobalUser, target: &Target) -> Result<(), failure::Error> { validate_target(target)?; let secret_value = interactive::get_user_input(&format!( - "Enter the secret text you'd like assigned to the variable {} on the script named {}", + "Enter the secret text you'd like assigned to the variable {} on the script named {}:", name, target.name )); if secret_value.is_empty() { - failure::bail!("Your secret cannot be empty") + failure::bail!("Your secret cannot be empty.") } message::working(&format!( @@ -72,12 +98,29 @@ pub fn create_secret(name: &str, user: &GlobalUser, target: &Target) -> Result<( let response = client.request(&CreateSecret { account_identifier: &target.account_id, script_name: &target.name, - params, + params: params.clone(), }); match response { - Ok(_) => message::success(&format!("Success! You've uploaded secret {}.", name)), - Err(e) => failure::bail!(format_error(e)), + Ok(_) => message::success(&format!("Success! Uploaded secret {}.", name)), + Err(e) => match upload_draft_worker(&e, user, target) { + None => failure::bail!(format_error(e)), + Some(draft_upload_response) => match draft_upload_response { + Ok(_) => { + let retry_response = client.request(&CreateSecret { + account_identifier: &target.account_id, + script_name: &target.name, + params, + }); + + match retry_response { + Ok(_) => message::success(&format!("Success! Uploaded secret {}.", name)), + Err(e) => failure::bail!(format_error(e)), + } + } + Err(e) => failure::bail!(e), + }, + }, } Ok(()) @@ -87,12 +130,12 @@ pub fn delete_secret(name: &str, user: &GlobalUser, target: &Target) -> Result<( validate_target(target)?; match interactive::delete(&format!( - "Are you sure you want to permanently delete the variable {} on the script named {}", + "Are you sure you want to permanently delete the variable {} on the script named {}?", name, target.name )) { Ok(true) => (), Ok(false) => { - message::info(&format!("Not deleting secret {}", name)); + message::info(&format!("Not deleting secret {}.", name)); return Ok(()); } Err(e) => failure::bail!(e), @@ -108,11 +151,11 @@ pub fn delete_secret(name: &str, user: &GlobalUser, target: &Target) -> Result<( let response = client.request(&DeleteSecret { account_identifier: &target.account_id, script_name: &target.name, - secret_name: name, + secret_name: name.clone(), }); match response { - Ok(_) => message::success(&format!("You've deleted the secret {}.", name)), + Ok(_) => message::success(&format!("Success! Deleted secret {}.", name)), Err(e) => failure::bail!(format_error(e)), }