use crate::repository::RepositoryError;
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
use config::ConfigError;
use rovo::aide::OperationOutput;
use thiserror::Error;
use validator::ValidationErrors;
#[derive(Debug, Error)]
pub enum ValidationError {
#[error("Validation error: {0}")]
InvalidValue(String),
}
impl IntoResponse for ValidationError {
fn into_response(self) -> Response {
(StatusCode::UNPROCESSABLE_ENTITY, self.to_string()).into_response()
}
}
#[derive(Debug, Error)]
pub enum HandlerError {
#[error("Repository Error: {0}")]
DbQuery(RepositoryError),
#[error("Not Found")]
NotFound,
}
impl From<RepositoryError> for HandlerError {
fn from(err: RepositoryError) -> Self {
match err {
RepositoryError::NotFound => HandlerError::NotFound,
other => HandlerError::DbQuery(other),
}
}
}
impl OperationOutput for HandlerError {
type Inner = ();
}
impl IntoResponse for HandlerError {
fn into_response(self) -> Response {
let status = match self {
HandlerError::DbQuery(_) => StatusCode::INTERNAL_SERVER_ERROR,
HandlerError::NotFound => StatusCode::NOT_FOUND,
};
(status, self.to_string()).into_response()
}
}
#[derive(Debug, Error)]
pub enum FatalError {
#[error("Database connection: {0}")]
DbConnection(#[from] sqlx::Error),
#[error("Repository error: {0}")]
Repository(#[from] RepositoryError),
#[error("Database migration: {0}")]
Migration(#[from] sqlx::migrate::MigrateError),
#[error("TCP binding: {0}")]
TcpBinding(#[source] std::io::Error),
#[error("Serve: {0}")]
Serve(#[source] std::io::Error),
#[allow(missing_docs)]
#[error("HTTP Client creation: {0}")]
ClientCreation(#[from] ClientCreationError),
#[error("Environment variable '{0}' not set")]
EnvVarNotSet(String),
#[error("Failed to load authentication key: {0}")]
AuthKeyLoading(#[source] jsonwebtoken::errors::Error),
#[error("Failed to read authentication key file: {0}")]
AuthKeyIo(#[source] std::io::Error),
#[error(transparent)]
Setup(SetupError),
#[error("Configuration validation failed: {0}")]
Validation(#[from] ValidationErrors),
}
#[derive(Debug, Error)]
pub enum SetupError {
#[error("Configuration error: {0}")]
Config(#[source] ConfigError),
#[error("Failed to load configuration: {0}")]
Env(#[source] dotenvy::Error),
}
impl From<config::ConfigError> for FatalError {
fn from(e: config::ConfigError) -> Self {
FatalError::Setup(SetupError::Config(e))
}
}
impl From<dotenvy::Error> for FatalError {
fn from(e: dotenvy::Error) -> Self {
FatalError::Setup(SetupError::Env(e))
}
}
#[derive(Debug, Error)]
#[error(transparent)]
pub struct ClientCreationError(#[from] reqwest::Error);
#[derive(Debug, Error)]
pub enum CommitHashError {
#[error("Validation error: {0}")]
Validation(#[from] ValidationError),
#[error("I/O error in `git ls-remote`: {0}")]
Io(#[from] std::io::Error),
#[error("Unexpected `git ls-remote` exit status: {0}")]
UnexpectedStatus(String),
#[error(
"Unexpected `git ls-remote` output format. Repo: {repo_url}; Branch: {branch}; Stdout: {stdout}"
)]
UnexpectedOutput {
stdout: String,
repo_url: String,
branch: String,
},
}