From 9a68133f36ad5478e3a0de10099d14b69da49a05 Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Thu, 17 Oct 2024 16:04:36 +0200 Subject: [PATCH] refactor: improve upload errors (#2303) --- src/cli/upload.rs | 101 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 15 deletions(-) diff --git a/src/cli/upload.rs b/src/cli/upload.rs index 92487d118..f0b4042f7 100644 --- a/src/cli/upload.rs +++ b/src/cli/upload.rs @@ -4,11 +4,12 @@ use std::sync::Arc; use clap::Parser; use futures::TryStreamExt; use indicatif::HumanBytes; -use miette::IntoDiagnostic; +use miette::{Diagnostic, IntoDiagnostic}; +use reqwest::StatusCode; use rattler_digest::{compute_file_digest, Sha256}; use rattler_networking::AuthenticationMiddleware; - +use thiserror::Error; use tokio::fs::File; use tokio_util::io::ReaderStream; @@ -83,22 +84,92 @@ pub async fn execute(args: Args) -> miette::Result<()> { .body(body) .send() .await - .into_diagnostic()?; - - if response.status().is_success() { - println!("Upload successful!"); - } else { - println!("Upload failed!"); - - if response.status() == 401 { - println!( - "Authentication failed! Did you run `pixi auth login {}`?", - args.host + .map_err(|e| UploadError::RequestFailed { + host: args.host.clone(), + source: e, + })?; + + match response.status() { + StatusCode::OK => { + eprintln!( + "{} Package uploaded successfully!", + console::style("✔").green() ); } - - std::process::exit(1); + StatusCode::UNAUTHORIZED => { + return Err(UploadError::Unauthorized { + host: args.host.clone(), + source: response.error_for_status().unwrap_err(), // Capture reqwest error + } + .into()); + } + StatusCode::INTERNAL_SERVER_ERROR => { + return Err(UploadError::ServerError { + host: args.host.clone(), + source: response.error_for_status().unwrap_err(), // Capture reqwest error + } + .into()); + } + StatusCode::CONFLICT => { + return Err(UploadError::Conflict { + host: args.host.clone(), + source: response.error_for_status().unwrap_err(), // Capture reqwest error + } + .into()); + } + status => { + return Err(UploadError::UnexpectedStatus { + host: args.host.clone(), + status, + source: response.error_for_status().unwrap_err(), // Capture reqwest error + } + .into()); + } } Ok(()) } + +#[derive(Debug, Error, Diagnostic)] +pub enum UploadError { + #[error("Failed to send request to {host}")] + #[diagnostic(help("Check if the host is correct and reachable."))] + RequestFailed { + host: String, + #[source] + source: reqwest_middleware::Error, + }, + + #[error("Unauthorized request to {host}")] + #[diagnostic(help("Try logging in with `pixi auth login`."))] + Unauthorized { + host: String, + #[source] + source: reqwest::Error, + }, + + #[error("Server error at {host}")] + #[diagnostic(help("The server encountered an internal error. Try again later."))] + ServerError { + host: String, + #[source] + source: reqwest::Error, + }, + + #[error("Unexpected response from {host}: {status}")] + #[diagnostic(help("Unexpected status code, verify the API specification."))] + UnexpectedStatus { + host: String, + status: StatusCode, + #[source] + source: reqwest::Error, + }, + + #[error("Conflict: The package likely already exists in the channel: {host}")] + #[diagnostic(help("Try changing the package version or build number."))] + Conflict { + host: String, + #[source] + source: reqwest::Error, + }, +}