1use std::fmt;
4
5#[derive(Debug)]
7pub enum Error {
8 IssueNotFound {
9 id: String,
10 },
11 ClaimConflict {
12 id: String,
13 holder: String,
14 claimed_at: Option<String>,
15 },
16 BlockerCycle {
17 blocker: String,
18 issue: String,
19 },
20 InvalidState {
21 id: String,
22 state: String,
23 },
24 Other(anyhow::Error),
25}
26
27impl fmt::Display for Error {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Error::IssueNotFound { id } => write!(f, "issue {id} not found"),
31 Error::ClaimConflict {
32 id,
33 holder,
34 claimed_at,
35 } => write!(
36 f,
37 "{id} is claimed by {holder} since {}; pass --force to take it over",
38 claimed_at.as_deref().unwrap_or("an unknown time")
39 ),
40 Error::BlockerCycle { blocker, issue } if blocker == issue => {
41 write!(f, "issue {issue} cannot block itself")
42 }
43 Error::BlockerCycle { blocker, issue } => {
44 write!(
45 f,
46 "adding {blocker} -> {issue} would create a blocker cycle"
47 )
48 }
49 Error::InvalidState { id, state } => {
50 write!(f, "{id} is already {state}; cannot claim")
51 }
52 Error::Other(err) => write!(f, "{err}"),
53 }
54 }
55}
56
57impl std::error::Error for Error {
58 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
59 match self {
60 Error::Other(err) => Some(err.as_ref()),
61 _ => None,
62 }
63 }
64}
65
66impl From<anyhow::Error> for Error {
67 fn from(err: anyhow::Error) -> Self {
68 match err.downcast::<Error>() {
69 Ok(typed) => typed,
70 Err(other) => Error::Other(other),
71 }
72 }
73}
74
75impl From<std::io::Error> for Error {
76 fn from(err: std::io::Error) -> Self {
77 Error::Other(err.into())
78 }
79}