1use http::uri::InvalidUri;
2
3use snafu::{Backtrace, Snafu};
4
5use std::fmt;
6use std::fmt::{Display, Formatter};
7use std::string::FromUtf8Error;
8use tower::BoxError;
9
10#[derive(Debug)]
12pub struct UriParseError;
13
14impl Display for UriParseError {
15 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
16 write!(f, "Failed to parse URI")
17 }
18}
19
20impl std::error::Error for UriParseError {}
21
22#[derive(Snafu, Debug)]
24#[snafu(visibility(pub))]
25#[non_exhaustive]
26pub enum Error {
27 GitHub {
28 source: Box<GitHubError>,
29 backtrace: Backtrace,
30 },
31 UriParse {
32 source: UriParseError,
33 backtrace: Backtrace,
34 },
35 Uri {
36 source: InvalidUri,
37 backtrace: Backtrace,
38 },
39 #[snafu(display("Installation Error: Github App authorization is required to target an installation.\n\nFound at {}", backtrace))]
40 Installation { backtrace: Backtrace },
41 #[snafu(display("Error getting installation access token: octocrab instance is not an installation.\n\nFound at {}", backtrace))]
42 InstallationTokenInvalidAuth { backtrace: Backtrace },
43 InvalidHeaderValue {
44 source: http::header::InvalidHeaderValue,
45 backtrace: Backtrace,
46 },
47
48 #[snafu(display("HTTP Error: {}\n\nFound at {}", source, backtrace))]
49 Http {
50 source: http::Error,
51 backtrace: Backtrace,
52 },
53
54 InvalidUtf8 {
55 source: FromUtf8Error,
56 backtrace: Backtrace,
57 },
58
59 Encoder {
60 source: std::io::Error,
61 backtrace: Backtrace,
62 },
63
64 #[snafu(display("Service Error: {}\n\nFound at {}", source, backtrace))]
65 Service {
66 source: BoxError,
67 backtrace: Backtrace,
68 },
69
70 #[snafu(display("Hyper Error: {}\n\nFound at {}", source, backtrace))]
71 Hyper {
72 source: hyper::Error,
73 backtrace: Backtrace,
74 },
75
76 #[snafu(display("Serde Url Encode Error: {}\nFound at {}", source, backtrace))]
77 SerdeUrlEncoded {
78 source: serde_urlencoded::ser::Error,
79 backtrace: Backtrace,
80 },
81
82 #[snafu(display("Serde Error: {}\nFound at {}", source, backtrace))]
83 Serde {
84 source: serde_json::Error,
85 backtrace: Backtrace,
86 },
87 #[snafu(display("JSON Error in {}: {}\nFound at {}", source.path(), source.inner(), backtrace))]
88 Json {
89 source: serde_path_to_error::Error<serde_json::Error>,
90 backtrace: Backtrace,
91 },
92 #[snafu(display("JWT Error in {}\nFound at {}", source, backtrace))]
93 JWT {
94 source: jsonwebtoken::errors::Error,
95 backtrace: Backtrace,
96 },
97 Other {
98 source: Box<dyn std::error::Error + Send + Sync>,
99 backtrace: Backtrace,
100 },
101}
102
103#[derive(Debug, Clone)]
105#[non_exhaustive]
106pub struct GitHubError {
107 pub documentation_url: Option<String>,
108 pub errors: Option<Vec<serde_json::Value>>,
109 pub message: String,
110 pub status_code: http::StatusCode,
111}
112
113impl fmt::Display for GitHubError {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 write!(f, "{}", self.message)?;
116
117 if let Some(documentation_url) = &self.documentation_url {
118 write!(f, "\nDocumentation URL: {documentation_url}")?;
119 }
120
121 if let Some(errors) = &self.errors.as_ref().filter(|errors| !errors.is_empty()) {
122 write!(f, "\nErrors:")?;
123 for error in errors.iter() {
124 write!(f, "\n- {error}")?;
125 }
126 }
127
128 Ok(())
129 }
130}
131
132impl std::error::Error for GitHubError {}