diff --git a/crates/gitbutler-core/src/error.rs b/crates/gitbutler-core/src/error.rs index ec64ed3c3..ba51f3f01 100644 --- a/crates/gitbutler-core/src/error.rs +++ b/crates/gitbutler-core/src/error.rs @@ -138,10 +138,6 @@ pub enum Code { Unknown, Validation, ProjectGitAuth, - /// An indicator for a conflict in the project which is used for flow-control. - /// - /// See usages for details on what these conflicts can be. - ProjectConflict, } impl std::fmt::Display for Code { @@ -150,7 +146,6 @@ impl std::fmt::Display for Code { Code::Unknown => "errors.unknown", Code::Validation => "errors.validation", Code::ProjectGitAuth => "errors.projects.git.auth", - Code::ProjectConflict => "errors.projects.conflict", }; f.write_str(code) } diff --git a/crates/gitbutler-core/src/project_repository/repository.rs b/crates/gitbutler-core/src/project_repository/repository.rs index 60ace9689..4a65ab6a5 100644 --- a/crates/gitbutler-core/src/project_repository/repository.rs +++ b/crates/gitbutler-core/src/project_repository/repository.rs @@ -7,6 +7,7 @@ use std::{ use anyhow::{anyhow, Context, Result}; use super::conflicts; +use crate::virtual_branches::errors::Marker; use crate::{ askpass, error, git::{self, credentials::HelpError, Url}, @@ -89,7 +90,7 @@ impl Repository { pub fn assure_resolved(&self) -> Result<()> { if self.is_resolving() { - Err(anyhow!("project has active conflicts")).context(Code::ProjectConflict) + Err(anyhow!("project has active conflicts")).context(Marker::ProjectConflict) } else { Ok(()) } @@ -97,7 +98,7 @@ impl Repository { pub fn assure_unconflicted(&self) -> Result<()> { if conflicts::is_conflicting(self, None)? { - Err(anyhow!("project has active conflicts")).context(Code::ProjectConflict) + Err(anyhow!("project has active conflicts")).context(Marker::ProjectConflict) } else { Ok(()) } diff --git a/crates/gitbutler-core/src/virtual_branches/base.rs b/crates/gitbutler-core/src/virtual_branches/base.rs index 6a0f9025e..a17fdcf21 100644 --- a/crates/gitbutler-core/src/virtual_branches/base.rs +++ b/crates/gitbutler-core/src/virtual_branches/base.rs @@ -11,7 +11,7 @@ use super::{ }, target, BranchId, RemoteCommit, VirtualBranchHunk, VirtualBranchesHandle, }; -use crate::error::Code; +use crate::virtual_branches::errors::Marker; use crate::{ git::{self, diff}, project_repository::{self, LogUntil}, @@ -57,7 +57,7 @@ fn go_back_to_integration( )) .context("failed to get status")?; if !statuses.is_empty() { - return Err(anyhow!("current HEAD is dirty")).context(Code::ProjectConflict); + return Err(anyhow!("current HEAD is dirty")).context(Marker::ProjectConflict); } let vb_state = project_repository.project().virtual_branches(); diff --git a/crates/gitbutler-core/src/virtual_branches/controller.rs b/crates/gitbutler-core/src/virtual_branches/controller.rs index 467058c78..b63a3fc8d 100644 --- a/crates/gitbutler-core/src/virtual_branches/controller.rs +++ b/crates/gitbutler-core/src/virtual_branches/controller.rs @@ -630,7 +630,7 @@ impl ControllerInner { self.with_verify_branch(project_id, |project_repository, user| { let snapshot_tree = project_repository.project().prepare_snapshot(); let result = - super::apply_branch(project_repository, branch_id, user).map_err(Error::from_err); + super::apply_branch(project_repository, branch_id, user).map_err(Into::into); let _ = snapshot_tree.and_then(|snapshot_tree| { project_repository diff --git a/crates/gitbutler-core/src/virtual_branches/errors.rs b/crates/gitbutler-core/src/virtual_branches/errors.rs index 51d1a7352..2ce6e3f22 100644 --- a/crates/gitbutler-core/src/virtual_branches/errors.rs +++ b/crates/gitbutler-core/src/virtual_branches/errors.rs @@ -1,6 +1,5 @@ -use super::BranchId; use crate::error::{AnyhowContextExt, Context, ErrorWithContext}; -use crate::{git, project_repository::RemoteError, projects::ProjectId}; +use crate::{project_repository::RemoteError, projects::ProjectId}; /// A way to mark errors using `[anyhow::Context::context]` for later retrieval. /// @@ -10,27 +9,21 @@ use crate::{git, project_repository::RemoteError, projects::ProjectId}; pub enum Marker { /// Invalid state was detected, making the repository invalid for operation. VerificationFailure, + /// An indicator for a conflict in the project. + /// + /// See usages for details on what these conflicts can be. + ProjectConflict, } impl std::fmt::Display for Marker { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Marker::VerificationFailure => f.write_str(""), + Marker::ProjectConflict => f.write_str(""), } } } -#[derive(Debug, thiserror::Error)] -pub enum ApplyBranchError { - // TODO(ST): use local Marker to detect this case, apply the same to ProjectConflict - #[error("branch {0} is in a conflicting state")] - BranchConflicts(BranchId), - #[error(transparent)] - GitError(#[from] git::Error), - #[error(transparent)] - Other(#[from] anyhow::Error), -} - #[derive(Debug, thiserror::Error)] pub enum PushError { #[error(transparent)] @@ -48,11 +41,6 @@ impl ErrorWithContext for PushError { } } -#[derive(Debug)] -pub struct ForcePushNotAllowed { - pub project_id: ProjectId, -} - #[derive(Debug, thiserror::Error)] pub enum FetchFromTargetError { #[error("failed to fetch")] diff --git a/crates/gitbutler-core/src/virtual_branches/virtual.rs b/crates/gitbutler-core/src/virtual_branches/virtual.rs index cb657eed6..f76001e0c 100644 --- a/crates/gitbutler-core/src/virtual_branches/virtual.rs +++ b/crates/gitbutler-core/src/virtual_branches/virtual.rs @@ -25,11 +25,12 @@ use super::{ }, branch_to_remote_branch, errors, target, RemoteBranch, VirtualBranchesHandle, }; -use crate::error::{self, AnyhowContextExt, Code}; +use crate::error::Code; use crate::git::diff::{diff_files_into_hunks, trees, FileDiff}; use crate::git::{CommitExt, RepositoryExt}; use crate::time::now_since_unix_epoch_ms; use crate::virtual_branches::branch::HunkHash; +use crate::virtual_branches::errors::Marker; use crate::{ dedup::{dedup, dedup_fmt}, git::{ @@ -220,7 +221,7 @@ pub fn apply_branch( project_repository: &project_repository::Repository, branch_id: BranchId, user: Option<&users::User>, -) -> Result { +) -> Result { project_repository.assure_resolved()?; let repo = &project_repository.git_repository; @@ -435,7 +436,8 @@ pub fn apply_branch( .context("failed to merge trees")?; if merge_index.has_conflicts() { - return Err(errors::ApplyBranchError::BranchConflicts(branch_id)); + return Err(anyhow!("branch {branch_id} is in a conflicting state")) + .context(Marker::ProjectConflict); } // apply the branch @@ -1190,19 +1192,20 @@ pub fn integrate_upstream_commits( // scenario we would need to "cherry rebase" new upstream commits onto the last rebased // local commit. if has_rebased_commits && !can_use_force { - let message = "Aborted because force push is disallowed and commits have been rebased."; return Err(anyhow!("Cannot merge rebased commits without force push") - .context(error::Context::new(message).with_code(Code::ProjectConflict))); + .context("Aborted because force push is disallowed and commits have been rebased") + .context(Marker::ProjectConflict)); } let integration_result = match can_use_force { true => integrate_with_rebase(project_repository, &mut branch, &mut unknown_commits), false => { if has_rebased_commits { - let message = - "Aborted because force push is disallowed and commits have been rebased."; return Err(anyhow!("Cannot merge rebased commits without force push") - .context(error::Context::new(message).with_code(Code::ProjectConflict))); + .context( + "Aborted because force push is disallowed and commits have been rebased", + ) + .context(Marker::ProjectConflict)); } integrate_with_merge( project_repository, @@ -1215,8 +1218,8 @@ pub fn integrate_upstream_commits( }; if integration_result.as_ref().err().map_or(false, |err| { - err.custom_context() - .is_some_and(|c| c.code == Code::ProjectConflict) + err.downcast_ref() + .is_some_and(|marker: &Marker| *marker == Marker::ProjectConflict) }) { return Ok(()); }; @@ -1295,10 +1298,7 @@ pub fn integrate_with_merge( .conflict_style_merge() .force() .checkout()?; - return Err(anyhow!("Merging")).context(error::Context::new_static( - Code::ProjectConflict, - "Merge problem", - )); + return Err(anyhow!("merge problem")).context(Marker::ProjectConflict); } let merge_tree_oid = merge_index.write_tree_to(repo)?; @@ -3892,7 +3892,11 @@ pub fn create_virtual_branch_from_branch( match apply_branch(project_repository, branch.id, user) { Ok(_) => Ok(branch.id), - Err(errors::ApplyBranchError::BranchConflicts(_)) => { + Err(err) + if err + .downcast_ref() + .map_or(false, |marker: &Marker| *marker == Marker::ProjectConflict) => + { // if branch conflicts with the workspace, it's ok. keep it unapplied Ok(branch.id) } @@ -4023,7 +4027,7 @@ mod tests { // let conflicts = merge_index.conflicts()?; // let conflict_message = conflicts_to_string(conflicts)?; // return Err(anyhow!("Merge failed") -// .context(error::Context::new(Code::ProjectConflict, conflict_message)) +// .context(error::Context::new(Marker::ProjectConflict, conflict_message)) // .); // fn conflicts_to_string(conflicts: IndexConflicts) -> Result { diff --git a/crates/gitbutler-core/tests/suite/virtual_branches/apply_virtual_branch.rs b/crates/gitbutler-core/tests/suite/virtual_branches/apply_virtual_branch.rs index 6f85b98d2..3b9bf6db0 100644 --- a/crates/gitbutler-core/tests/suite/virtual_branches/apply_virtual_branch.rs +++ b/crates/gitbutler-core/tests/suite/virtual_branches/apply_virtual_branch.rs @@ -52,7 +52,7 @@ async fn deltect_conflict() { .await .unwrap_err() .downcast_ref(), - Some(errors::ApplyBranchError::BranchConflicts(_)) + Some(Marker::ProjectConflict) )); } } diff --git a/crates/gitbutler-core/tests/suite/virtual_branches/mod.rs b/crates/gitbutler-core/tests/suite/virtual_branches/mod.rs index c2ebb4ac9..0391fbd05 100644 --- a/crates/gitbutler-core/tests/suite/virtual_branches/mod.rs +++ b/crates/gitbutler-core/tests/suite/virtual_branches/mod.rs @@ -1,12 +1,12 @@ use std::path::PathBuf; use std::{fs, path, str::FromStr}; -use gitbutler_core::error::Code; +use gitbutler_core::virtual_branches::errors::Marker; use gitbutler_core::{ git, projects::{self, Project, ProjectId}, users, - virtual_branches::{branch, errors, Controller}, + virtual_branches::{branch, Controller}, }; use tempfile::TempDir; @@ -170,7 +170,7 @@ async fn resolve_conflict_flow() { .await .unwrap_err() .downcast_ref(), - Some(Code::ProjectConflict) + Some(Marker::ProjectConflict) )); } diff --git a/crates/gitbutler-core/tests/suite/virtual_branches/set_base_branch.rs b/crates/gitbutler-core/tests/suite/virtual_branches/set_base_branch.rs index a0fa65017..6b7bd2c82 100644 --- a/crates/gitbutler-core/tests/suite/virtual_branches/set_base_branch.rs +++ b/crates/gitbutler-core/tests/suite/virtual_branches/set_base_branch.rs @@ -123,7 +123,7 @@ mod go_back_to_integration { .await .unwrap_err() .downcast_ref(), - Some(Code::ProjectConflict) + Some(Marker::ProjectConflict) )); } @@ -159,7 +159,7 @@ mod go_back_to_integration { .await .unwrap_err() .downcast_ref(), - Some(Code::ProjectConflict) + Some(Marker::ProjectConflict) )); }