ralph_workflow/git_helpers/
rebase_kinds.rs1#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum RebaseErrorKind {
16 InvalidRevision { revision: String },
19
20 DirtyWorkingTree,
22
23 ConcurrentOperation { operation: String },
25
26 RepositoryCorrupt { details: String },
28
29 EnvironmentFailure { reason: String },
31
32 HookRejection { hook_name: String },
34
35 ContentConflict { files: Vec<String> },
38
39 PatchApplicationFailed { reason: String },
41
42 InteractiveStop { command: String },
44
45 EmptyCommit,
47
48 AutostashFailed { reason: String },
50
51 CommitCreationFailed { reason: String },
53
54 ReferenceUpdateFailed { reason: String },
56
57 #[cfg(any(test, feature = "test-utils"))]
60 ValidationFailed { reason: String },
61
62 #[cfg(any(test, feature = "test-utils"))]
65 ProcessTerminated { reason: String },
66
67 #[cfg(any(test, feature = "test-utils"))]
69 InconsistentState { details: String },
70
71 Unknown { details: String },
74}
75
76impl RebaseErrorKind {
77 #[must_use]
79 pub fn description(&self) -> String {
80 describe_rebase_error_kind(self)
81 }
82}
83
84fn describe_invalid_revision(revision: &str) -> String {
85 format!("Invalid or unresolvable revision: '{revision}'")
86}
87
88fn describe_dirty_working_tree() -> String {
89 "Working tree has uncommitted changes".to_string()
90}
91
92fn describe_concurrent_operation(operation: &str) -> String {
93 format!("Concurrent Git operation in progress: {operation}")
94}
95
96fn describe_repository_corrupt(details: &str) -> String {
97 format!("Repository integrity issue: {details}")
98}
99
100fn describe_environment_failure(reason: &str) -> String {
101 format!("Environment or configuration failure: {reason}")
102}
103
104fn describe_hook_rejection(hook_name: &str) -> String {
105 format!("Hook '{hook_name}' rejected the operation")
106}
107
108fn describe_content_conflict(file_count: usize) -> String {
109 format!("Merge conflicts in {file_count} file(s)",)
110}
111
112fn describe_patch_application_failed(reason: &str) -> String {
113 format!("Patch application failed: {reason}")
114}
115
116fn describe_interactive_stop(command: &str) -> String {
117 format!("Interactive rebase stopped at command: {command}")
118}
119
120fn describe_empty_commit() -> String {
121 "Empty or redundant commit".to_string()
122}
123
124fn describe_autostash_failed(reason: &str) -> String {
125 format!("Autostash failed: {reason}")
126}
127
128fn describe_commit_creation_failed(reason: &str) -> String {
129 format!("Commit creation failed: {reason}")
130}
131
132fn describe_reference_update_failed(reason: &str) -> String {
133 format!("Reference update failed: {reason}")
134}
135
136#[cfg(any(test, feature = "test-utils"))]
137fn describe_validation_failed(reason: &str) -> String {
138 format!("Post-rebase validation failed: {reason}")
139}
140
141#[cfg(any(test, feature = "test-utils"))]
142fn describe_process_terminated(reason: &str) -> String {
143 format!("Rebase process terminated: {reason}")
144}
145
146#[cfg(any(test, feature = "test-utils"))]
147fn describe_inconsistent_state(details: &str) -> String {
148 format!("Inconsistent rebase state: {details}")
149}
150
151fn describe_unknown(details: &str) -> String {
152 format!("Unknown rebase error: {details}")
153}
154
155fn describe_rebase_error_kind(kind: &RebaseErrorKind) -> String {
156 match kind {
157 RebaseErrorKind::InvalidRevision { revision } => describe_invalid_revision(revision),
158 RebaseErrorKind::DirtyWorkingTree => describe_dirty_working_tree(),
159 RebaseErrorKind::ConcurrentOperation { operation } => {
160 describe_concurrent_operation(operation)
161 }
162 RebaseErrorKind::RepositoryCorrupt { details } => describe_repository_corrupt(details),
163 RebaseErrorKind::EnvironmentFailure { reason } => describe_environment_failure(reason),
164 RebaseErrorKind::HookRejection { hook_name } => describe_hook_rejection(hook_name),
165 RebaseErrorKind::ContentConflict { files } => describe_content_conflict(files.len()),
166 RebaseErrorKind::PatchApplicationFailed { reason } => {
167 describe_patch_application_failed(reason)
168 }
169 RebaseErrorKind::InteractiveStop { command } => describe_interactive_stop(command),
170 RebaseErrorKind::EmptyCommit => describe_empty_commit(),
171 RebaseErrorKind::AutostashFailed { reason } => describe_autostash_failed(reason),
172 RebaseErrorKind::CommitCreationFailed { reason } => describe_commit_creation_failed(reason),
173 RebaseErrorKind::ReferenceUpdateFailed { reason } => {
174 describe_reference_update_failed(reason)
175 }
176 #[cfg(any(test, feature = "test-utils"))]
177 RebaseErrorKind::ValidationFailed { reason } => describe_validation_failed(reason),
178 #[cfg(any(test, feature = "test-utils"))]
179 RebaseErrorKind::ProcessTerminated { reason } => describe_process_terminated(reason),
180 #[cfg(any(test, feature = "test-utils"))]
181 RebaseErrorKind::InconsistentState { details } => describe_inconsistent_state(details),
182 RebaseErrorKind::Unknown { details } => describe_unknown(details),
183 }
184}
185
186impl RebaseErrorKind {
187 #[cfg(any(test, feature = "test-utils"))]
189 #[must_use]
190 pub const fn is_recoverable(&self) -> bool {
191 match self {
192 Self::ConcurrentOperation { .. } => true,
194 #[cfg(any(test, feature = "test-utils"))]
195 Self::ProcessTerminated { .. } | Self::InconsistentState { .. } => true,
196
197 Self::ContentConflict { .. } => true,
199
200 Self::InvalidRevision { .. }
202 | Self::DirtyWorkingTree
203 | Self::RepositoryCorrupt { .. }
204 | Self::EnvironmentFailure { .. }
205 | Self::HookRejection { .. }
206 | Self::PatchApplicationFailed { .. }
207 | Self::InteractiveStop { .. }
208 | Self::EmptyCommit
209 | Self::AutostashFailed { .. }
210 | Self::CommitCreationFailed { .. }
211 | Self::ReferenceUpdateFailed { .. } => false,
212 #[cfg(any(test, feature = "test-utils"))]
213 Self::ValidationFailed { .. } => false,
214 Self::Unknown { .. } => false,
215 }
216 }
217
218 #[cfg(any(test, feature = "test-utils"))]
220 #[must_use]
221 pub const fn category(&self) -> u8 {
222 match self {
223 Self::InvalidRevision { .. }
224 | Self::DirtyWorkingTree
225 | Self::ConcurrentOperation { .. }
226 | Self::RepositoryCorrupt { .. }
227 | Self::EnvironmentFailure { .. }
228 | Self::HookRejection { .. } => 1,
229
230 Self::ContentConflict { .. }
231 | Self::PatchApplicationFailed { .. }
232 | Self::InteractiveStop { .. }
233 | Self::EmptyCommit
234 | Self::AutostashFailed { .. }
235 | Self::CommitCreationFailed { .. }
236 | Self::ReferenceUpdateFailed { .. } => 2,
237
238 #[cfg(any(test, feature = "test-utils"))]
239 Self::ValidationFailed { .. } => 3,
240
241 #[cfg(any(test, feature = "test-utils"))]
242 Self::ProcessTerminated { .. } | Self::InconsistentState { .. } => 4,
243
244 Self::Unknown { .. } => 5,
245 }
246 }
247}
248
249impl std::fmt::Display for RebaseErrorKind {
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 write!(f, "{}", self.description())
252 }
253}
254
255impl std::error::Error for RebaseErrorKind {}
256
257#[derive(Debug, Clone, PartialEq, Eq)]
263pub enum RebaseResult {
264 Success,
266
267 Conflicts(Vec<String>),
269
270 NoOp { reason: String },
272
273 Failed(RebaseErrorKind),
275}
276
277impl RebaseResult {
278 #[cfg(any(test, feature = "test-utils"))]
280 #[must_use]
281 pub const fn is_success(&self) -> bool {
282 matches!(self, Self::Success)
283 }
284
285 #[cfg(any(test, feature = "test-utils"))]
287 #[must_use]
288 pub const fn has_conflicts(&self) -> bool {
289 matches!(self, Self::Conflicts(_))
290 }
291
292 #[cfg(any(test, feature = "test-utils"))]
294 #[must_use]
295 pub const fn is_noop(&self) -> bool {
296 matches!(self, Self::NoOp { .. })
297 }
298
299 #[cfg(any(test, feature = "test-utils"))]
301 #[must_use]
302 pub const fn is_failed(&self) -> bool {
303 matches!(self, Self::Failed(_))
304 }
305
306 #[cfg(any(test, feature = "test-utils"))]
308 #[must_use]
309 pub fn conflict_files(&self) -> Option<&[String]> {
310 match self {
311 Self::Conflicts(files) | Self::Failed(RebaseErrorKind::ContentConflict { files }) => {
312 Some(files)
313 }
314 _ => None,
315 }
316 }
317
318 #[cfg(any(test, feature = "test-utils"))]
320 #[must_use]
321 pub const fn error_kind(&self) -> Option<&RebaseErrorKind> {
322 match self {
323 Self::Failed(kind) => Some(kind),
324 _ => None,
325 }
326 }
327
328 #[cfg(any(test, feature = "test-utils"))]
330 #[must_use]
331 pub fn noop_reason(&self) -> Option<&str> {
332 match self {
333 Self::NoOp { reason } => Some(reason),
334 _ => None,
335 }
336 }
337}