1use std::path::PathBuf;
4
5use omnifuse_core::ErrorKind;
6use thiserror::Error;
7
8#[derive(Debug, Error)]
10pub enum GitError {
11 #[error("backend not initialized")]
13 NotInitialized,
14 #[error("not a git repository: {path}")]
16 InvalidRepository {
17 path: PathBuf
19 },
20 #[error("nothing to commit")]
22 NothingToCommit,
23 #[error("no files to commit")]
25 NoFilesToCommit,
26 #[error("network unavailable: {message}")]
28 NetworkUnavailable {
29 message: String
31 },
32 #[error("{count} file(s) in conflict", count = .files.len())]
34 Conflict {
35 files: Vec<PathBuf>
37 },
38 #[error("push rejected after {retries} attempts")]
40 PushRejected {
41 retries: u32
43 },
44 #[error("{op} failed: {stderr}")]
46 CommandFailed {
47 op: &'static str,
49 stderr: String
51 }
52}
53
54#[must_use]
56pub fn classify_git_error(error: &anyhow::Error) -> Option<ErrorKind> {
57 match error.downcast_ref::<GitError>() {
58 Some(GitError::NetworkUnavailable { .. }) => Some(ErrorKind::Offline),
59 Some(GitError::Conflict { .. } | GitError::PushRejected { .. }) => Some(ErrorKind::Conflict),
60 Some(GitError::InvalidRepository { .. }) => Some(ErrorKind::InvalidConfig),
61 Some(GitError::CommandFailed { .. }) => Some(ErrorKind::BackendCommandFailed),
62 Some(GitError::NotInitialized) => Some(ErrorKind::Internal),
63 Some(GitError::NothingToCommit | GitError::NoFilesToCommit) | None => None
64 }
65}
66
67#[must_use]
69pub fn is_nothing_to_commit(error: &anyhow::Error) -> bool {
70 matches!(error.downcast_ref::<GitError>(), Some(GitError::NothingToCommit))
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_classify_git_error() {
79 let offline: anyhow::Error = GitError::NetworkUnavailable {
80 message: "dns".to_string()
81 }
82 .into();
83 let conflict: anyhow::Error = GitError::Conflict {
84 files: vec!["README.md".into()]
85 }
86 .into();
87 let nothing: anyhow::Error = GitError::NothingToCommit.into();
88
89 assert_eq!(classify_git_error(&offline), Some(ErrorKind::Offline));
90 assert_eq!(classify_git_error(&conflict), Some(ErrorKind::Conflict));
91 assert_eq!(classify_git_error(¬hing), None);
92 assert!(is_nothing_to_commit(¬hing));
93 }
94}