vcs_forge/error.rs
1//! The facade's error type: the underlying [`processkit::Error`] the wrapper
2//! clients return, plus an [`Unsupported`](Error::Unsupported) variant for an
3//! operation a given forge's CLI does not provide.
4
5use crate::ForgeKind;
6
7/// An error from a [`Forge`](crate::Forge) operation.
8#[derive(Debug)]
9#[non_exhaustive]
10pub enum Error {
11 /// An underlying `vcs-github` / `vcs-gitlab` / `vcs-gitea` (i.e. `processkit`)
12 /// error.
13 Forge(processkit::Error),
14 /// The operation isn't available on this forge's CLI — e.g. `repo_view`,
15 /// `pr_mark_ready`, and `pr_checks` on Gitea, whose `tea` has no command for
16 /// them. The `operation` is the [`ForgeApi`](crate::ForgeApi) method name.
17 Unsupported {
18 /// Which forge lacks the operation.
19 forge: ForgeKind,
20 /// The [`ForgeApi`](crate::ForgeApi) method that isn't supported.
21 operation: &'static str,
22 },
23}
24
25impl Error {
26 /// Whether this is a **transient** network failure worth retrying (DNS,
27 /// connection reset, timeout) — forge commands are network-bound, so a higher
28 /// flow may want to retry. Named to match the wrapper classifiers
29 /// ([`vcs_cli_support::is_transient_fetch_error`]).
30 pub fn is_transient_fetch_error(&self) -> bool {
31 matches!(self, Error::Forge(e) if vcs_cli_support::is_transient_fetch_error(e))
32 }
33
34 /// Whether this is an [`Unsupported`](Error::Unsupported) operation (rather
35 /// than a forge/network failure).
36 pub fn is_unsupported(&self) -> bool {
37 matches!(self, Error::Unsupported { .. })
38 }
39}
40
41impl std::fmt::Display for Error {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 match self {
44 Error::Forge(e) => write!(f, "{e}"),
45 Error::Unsupported { forge, operation } => {
46 write!(f, "{} does not support `{operation}`", forge.as_str())
47 }
48 }
49 }
50}
51
52impl std::error::Error for Error {
53 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
54 match self {
55 Error::Forge(e) => Some(e),
56 Error::Unsupported { .. } => None,
57 }
58 }
59}
60
61impl From<processkit::Error> for Error {
62 fn from(e: processkit::Error) -> Self {
63 Error::Forge(e)
64 }
65}
66
67/// `Result` specialised to the facade [`Error`].
68pub type Result<T> = std::result::Result<T, Error>;