1use std::path::PathBuf;
4use thiserror::Error;
5
6pub type OpsResult<T> = Result<T, OpsError>;
8
9#[derive(Debug, Error)]
11pub enum OpsError {
12 #[error("No workspace found at {path}")]
14 WorkspaceNotFound { path: PathBuf },
15
16 #[error("No .self folder found at {path}. Run sync first.")]
18 StoreNotFound { path: PathBuf },
19
20 #[error("No project data found in .self store")]
22 ProjectNotFound,
23
24 #[error("No graph data found in .self store")]
26 GraphNotFound,
27
28 #[error("GitHub credentials not configured. Set GITHUB_USERNAME and GITHUB_TOKEN or use `vg config set`")]
30 GitHubNotConfigured,
31
32 #[error("Failed to clone repository {repo}: {message}")]
34 CloneFailed { repo: String, message: String },
35
36 #[error("GitHub API error for {resource}: {message}")]
38 GitHubApiError { resource: String, message: String },
39
40 #[error("IO error: {0}")]
42 Io(#[from] std::io::Error),
43
44 #[error("JSON error: {0}")]
46 Json(#[from] serde_json::Error),
47
48 #[error("Git error: {0}")]
50 Git(#[from] git2::Error),
51
52 #[error("Failed to resolve path {path}: {message}")]
54 PathResolution { path: PathBuf, message: String },
55
56 #[error("Configuration error: {0}")]
58 Config(String),
59
60 #[error("{context}: {message}")]
62 WithContext { context: String, message: String },
63}
64
65impl OpsError {
66 pub fn with_context(context: impl Into<String>, message: impl Into<String>) -> Self {
68 Self::WithContext {
69 context: context.into(),
70 message: message.into(),
71 }
72 }
73
74 pub fn path_resolution(path: impl Into<PathBuf>, message: impl Into<String>) -> Self {
76 Self::PathResolution {
77 path: path.into(),
78 message: message.into(),
79 }
80 }
81}
82
83impl From<anyhow::Error> for OpsError {
84 fn from(err: anyhow::Error) -> Self {
85 OpsError::WithContext {
86 context: "Operation failed".to_string(),
87 message: err.to_string(),
88 }
89 }
90}