diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 691a313c2..9d3246ddf 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -5,7 +5,6 @@ "rust-lang.rust-analyzer", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", - "ZixuanChen.vitest-explorer", "EditorConfig.EditorConfig" ] } diff --git a/gitbutler-app/src/git/diff.rs b/gitbutler-app/src/git/diff.rs index 2fe6d7915..b23f456b8 100644 --- a/gitbutler-app/src/git/diff.rs +++ b/gitbutler-app/src/git/diff.rs @@ -59,6 +59,7 @@ impl Default for Options { pub fn workdir( repository: &Repository, commit_oid: &git::Oid, + context_lines: u32, ) -> Result>> { let commit = repository .find_commit(*commit_oid) @@ -72,7 +73,7 @@ pub fn workdir( .show_binary(true) .show_untracked_content(true) .ignore_submodules(true) - .context_lines(0); + .context_lines(context_lines); let diff = repository.diff_tree_to_workdir(Some(&tree), Some(&mut diff_opts))?; @@ -83,6 +84,7 @@ pub fn trees( repository: &Repository, old_tree: &git::Tree, new_tree: &git::Tree, + context_lines: u32, ) -> Result>> { let mut diff_opts = git2::DiffOptions::new(); diff_opts @@ -90,7 +92,7 @@ pub fn trees( .include_untracked(true) .show_binary(true) .ignore_submodules(true) - .context_lines(0) + .context_lines(context_lines) .show_untracked_content(true); let diff = @@ -340,7 +342,7 @@ mod tests { let head_commit_id = repository.head().unwrap().peel_to_commit().unwrap().id(); - let diff = workdir(&repository, &head_commit_id).unwrap(); + let diff = workdir(&repository, &head_commit_id, 0).unwrap(); assert_eq!(diff.len(), 1); assert_eq!( diff[&path::PathBuf::from("file")], @@ -363,7 +365,7 @@ mod tests { let head_commit_id = repository.head().unwrap().peel_to_commit().unwrap().id(); - let diff = workdir(&repository, &head_commit_id).unwrap(); + let diff = workdir(&repository, &head_commit_id, 0).unwrap(); assert_eq!(diff.len(), 1); assert_eq!( diff[&path::PathBuf::from("first")], @@ -387,7 +389,7 @@ mod tests { let head_commit_id = repository.head().unwrap().peel_to_commit().unwrap().id(); - let diff = workdir(&repository, &head_commit_id).unwrap(); + let diff = workdir(&repository, &head_commit_id, 0).unwrap(); assert_eq!(diff.len(), 2); assert_eq!( diff[&path::PathBuf::from("first")], @@ -431,7 +433,7 @@ mod tests { let head_commit_id = repository.head().unwrap().peel_to_commit().unwrap().id(); - let diff = workdir(&repository, &head_commit_id).unwrap(); + let diff = workdir(&repository, &head_commit_id, 0).unwrap(); assert_eq!( diff[&path::PathBuf::from("image")], vec![Hunk { @@ -474,7 +476,7 @@ mod tests { let head_commit_id = repository.head().unwrap().peel_to_commit().unwrap().id(); - let diff = workdir(&repository, &head_commit_id).unwrap(); + let diff = workdir(&repository, &head_commit_id, 0).unwrap(); assert_eq!( diff[&path::PathBuf::from("file")], vec![Hunk { diff --git a/gitbutler-app/src/project_repository/repository.rs b/gitbutler-app/src/project_repository/repository.rs index f0fa3f1ec..930b7c093 100644 --- a/gitbutler-app/src/project_repository/repository.rs +++ b/gitbutler-app/src/project_repository/repository.rs @@ -365,6 +365,13 @@ impl Repository { if self.project.omit_certificate_check.unwrap_or(false) { cbs.certificate_check(|_, _| Ok(git2::CertificateCheckStatus::CertificateOk)); } + cbs.push_update_reference(|_reference: &str, status: Option<&str>| { + if let Some(status) = status { + return Err(git2::Error::from_str(status)); + }; + Ok(()) + }); + match remote.push( &[refspec.as_str()], Some(&mut git2::PushOptions::new().remote_callbacks(cbs)), diff --git a/gitbutler-app/src/projects/commands.rs b/gitbutler-app/src/projects/commands.rs index 9e0fb0b7b..d6d7c7feb 100644 --- a/gitbutler-app/src/projects/commands.rs +++ b/gitbutler-app/src/projects/commands.rs @@ -70,6 +70,10 @@ impl From for Error { code: Code::Projects, message: "Path not found".to_string(), }, + controller::AddError::SubmodulesNotSupported => Error::UserError { + code: Code::Projects, + message: "Repositories with git submodules are not supported".to_string(), + }, controller::AddError::User(error) => error.into(), controller::AddError::Other(error) => { tracing::error!(?error, "failed to add project"); diff --git a/gitbutler-app/src/projects/controller.rs b/gitbutler-app/src/projects/controller.rs index 1fae9949a..04187c794 100644 --- a/gitbutler-app/src/projects/controller.rs +++ b/gitbutler-app/src/projects/controller.rs @@ -66,6 +66,10 @@ impl Controller { return Err(AddError::NotAGitRepository); }; + if path.join(".gitmodules").exists() { + return Err(AddError::SubmodulesNotSupported); + } + let id = uuid::Uuid::new_v4().to_string(); // title is the base name of the file @@ -79,6 +83,7 @@ impl Controller { title, path: path.to_path_buf(), api: None, + use_diff_context: Some(true), ..Default::default() }; @@ -201,6 +206,10 @@ impl Controller { tracing::error!(project_id = %id, ?error, "failed to remove project data",); } + if let Err(error) = std::fs::remove_file(project.path.join(".git/gitbutler.json")) { + tracing::error!(project_id = %project.id, ?error, "failed to remove .git/gitbutler.json data",); + } + Ok(()) } } @@ -253,6 +262,8 @@ pub enum AddError { PathNotFound, #[error("project already exists")] AlreadyExists, + #[error("submodules not supported")] + SubmodulesNotSupported, #[error(transparent)] User(#[from] users::GetError), #[error(transparent)] diff --git a/gitbutler-app/src/projects/project.rs b/gitbutler-app/src/projects/project.rs index e55c23c17..1614554ba 100644 --- a/gitbutler-app/src/projects/project.rs +++ b/gitbutler-app/src/projects/project.rs @@ -78,6 +78,8 @@ pub struct Project { pub project_data_last_fetch: Option, #[serde(default)] pub omit_certificate_check: Option, + #[serde(default)] + pub use_diff_context: Option, } impl AsRef for Project { diff --git a/gitbutler-app/src/projects/storage.rs b/gitbutler-app/src/projects/storage.rs index 19b77a16c..642285191 100644 --- a/gitbutler-app/src/projects/storage.rs +++ b/gitbutler-app/src/projects/storage.rs @@ -47,6 +47,7 @@ pub struct UpdateRequest { pub gitbutler_code_push_state: Option, pub project_data_last_fetched: Option, pub omit_certificate_check: Option, + pub use_diff_context: Option, } #[derive(Debug, thiserror::Error)] @@ -139,6 +140,10 @@ impl Storage { project.omit_certificate_check = Some(omit_certificate_check); } + if let Some(use_diff_context) = update_request.use_diff_context { + project.use_diff_context = Some(use_diff_context); + } + self.storage .write(PROJECTS_FILE, &serde_json::to_string_pretty(&projects)?)?; diff --git a/gitbutler-app/src/virtual_branches/base.rs b/gitbutler-app/src/virtual_branches/base.rs index f62418578..7d069b1ea 100644 --- a/gitbutler-app/src/virtual_branches/base.rs +++ b/gitbutler-app/src/virtual_branches/base.rs @@ -135,7 +135,12 @@ pub fn set_base_branch( // if there are any commits on the head branch or uncommitted changes in the working directory, we need to // put them into a virtual branch - let wd_diff = diff::workdir(repo, ¤t_head_commit.id())?; + let use_context = project_repository + .project() + .use_diff_context + .unwrap_or(false); + let context_lines = if use_context { 3_u32 } else { 0_u32 }; + let wd_diff = diff::workdir(repo, ¤t_head_commit.id(), context_lines)?; if !wd_diff.is_empty() || current_head_commit.id() != target.sha { let hunks_by_filepath = super::virtual_hunks_by_filepath(&project_repository.project().path, &wd_diff); @@ -308,6 +313,12 @@ pub fn update_base_branch( let branch_writer = branch::Writer::new(gb_repository).context("failed to create branch writer")?; + let use_context = project_repository + .project() + .use_diff_context + .unwrap_or(false); + let context_lines = if use_context { 3_u32 } else { 0_u32 }; + // try to update every branch let updated_vbranches = super::get_status_by_branch(gb_repository, project_repository)? .into_iter() @@ -341,6 +352,7 @@ pub fn update_base_branch( &project_repository.git_repository, &branch_head_tree, &branch_tree, + context_lines, )?; if non_commited_files.is_empty() { // if there are no commited files, then the branch is fully merged diff --git a/gitbutler-app/src/virtual_branches/commands.rs b/gitbutler-app/src/virtual_branches/commands.rs index 7efb586e1..1335e8b7e 100644 --- a/gitbutler-app/src/virtual_branches/commands.rs +++ b/gitbutler-app/src/virtual_branches/commands.rs @@ -12,7 +12,7 @@ use crate::{ }; use super::{ - branch::BranchId, + branch::{self, BranchId}, controller::{Controller, ControllerError}, BaseBranch, RemoteBranchFile, }; @@ -80,11 +80,23 @@ pub async fn list_virtual_branches( code: Code::Validation, message: "Malformed project id".to_string(), })?; - let branches = handle + let (branches, uses_diff_context) = handle .state::() .list_virtual_branches(&project_id) .await?; + // Migration: If use_diff_context is not already set and if there are no vbranches, set use_diff_context to true + if !uses_diff_context && branches.is_empty() { + let _ = handle + .state::() + .update(&projects::UpdateRequest { + id: project_id, + use_diff_context: Some(true), + ..Default::default() + }) + .await; + } + let proxy = handle.state::(); let branches = proxy.proxy_virtual_branches(branches).await; Ok(branches) diff --git a/gitbutler-app/src/virtual_branches/controller.rs b/gitbutler-app/src/virtual_branches/controller.rs index bb58f63fa..978f58fee 100644 --- a/gitbutler-app/src/virtual_branches/controller.rs +++ b/gitbutler-app/src/virtual_branches/controller.rs @@ -124,7 +124,8 @@ impl Controller { pub async fn list_virtual_branches( &self, project_id: &ProjectId, - ) -> Result, ControllerError> { + ) -> Result<(Vec, bool), ControllerError> + { self.inner(project_id) .await .list_virtual_branches(project_id) @@ -493,7 +494,8 @@ impl ControllerInner { pub async fn list_virtual_branches( &self, project_id: &ProjectId, - ) -> Result, ControllerError> { + ) -> Result<(Vec, bool), ControllerError> + { let _permit = self.semaphore.acquire().await; self.with_verify_branch(project_id, |gb_repository, project_repository, _| { @@ -570,9 +572,17 @@ impl ControllerInner { ) -> Result, Error> { let project = self.projects.get(project_id)?; let project_repository = project_repository::Repository::open(&project)?; - - super::list_remote_commit_files(&project_repository.git_repository, commit_oid) - .map_err(Into::into) + let use_context = project_repository + .project() + .use_diff_context + .unwrap_or(false); + let context_lines = if use_context { 3_u32 } else { 0_u32 }; + super::list_remote_commit_files( + &project_repository.git_repository, + commit_oid, + context_lines, + ) + .map_err(Into::into) } pub fn set_base_branch( diff --git a/gitbutler-app/src/virtual_branches/files.rs b/gitbutler-app/src/virtual_branches/files.rs index 35812e68b..d2df431b8 100644 --- a/gitbutler-app/src/virtual_branches/files.rs +++ b/gitbutler-app/src/virtual_branches/files.rs @@ -19,6 +19,7 @@ pub struct RemoteBranchFile { pub fn list_remote_commit_files( repository: &git::Repository, commit_oid: git::Oid, + context_lines: u32, ) -> Result, errors::ListRemoteCommitFilesError> { let commit = match repository.find_commit(commit_oid) { Ok(commit) => Ok(commit), @@ -35,7 +36,7 @@ pub fn list_remote_commit_files( let parent = commit.parent(0).context("failed to get parent commit")?; let commit_tree = commit.tree().context("failed to get commit tree")?; let parent_tree = parent.tree().context("failed to get parent tree")?; - let diff = diff::trees(repository, &parent_tree, &commit_tree)?; + let diff = diff::trees(repository, &parent_tree, &commit_tree, context_lines)?; let files = diff .into_iter() diff --git a/gitbutler-app/src/virtual_branches/tests.rs b/gitbutler-app/src/virtual_branches/tests.rs index f74880fb7..3c11b93ab 100644 --- a/gitbutler-app/src/virtual_branches/tests.rs +++ b/gitbutler-app/src/virtual_branches/tests.rs @@ -81,7 +81,7 @@ fn test_commit_on_branch_then_change_file_then_get_status() -> Result<()> { "line0\nline1\nline2\nline3\nline4\n", )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches[0]; assert_eq!(branch.files.len(), 1); assert_eq!(branch.commits.len(), 0); @@ -99,7 +99,7 @@ fn test_commit_on_branch_then_change_file_then_get_status() -> Result<()> { )?; // status (no files) - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches[0]; assert_eq!(branch.files.len(), 0); assert_eq!(branch.commits.len(), 1); @@ -110,7 +110,7 @@ fn test_commit_on_branch_then_change_file_then_get_status() -> Result<()> { )?; // should have just the last change now, the other line is committed - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches[0]; assert_eq!(branch.files.len(), 1); assert_eq!(branch.commits.len(), 1); @@ -170,7 +170,7 @@ fn test_signed_commit() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository).unwrap(); + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository).unwrap(); let commit_id = &branches[0].commits[0].id; let commit_obj = project_repository.git_repository.find_commit(*commit_id)?; // check the raw_header contains the string "SSH SIGNATURE" @@ -235,7 +235,7 @@ fn test_track_binary_files() -> Result<()> { let mut file = fs::File::create(std::path::Path::new(&project.path).join("image.bin"))?; file.write_all(&image_data)?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches[0]; assert_eq!(branch.files.len(), 2); let img_file = &branch @@ -262,7 +262,7 @@ fn test_track_binary_files() -> Result<()> { )?; // status (no files) - let branches = list_virtual_branches(&gb_repository, &project_repository).unwrap(); + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository).unwrap(); let commit_id = &branches[0].commits[0].id; let commit_obj = project_repository.git_repository.find_commit(*commit_id)?; let tree = commit_obj.tree()?; @@ -291,7 +291,7 @@ fn test_track_binary_files() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository).unwrap(); + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository).unwrap(); let commit_id = &branches[0].commits[0].id; // get tree from commit_id let commit_obj = project_repository.git_repository.find_commit(*commit_id)?; @@ -621,7 +621,7 @@ fn test_updated_ownership_should_bubble_up() -> Result<()> { )?; get_status_by_branch(&gb_repository, &project_repository).expect("failed to get status"); let files = branch_reader.read(&branch1_id)?.ownership.files; - assert_eq!(files, vec!["test.txt:14-15,1-2".parse()?]); + assert_eq!(files, vec!["test.txt:11-15,1-5".parse()?]); assert_eq!( files[0].hunks[0].timestam_ms(), files[0].hunks[1].timestam_ms(), @@ -641,7 +641,7 @@ fn test_updated_ownership_should_bubble_up() -> Result<()> { let files1 = branch_reader.read(&branch1_id)?.ownership.files; assert_eq!( files1, - vec!["test2.txt:1-2".parse()?, "test.txt:14-15,1-2".parse()?] + vec!["test2.txt:1-2".parse()?, "test.txt:11-15,1-5".parse()?] ); assert_ne!( @@ -667,7 +667,7 @@ fn test_updated_ownership_should_bubble_up() -> Result<()> { let files2 = branch_reader.read(&branch1_id)?.ownership.files; assert_eq!( files2, - vec!["test.txt:1-3,14-15".parse()?, "test2.txt:1-2".parse()?,] + vec!["test.txt:1-6,11-15".parse()?, "test2.txt:1-2".parse()?,] ); assert_ne!( @@ -736,12 +736,12 @@ fn test_move_hunks_multiple_sources() -> Result<()> { let branch_writer = branch::Writer::new(&gb_repository)?; let mut branch2 = branch_reader.read(&branch2_id)?; branch2.ownership = Ownership { - files: vec!["test.txt:1-2".parse()?], + files: vec!["test.txt:1-5".parse()?], }; branch_writer.write(&mut branch2)?; let mut branch1 = branch_reader.read(&branch1_id)?; branch1.ownership = Ownership { - files: vec!["test.txt:14-15".parse()?], + files: vec!["test.txt:11-15".parse()?], }; branch_writer.write(&mut branch1)?; @@ -765,7 +765,7 @@ fn test_move_hunks_multiple_sources() -> Result<()> { &project_repository, branch::BranchUpdateRequest { id: branch3_id, - ownership: Some("test.txt:1-2,14-15".parse()?), + ownership: Some("test.txt:1-5,11-15".parse()?), ..Default::default() }, )?; @@ -788,11 +788,11 @@ fn test_move_hunks_multiple_sources() -> Result<()> { ); assert_eq!( files_by_branch_id[&branch3_id][std::path::Path::new("test.txt")][0].diff, - "@@ -0,0 +1 @@\n+line0\n" + "@@ -1,3 +1,4 @@\n+line0\n line1\n line2\n line3\n" ); assert_eq!( files_by_branch_id[&branch3_id][std::path::Path::new("test.txt")][1].diff, - "@@ -12,0 +14 @@ line12\n+line13\n" + "@@ -10,3 +11,4 @@ line9\n line10\n line11\n line12\n+line13\n" ); Ok(()) } @@ -848,7 +848,7 @@ fn test_move_hunks_partial_explicitly() -> Result<()> { &project_repository, branch::BranchUpdateRequest { id: branch2_id, - ownership: Some("test.txt:1-2".parse()?), + ownership: Some("test.txt:1-5".parse()?), ..Default::default() }, )?; @@ -869,7 +869,7 @@ fn test_move_hunks_partial_explicitly() -> Result<()> { ); assert_eq!( files_by_branch_id[&branch1_id][std::path::Path::new("test.txt")][0].diff, - "@@ -13,0 +15 @@ line13\n+line14\n" + "@@ -11,3 +12,4 @@ line10\n line11\n line12\n line13\n+line14\n" ); assert_eq!(files_by_branch_id[&branch2_id].len(), 1); @@ -879,7 +879,7 @@ fn test_move_hunks_partial_explicitly() -> Result<()> { ); assert_eq!( files_by_branch_id[&branch2_id][std::path::Path::new("test.txt")][0].diff, - "@@ -0,0 +1 @@\n+line0\n" + "@@ -1,3 +1,4 @@\n+line0\n line1\n line2\n line3\n" ); Ok(()) @@ -915,11 +915,7 @@ fn test_add_new_hunk_to_the_end() -> Result<()> { get_status_by_branch(&gb_repository, &project_repository).expect("failed to get status"); assert_eq!( statuses[0].1[std::path::Path::new("test.txt")][0].diff, - "@@ -14 +13,0 @@ line13\n-line13\n" - ); - assert_eq!( - statuses[0].1[std::path::Path::new("test.txt")][1].diff, - "@@ -15,0 +15 @@ line14\n+line15\n" + "@@ -11,5 +11,5 @@ line10\n line11\n line12\n line13\n-line13\n line14\n+line15\n" ); std::fs::write( @@ -932,15 +928,11 @@ fn test_add_new_hunk_to_the_end() -> Result<()> { assert_eq!( statuses[0].1[std::path::Path::new("test.txt")][0].diff, - "@@ -15,0 +16 @@ line14\n+line15\n" + "@@ -11,5 +12,5 @@ line10\n line11\n line12\n line13\n-line13\n line14\n+line15\n" ); assert_eq!( statuses[0].1[std::path::Path::new("test.txt")][1].diff, - "@@ -0,0 +1 @@\n+line0\n" - ); - assert_eq!( - statuses[0].1[std::path::Path::new("test.txt")][2].diff, - "@@ -14 +14,0 @@ line13\n-line13\n" + "@@ -1,3 +1,4 @@\n+line0\n line1\n line2\n line3\n" ); Ok(()) @@ -1040,7 +1032,7 @@ fn test_merge_vbranch_upstream_clean_rebase() -> Result<()> { .context("failed to write target branch after push")?; // create the branch - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches[0]; assert_eq!(branch1.files.len(), 1); assert_eq!(branch1.commits.len(), 1); @@ -1054,7 +1046,7 @@ fn test_merge_vbranch_upstream_clean_rebase() -> Result<()> { None, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches[0]; let contents = std::fs::read(std::path::Path::new(&project.path).join(file_path))?; @@ -1163,7 +1155,7 @@ fn test_merge_vbranch_upstream_conflict() -> Result<()> { .context("failed to write target branch after push")?; // create the branch - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches[0]; assert_eq!(branch1.files.len(), 1); @@ -1172,7 +1164,7 @@ fn test_merge_vbranch_upstream_conflict() -> Result<()> { merge_virtual_branch_upstream(&gb_repository, &project_repository, &branch1.id, None, None)?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches[0]; let contents = std::fs::read(std::path::Path::new(&project.path).join(file_path))?; @@ -1192,7 +1184,7 @@ fn test_merge_vbranch_upstream_conflict() -> Result<()> { )?; // make gb see the conflict resolution - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; assert!(branches[0].conflicted); // commit the merge resolution @@ -1207,7 +1199,7 @@ fn test_merge_vbranch_upstream_conflict() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches[0]; assert!(!branch1.conflicted); assert_eq!(branch1.files.len(), 0); @@ -1247,7 +1239,7 @@ fn test_unapply_ownership_partial() -> Result<()> { ) .expect("failed to create virtual branch"); - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; assert_eq!(branches.len(), 1); assert_eq!(branches[0].files.len(), 1); assert_eq!(branches[0].ownership.files.len(), 1); @@ -1261,11 +1253,11 @@ fn test_unapply_ownership_partial() -> Result<()> { unapply_ownership( &gb_repository, &project_repository, - &"test.txt:5-6".parse().unwrap(), + &"test.txt:2-6".parse().unwrap(), ) .unwrap(); - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; assert_eq!(branches.len(), 1); assert_eq!(branches[0].files.len(), 0); assert_eq!(branches[0].ownership.files.len(), 0); @@ -1339,7 +1331,7 @@ fn test_apply_unapply_branch() -> Result<()> { let contents = std::fs::read(std::path::Path::new(&project.path).join(file_path2))?; assert_eq!("line5\nline6\n", String::from_utf8(contents)?); - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1); assert!(branch.active); @@ -1351,7 +1343,7 @@ fn test_apply_unapply_branch() -> Result<()> { let contents = std::fs::read(std::path::Path::new(&project.path).join(file_path2))?; assert_eq!("line5\nline6\n", String::from_utf8(contents)?); - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1); assert!(!branch.active); @@ -1365,7 +1357,7 @@ fn test_apply_unapply_branch() -> Result<()> { let contents = std::fs::read(std::path::Path::new(&project.path).join(file_path2))?; assert_eq!("line5\nline6\n", String::from_utf8(contents)?); - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1); assert!(branch.active); @@ -1621,7 +1613,7 @@ fn test_detect_mergeable_branch() -> Result<()> { }; branch_writer.write(&mut branch4)?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; assert_eq!(branches.len(), 4); let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap(); @@ -1803,7 +1795,7 @@ fn test_upstream_integrated_vbranch() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert!(branch1.commits.iter().any(|c| c.is_integrated)); @@ -1850,7 +1842,7 @@ fn test_commit_same_hunk_twice() -> Result<()> { "line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nline11\nline12\n", )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1); @@ -1869,7 +1861,7 @@ fn test_commit_same_hunk_twice() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 0, "no files expected"); @@ -1889,7 +1881,7 @@ fn test_commit_same_hunk_twice() -> Result<()> { "line1\nPATCH1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nline11\nline12\n", )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1, "one file should be changed"); @@ -1906,7 +1898,7 @@ fn test_commit_same_hunk_twice() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!( @@ -1951,7 +1943,7 @@ fn test_commit_same_file_twice() -> Result<()> { "line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nline11\nline12\n", )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1); @@ -1970,7 +1962,7 @@ fn test_commit_same_file_twice() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 0, "no files expected"); @@ -1990,7 +1982,7 @@ fn test_commit_same_file_twice() -> Result<()> { "line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\npatch2\nline11\nline12\n", )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1, "one file should be changed"); @@ -2007,7 +1999,7 @@ fn test_commit_same_file_twice() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!( @@ -2052,7 +2044,7 @@ fn test_commit_partial_by_hunk() -> Result<()> { "line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\npatch2\nline11\nline12\n", )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1); @@ -2065,13 +2057,13 @@ fn test_commit_partial_by_hunk() -> Result<()> { &project_repository, &branch1_id, "first commit to test.txt", - Some(&"test.txt:2-3".parse::().unwrap()), + Some(&"test.txt:1-6".parse::().unwrap()), None, None, false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 1); @@ -2085,13 +2077,13 @@ fn test_commit_partial_by_hunk() -> Result<()> { &project_repository, &branch1_id, "second commit to test.txt", - Some(&"test.txt:19-20".parse::().unwrap()), + Some(&"test.txt:16-22".parse::().unwrap()), None, None, false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap(); assert_eq!(branch.files.len(), 0); @@ -2158,7 +2150,7 @@ fn test_commit_partial_by_file() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap(); // branch one test.txt has just the 1st and 3rd hunks applied @@ -2234,7 +2226,7 @@ fn test_commit_add_and_delete_files() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap(); // branch one test.txt has just the 1st and 3rd hunks applied @@ -2305,7 +2297,7 @@ fn test_commit_executable_and_symlinks() -> Result<()> { false, )?; - let branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap(); let commit = &branch1.commits[0].id; @@ -2407,7 +2399,7 @@ fn test_verify_branch_commits_to_integration() -> Result<()> { integration::verify_branch(&gb_repository, &project_repository).unwrap(); // one virtual branch with two commits was created - let virtual_branches = list_virtual_branches(&gb_repository, &project_repository)?; + let (virtual_branches, _) = list_virtual_branches(&gb_repository, &project_repository)?; assert_eq!(virtual_branches.len(), 1); let branch = &virtual_branches.first().unwrap(); diff --git a/gitbutler-app/src/virtual_branches/virtual.rs b/gitbutler-app/src/virtual_branches/virtual.rs index b5cbcd869..d088814c2 100644 --- a/gitbutler-app/src/virtual_branches/virtual.rs +++ b/gitbutler-app/src/virtual_branches/virtual.rs @@ -4,8 +4,9 @@ use std::{collections::HashMap, path, time, vec}; use std::os::unix::prelude::*; use anyhow::{bail, Context, Result}; -use diffy::{apply_bytes, Patch}; -use git2_hooks::{HookResult, PrepareCommitMsgSource}; +use bstr::ByteSlice; +use diffy::{apply, Patch}; +use git2_hooks::HookResult; use regex::Regex; use serde::Serialize; @@ -728,7 +729,7 @@ fn find_base_tree<'a>( pub fn list_virtual_branches( gb_repository: &gb_repository::Repository, project_repository: &project_repository::Repository, -) -> Result, errors::ListVirtualBranchesError> { +) -> Result<(Vec, bool), errors::ListVirtualBranchesError> { let mut branches: Vec = Vec::new(); let default_target = gb_repository @@ -889,21 +890,29 @@ pub fn list_virtual_branches( let branches = branches_with_large_files_abridged(branches); let mut branches = branches_with_hunk_locks(branches, project_repository)?; - for branch in &mut branches { - branch.files = files_with_hunk_context( - &project_repository.git_repository, - branch.files.clone(), - 3, - branch.head, - ) - .context("failed to add hunk context")?; + + // If there no context lines are used internally, add them here, before returning to the UI + if context_lines(project_repository) == 0 { + for branch in &mut branches { + branch.files = files_with_hunk_context( + &project_repository.git_repository, + branch.files.clone(), + 3, + branch.head, + ) + .context("failed to add hunk context")?; + } } branches.sort_by(|a, b| a.order.cmp(&b.order)); super::integration::update_gitbutler_integration(gb_repository, project_repository)?; - Ok(branches) + let uses_diff_context = project_repository + .project() + .use_diff_context + .unwrap_or(false); + Ok((branches, uses_diff_context)) } fn branches_with_large_files_abridged(mut branches: Vec) -> Vec { @@ -940,6 +949,7 @@ fn branches_with_hunk_locks( &project_repository.git_repository, &parent_tree, &commit_tree, + context_lines(project_repository), )?; for branch in &mut branches { for file in &mut branch.files { @@ -1091,6 +1101,7 @@ pub fn calculate_non_commited_diffs( &project_repository.git_repository, &branch_head, &branch_tree, + context_lines(project_repository), ) .context("failed to diff trees")?; @@ -1132,6 +1143,7 @@ fn list_virtual_commit_files( &project_repository.git_repository, &parent_tree, &commit_tree, + context_lines(project_repository), )?; let hunks_by_filepath = virtual_hunks_by_filepath(&project_repository.project().path, &diff); Ok(virtual_hunks_to_virtual_files( @@ -1895,6 +1907,7 @@ fn get_non_applied_status( &project_repository.git_repository, &target_tree, &branch_tree, + context_lines(project_repository), )?; Ok((branch, diff)) @@ -1913,8 +1926,12 @@ fn get_applied_status( default_target: &target::Target, mut virtual_branches: Vec, ) -> Result { - let mut diff = diff::workdir(&project_repository.git_repository, &default_target.sha) - .context("failed to diff workdir")?; + let mut diff = diff::workdir( + &project_repository.git_repository, + &default_target.sha, + context_lines(project_repository), + ) + .context("failed to diff workdir")?; // sort by order, so that the default branch is first (left in the ui) virtual_branches.sort_by(|a, b| a.order.cmp(&b.order)); @@ -2291,39 +2308,37 @@ pub fn write_tree_onto_tree( .peel_to_blob() .context("failed to get blob")?; - // get the contents - let mut blob_contents = blob.content().to_vec(); + let mut blob_contents = blob.content().to_str()?.to_string(); let mut hunks = hunks.clone(); hunks.sort_by_key(|hunk| hunk.new_start); + let mut all_diffs = String::new(); for hunk in hunks { - let patch = format!("--- original\n+++ modified\n{}", hunk.diff); - let patch_bytes = patch.as_bytes(); - let patch = Patch::from_bytes(patch_bytes)?; - blob_contents = apply_bytes(&blob_contents, &patch) - .context(format!("failed to apply {}", &hunk.diff))?; + all_diffs.push_str(&hunk.diff); } + let patch = Patch::from_str(&all_diffs)?; + blob_contents = apply(&blob_contents, &patch) + .context(format!("failed to apply {}", &all_diffs))?; + // create a blob - let new_blob_oid = git_repository.blob(&blob_contents)?; + let new_blob_oid = git_repository.blob(blob_contents.as_bytes())?; // upsert into the builder builder.upsert(rel_path, new_blob_oid, filemode); } } else if is_submodule { - let mut blob_contents = vec![]; + let mut blob_contents = String::new(); let mut hunks = hunks.clone(); hunks.sort_by_key(|hunk| hunk.new_start); for hunk in hunks { - let patch = format!("--- original\n+++ modified\n{}", hunk.diff); - let patch_bytes = patch.as_bytes(); - let patch = Patch::from_bytes(patch_bytes)?; - blob_contents = apply_bytes(&blob_contents, &patch) + let patch = Patch::from_str(&hunk.diff)?; + blob_contents = apply(&blob_contents, &patch) .context(format!("failed to apply {}", &hunk.diff))?; } // create a blob - let new_blob_oid = git_repository.blob(&blob_contents)?; + let new_blob_oid = git_repository.blob(blob_contents.as_bytes())?; // upsert into the builder builder.upsert(rel_path, new_blob_oid, filemode); } else { @@ -3636,6 +3651,7 @@ pub fn move_commit( &project_repository.git_repository, &source_branch_head_parent_tree, &source_branch_head_tree, + context_lines(project_repository), )?; let is_source_locked = source_branch_non_comitted_files @@ -3836,6 +3852,7 @@ pub fn create_virtual_branch_from_branch( &project_repository.git_repository, &merge_base_tree, &head_commit_tree, + context_lines(project_repository), ) .context("failed to diff trees")?; @@ -3899,6 +3916,19 @@ pub fn create_virtual_branch_from_branch( } } +pub fn context_lines(project_repository: &project_repository::Repository) -> u32 { + let use_context = project_repository + .project() + .use_diff_context + .unwrap_or(false); + + if use_context { + 3_u32 + } else { + 0_u32 + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs b/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs index 8052ba3a8..23296f897 100644 --- a/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs +++ b/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs @@ -79,7 +79,7 @@ impl InnerHandler { .list_virtual_branches(project_id) .await { - Ok(branches) => Ok(vec![events::Event::Emit( + Ok((branches, _)) => Ok(vec![events::Event::Emit( app_events::Event::virtual_branches( project_id, &self.assets_proxy.proxy_virtual_branches(branches).await, diff --git a/gitbutler-app/tauri.conf.nightly.json b/gitbutler-app/tauri.conf.nightly.json index 9157b378a..c69356125 100644 --- a/gitbutler-app/tauri.conf.nightly.json +++ b/gitbutler-app/tauri.conf.nightly.json @@ -27,7 +27,7 @@ }, "updater": { "active": true, - "dialog": true, + "dialog": false, "endpoints": [ "https://app.gitbutler.com/releases/nightly/{{target}}-{{arch}}/{{current_version}}" ], diff --git a/gitbutler-app/tauri.conf.release.json b/gitbutler-app/tauri.conf.release.json index 20be3f635..a2723e0f0 100644 --- a/gitbutler-app/tauri.conf.release.json +++ b/gitbutler-app/tauri.conf.release.json @@ -27,7 +27,7 @@ }, "updater": { "active": true, - "dialog": true, + "dialog": false, "endpoints": [ "https://app.gitbutler.com/releases/release/{{target}}-{{arch}}/{{current_version}}" ], diff --git a/gitbutler-app/tests/virtual_branches.rs b/gitbutler-app/tests/virtual_branches.rs index 9219eb138..afe0bf7d1 100644 --- a/gitbutler-app/tests/virtual_branches.rs +++ b/gitbutler-app/tests/virtual_branches.rs @@ -92,7 +92,7 @@ mod unapply_ownership { controller .unapply_ownership( &project_id, - &"file.txt:1-2,10-11".parse::().unwrap(), + &"file.txt:1-5,7-11".parse::().unwrap(), ) .await .unwrap(); @@ -101,6 +101,7 @@ mod unapply_ownership { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -139,6 +140,7 @@ mod create_commit { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -161,6 +163,7 @@ mod create_commit { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -203,6 +206,7 @@ mod create_commit { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -224,12 +228,13 @@ mod create_commit { { // hunk before the commited part is not locked let mut changed_lines = lines.clone(); - changed_lines[0] = "updated line\nwith extra line".to_string(); + changed_lines[0] = "updated line".to_string(); fs::write(repository.path().join("file.txt"), changed_lines.join("\n")).unwrap(); let branch = controller .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -249,6 +254,7 @@ mod create_commit { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -268,13 +274,15 @@ mod create_commit { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); assert_eq!(branch.files.len(), 1); assert_eq!(branch.files[0].path.display().to_string(), "file.txt"); assert_eq!(branch.files[0].hunks.len(), 1); - assert!(!branch.files[0].hunks[0].locked); + // TODO: We lock this hunk, but can we afford not lock it? + assert!(branch.files[0].hunks[0].locked); // cleanup fs::write(repository.path().join("file.txt"), lines.clone().join("\n")).unwrap(); } @@ -287,13 +295,15 @@ mod create_commit { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); assert_eq!(branch.files.len(), 1); assert_eq!(branch.files[0].path.display().to_string(), "file.txt"); assert_eq!(branch.files[0].hunks.len(), 1); - assert!(!branch.files[0].hunks[0].locked); + // TODO: We lock this hunk, but can we afford not lock it? + assert!(branch.files[0].hunks[0].locked); // cleanup fs::write(repository.path().join("file.txt"), lines.clone().join("\n")).unwrap(); } @@ -325,7 +335,7 @@ mod references { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert_eq!(branches[0].name, "Virtual branch"); @@ -374,7 +384,7 @@ mod references { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 2); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].name, "name"); @@ -431,7 +441,7 @@ mod references { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert_eq!(branches[0].name, "new name"); @@ -492,7 +502,7 @@ mod references { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 2); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].name, "name"); @@ -548,7 +558,7 @@ mod references { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].name, "name"); @@ -640,7 +650,7 @@ mod references { branch2_id }; - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 2); // first branch is pushing to old ref remotely assert_eq!(branches[0].id, branch1_id); @@ -688,14 +698,14 @@ mod delete_virtual_branch { // write some std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); controller .delete_virtual_branch(&project_id, &branches[0].id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 0); assert!(!repository.path().join("file.txt").exists()); @@ -737,7 +747,7 @@ mod delete_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 0); let refnames = repository @@ -813,7 +823,7 @@ mod set_base_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert!(branches.is_empty()); repository.checkout_commit(oid_one); @@ -823,7 +833,7 @@ mod set_base_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(base_two, base); @@ -849,7 +859,7 @@ mod unapply { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); controller @@ -859,7 +869,7 @@ mod unapply { assert!(!repository.path().join("file.txt").exists()); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(!branches[0].active); } @@ -893,11 +903,11 @@ mod unapply { std::fs::write(repository.path().join("file.txt"), "conflict").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].base_current); assert!(branches[0].active); - assert_eq!(branches[0].files[0].hunks[0].diff, "@@ -1,1 +1,1 @@\n-first\n\\ No newline at end of file\n+conflict\n\\ No newline at end of file\n"); + assert_eq!(branches[0].files[0].hunks[0].diff, "@@ -1 +1 @@\n-first\n\\ No newline at end of file\n+conflict\n\\ No newline at end of file\n"); controller .unapply_virtual_branch(&project_id, &branches[0].id) @@ -920,6 +930,7 @@ mod unapply { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|branch| branch.id == branch_id) .unwrap(); @@ -943,12 +954,13 @@ mod unapply { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); assert!(branch.base_current); assert!(branch.conflicted); - assert_eq!(branch.files[0].hunks[0].diff, "@@ -1,1 +1,5 @@\n-first\n\\ No newline at end of file\n+<<<<<<< ours\n+conflict\n+=======\n+second\n+>>>>>>> theirs\n"); + assert_eq!(branch.files[0].hunks[0].diff, "@@ -1 +1,5 @@\n-first\n\\ No newline at end of file\n+<<<<<<< ours\n+conflict\n+=======\n+second\n+>>>>>>> theirs\n"); } { @@ -966,13 +978,14 @@ mod unapply { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); assert!(!branch.active); assert!(!branch.base_current); assert!(!branch.conflicted); - assert_eq!(branch.files[0].hunks[0].diff, "@@ -1,1 +1,1 @@\n-first\n\\ No newline at end of file\n+conflict\n\\ No newline at end of file\n"); + assert_eq!(branch.files[0].hunks[0].diff, "@@ -1 +1 @@\n-first\n\\ No newline at end of file\n+conflict\n\\ No newline at end of file\n"); } } @@ -994,7 +1007,7 @@ mod unapply { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); controller @@ -1002,7 +1015,7 @@ mod unapply { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 0); } } @@ -1105,7 +1118,7 @@ mod apply_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert!(branches[0].active); @@ -1131,7 +1144,7 @@ mod apply_virtual_branch { "one" ); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].files.len(), 0); @@ -1144,7 +1157,7 @@ mod apply_virtual_branch { controller.update_base_branch(&project_id).await.unwrap(); // branch is stil unapplied - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].files.len(), 0); @@ -1170,7 +1183,7 @@ mod apply_virtual_branch { .unwrap(); // it should be rebased - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].files.len(), 0); @@ -1221,7 +1234,7 @@ mod apply_virtual_branch { .unwrap(); fs::write(repository.path().join("another_file.txt"), "").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert!(branches[0].active); @@ -1238,7 +1251,7 @@ mod apply_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].files.len(), 1); @@ -1254,7 +1267,7 @@ mod apply_virtual_branch { controller.update_base_branch(&project_id).await.unwrap(); // first branch is stil unapplied - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].files.len(), 1); @@ -1274,7 +1287,7 @@ mod apply_virtual_branch { .unwrap(); // workdir should be rebased, and work should be restored - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].files.len(), 1); @@ -1320,7 +1333,7 @@ async fn resolve_conflict_flow() { .unwrap(); fs::write(repository.path().join("file.txt"), "conflict").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert!(branches[0].active); @@ -1333,7 +1346,7 @@ async fn resolve_conflict_flow() { controller.update_base_branch(&project_id).await.unwrap(); // there is a conflict now, so the branch should be inactive - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert!(!branches[0].active); @@ -1346,7 +1359,7 @@ async fn resolve_conflict_flow() { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert!(branches[0].active); @@ -1380,7 +1393,7 @@ async fn resolve_conflict_flow() { let commit = repository.find_commit(commit_oid).unwrap(); assert_eq!(commit.parent_count(), 2); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert!(branches[0].active); @@ -1483,7 +1496,7 @@ mod update_base_branch { // branch should not be changed. - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -1502,7 +1515,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -1569,7 +1582,7 @@ mod update_base_branch { // should not change the branch. - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -1588,7 +1601,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -1660,7 +1673,7 @@ mod update_base_branch { // should not change the branch. - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -1679,7 +1692,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -1748,7 +1761,7 @@ mod update_base_branch { // should rebase upstream, and leave uncommited file as is - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -1767,7 +1780,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -1836,7 +1849,7 @@ mod update_base_branch { // should not touch the branch - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -1855,7 +1868,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -1930,7 +1943,7 @@ mod update_base_branch { // should update branch base - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -1950,7 +1963,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2012,6 +2025,7 @@ mod update_base_branch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -2033,7 +2047,7 @@ mod update_base_branch { // should remove integrated commit, but leave work - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -2053,7 +2067,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2122,7 +2136,7 @@ mod update_base_branch { // should remove identical branch - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 0); } } @@ -2176,8 +2190,12 @@ mod update_base_branch { { // merge pr - let branch = - controller.list_virtual_branches(&project_id).await.unwrap()[0].clone(); + let branch = controller + .list_virtual_branches(&project_id) + .await + .unwrap() + .0[0] + .clone(); repository.merge(&branch.upstream.as_ref().unwrap().name); repository.fetch(); } @@ -2187,7 +2205,7 @@ mod update_base_branch { controller.update_base_branch(&project_id).await.unwrap(); // just removes integrated branch - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 0); } } @@ -2238,7 +2256,7 @@ mod update_base_branch { // should stash conflicing branch - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -2257,7 +2275,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2319,7 +2337,7 @@ mod update_base_branch { // should stash the branch. - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -2338,7 +2356,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2405,7 +2423,7 @@ mod update_base_branch { // should stash the branch. - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -2424,7 +2442,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2488,7 +2506,7 @@ mod update_base_branch { // should rebase upstream, and leave uncommited file as is - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -2507,7 +2525,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2571,7 +2589,7 @@ mod update_base_branch { // should merge upstream, and leave uncommited file as is. - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -2590,7 +2608,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2671,7 +2689,8 @@ mod update_base_branch { // rebases branch, since the branch is pushed and force pushing is // allowed - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = + controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2750,7 +2769,8 @@ mod update_base_branch { // creates a merge commit, since the branch is pushed - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = + controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2818,7 +2838,7 @@ mod update_base_branch { // just rebases branch - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2836,7 +2856,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2899,6 +2919,7 @@ mod update_base_branch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -2918,7 +2939,7 @@ mod update_base_branch { // should remove integrated commit, but leave non integrated work as is - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -2937,7 +2958,7 @@ mod update_base_branch { .apply_virtual_branch(&project_id, &branch_id) .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -3024,8 +3045,12 @@ mod update_base_branch { { // merge branch remotely - let branch = - controller.list_virtual_branches(&project_id).await.unwrap()[0].clone(); + let branch = controller + .list_virtual_branches(&project_id) + .await + .unwrap() + .0[0] + .clone(); repository.merge(&branch.upstream.as_ref().unwrap().name); } @@ -3036,7 +3061,7 @@ mod update_base_branch { // removes integrated commit, leaves non commited work as is - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(!branches[0].active); @@ -3050,7 +3075,7 @@ mod update_base_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].active); assert!(branches[0].conflicted); @@ -3112,8 +3137,12 @@ mod update_base_branch { { // push and merge branch remotely - let branch = - controller.list_virtual_branches(&project_id).await.unwrap()[0].clone(); + let branch = controller + .list_virtual_branches(&project_id) + .await + .unwrap() + .0[0] + .clone(); repository.merge(&branch.upstream.as_ref().unwrap().name); } @@ -3124,7 +3153,7 @@ mod update_base_branch { // removes integrated commit, leaves non commited work as is - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -3139,7 +3168,7 @@ mod update_base_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].active); assert!(!branches[0].conflicted); @@ -3190,8 +3219,12 @@ mod update_base_branch { { // push and merge branch remotely - let branch = - controller.list_virtual_branches(&project_id).await.unwrap()[0].clone(); + let branch = controller + .list_virtual_branches(&project_id) + .await + .unwrap() + .0[0] + .clone(); repository.merge(&branch.upstream.as_ref().unwrap().name); } @@ -3202,7 +3235,7 @@ mod update_base_branch { // removes integrated commit, leaves non commited work as is - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -3217,7 +3250,7 @@ mod update_base_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].active); assert!(!branches[0].conflicted); @@ -3272,7 +3305,7 @@ mod update_base_branch { // just removes integrated branch - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 0); } } @@ -3321,8 +3354,12 @@ mod update_base_branch { { // merge pr - let branch = - controller.list_virtual_branches(&project_id).await.unwrap()[0].clone(); + let branch = controller + .list_virtual_branches(&project_id) + .await + .unwrap() + .0[0] + .clone(); repository.merge(&branch.upstream.as_ref().unwrap().name); repository.fetch(); } @@ -3332,7 +3369,7 @@ mod update_base_branch { controller.update_base_branch(&project_id).await.unwrap(); // just removes integrated branch - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 0); } } @@ -3372,7 +3409,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 1); @@ -3393,7 +3430,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 1); @@ -3434,7 +3471,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 1); @@ -3453,7 +3490,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 0); @@ -3494,7 +3531,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 1); @@ -3517,7 +3554,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 2); @@ -3537,7 +3574,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 1); @@ -3578,7 +3615,7 @@ mod reset_virtual_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 1); @@ -3664,7 +3701,7 @@ mod upstream { { // should correctly detect pushed commits - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 3); @@ -3726,6 +3763,7 @@ mod upstream { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch1_id) .unwrap(); @@ -3744,7 +3782,7 @@ mod upstream { { // should correctly detect pushed commits - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch1_id); assert_eq!(branches[0].commits.len(), 3); @@ -3827,7 +3865,7 @@ mod cherry_pick { "content two" ); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -3900,7 +3938,7 @@ mod cherry_pick { .unwrap(); assert!(cherry_picked_commit_oid.is_some()); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert!(repository.path().join("file_two.txt").exists()); assert_eq!( fs::read_to_string(repository.path().join("file_two.txt")).unwrap(), @@ -4061,7 +4099,7 @@ mod cherry_pick { "<<<<<<< ours\nconflict\n=======\ncontent three\n>>>>>>> theirs\n" ); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -4082,7 +4120,7 @@ mod cherry_pick { let commit = repository.find_commit(commited_oid).unwrap(); assert_eq!(commit.parent_count(), 2); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert!(branches[0].active); @@ -4240,6 +4278,7 @@ mod amend { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4337,6 +4376,7 @@ mod amend { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4358,6 +4398,7 @@ mod amend { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4398,6 +4439,7 @@ mod amend { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4423,6 +4465,7 @@ mod amend { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4468,6 +4511,7 @@ mod amend { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4517,6 +4561,7 @@ mod init { .list_virtual_branches(&project.id) .await .unwrap() + .0 .is_empty()); projects.delete(&project.id).await.unwrap(); controller @@ -4537,6 +4582,7 @@ mod init { .list_virtual_branches(&project.id) .await .unwrap() + .0 .is_empty()); } } @@ -4561,7 +4607,7 @@ mod init { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].files.len(), 1); assert_eq!(branches[0].files[0].hunks.len(), 1); @@ -4587,7 +4633,7 @@ mod init { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].files.len(), 1); assert_eq!(branches[0].files[0].hunks.len(), 1); @@ -4613,7 +4659,7 @@ mod init { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].files.is_empty()); assert_eq!(branches[0].commits.len(), 1); @@ -4640,7 +4686,7 @@ mod init { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].files.is_empty()); assert_eq!(branches[0].commits.len(), 1); @@ -4665,7 +4711,7 @@ mod init { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].files.is_empty()); assert_eq!(branches[0].commits.len(), 1); @@ -4695,7 +4741,7 @@ mod init { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].files.len(), 1); assert_eq!(branches[0].files[0].hunks.len(), 1); @@ -4765,6 +4811,7 @@ mod squash { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4840,6 +4887,7 @@ mod squash { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -4930,6 +4978,7 @@ mod squash { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -5118,6 +5167,7 @@ mod update_commit_message { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -5191,6 +5241,7 @@ mod update_commit_message { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -5262,6 +5313,7 @@ mod update_commit_message { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -5388,6 +5440,7 @@ mod update_commit_message { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == branch_id) .unwrap(); @@ -5480,6 +5533,7 @@ mod create_virtual_branch_from_branch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|branch| branch.id == branch_id) .unwrap(); @@ -5530,6 +5584,7 @@ mod create_virtual_branch_from_branch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|branch| branch.id == branch_id) .unwrap(); @@ -5550,6 +5605,7 @@ mod create_virtual_branch_from_branch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|branch| branch.id == branch_id) .unwrap(); @@ -5585,7 +5641,7 @@ mod create_virtual_branch_from_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert!(branches.is_empty()); let branch_id = controller @@ -5596,7 +5652,7 @@ mod create_virtual_branch_from_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert_eq!(branches[0].commits.len(), 1); @@ -5631,7 +5687,7 @@ mod create_virtual_branch_from_branch { { std::fs::write(repository.path().join("file.txt"), "conflict").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); }; @@ -5648,6 +5704,7 @@ mod create_virtual_branch_from_branch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|branch| branch.id == new_branch_id) .unwrap(); @@ -5684,7 +5741,7 @@ mod create_virtual_branch_from_branch { { std::fs::write(repository.path().join("file.txt"), "conflict").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); controller @@ -5706,6 +5763,7 @@ mod create_virtual_branch_from_branch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|branch| branch.id == new_branch_id) .unwrap(); @@ -5809,7 +5867,7 @@ mod create_virtual_branch_from_branch { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, branch_id); assert_eq!(branches[0].commits.len(), 1); @@ -5849,7 +5907,7 @@ mod selected_for_changes { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); let b = branches.iter().find(|b| b.id == b_id).unwrap(); @@ -5863,7 +5921,7 @@ mod selected_for_changes { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 2); assert_eq!(branches[0].id, b.id); @@ -5899,7 +5957,7 @@ mod selected_for_changes { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); let b = branches.iter().find(|b| b.id == b_id).unwrap(); @@ -5913,7 +5971,7 @@ mod selected_for_changes { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert_eq!(branches[0].id, b2.id); @@ -5942,6 +6000,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b_id) .unwrap(); @@ -5956,6 +6015,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b_id) .unwrap(); @@ -5976,6 +6036,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b_id) .unwrap(); @@ -5996,6 +6057,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b_id) .unwrap(); @@ -6023,6 +6085,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b1_id) .unwrap(); @@ -6036,6 +6099,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b2_id) .unwrap(); @@ -6057,6 +6121,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b1_id) .unwrap(); @@ -6066,6 +6131,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b2_id) .unwrap(); @@ -6096,6 +6162,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b1_id) .unwrap(); @@ -6110,6 +6177,7 @@ mod selected_for_changes { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == b1_id) .unwrap(); @@ -6132,7 +6200,7 @@ mod selected_for_changes { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches[0].files.len(), 1); controller @@ -6146,7 +6214,7 @@ mod selected_for_changes { .await .unwrap(); std::fs::write(repository.path().join("another_file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches[0].files.len(), 1); assert_eq!(branches[1].files.len(), 1); } @@ -6167,7 +6235,7 @@ mod selected_for_changes { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); controller @@ -6179,7 +6247,7 @@ mod selected_for_changes { .await .unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); assert!(branches[0].active); assert!(branches[0].selected_for_changes); @@ -6207,7 +6275,7 @@ mod move_commit_to_vbranch { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); let source_branch_id = branches[0].id; @@ -6231,6 +6299,7 @@ mod move_commit_to_vbranch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == target_branch_id) .unwrap(); @@ -6239,6 +6308,7 @@ mod move_commit_to_vbranch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == source_branch_id) .unwrap(); @@ -6265,7 +6335,7 @@ mod move_commit_to_vbranch { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); let source_branch_id = branches[0].id; @@ -6295,6 +6365,7 @@ mod move_commit_to_vbranch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == target_branch_id) .unwrap(); @@ -6303,6 +6374,7 @@ mod move_commit_to_vbranch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == source_branch_id) .unwrap(); @@ -6329,7 +6401,7 @@ mod move_commit_to_vbranch { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); let source_branch_id = branches[0].id; @@ -6365,6 +6437,7 @@ mod move_commit_to_vbranch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == target_branch_id) .unwrap(); @@ -6373,6 +6446,7 @@ mod move_commit_to_vbranch { .list_virtual_branches(&project_id) .await .unwrap() + .0 .into_iter() .find(|b| b.id == source_branch_id) .unwrap(); @@ -6399,7 +6473,7 @@ mod move_commit_to_vbranch { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); let source_branch_id = branches[0].id; @@ -6441,7 +6515,7 @@ mod move_commit_to_vbranch { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); let source_branch_id = branches[0].id; @@ -6485,7 +6559,7 @@ mod move_commit_to_vbranch { std::fs::write(repository.path().join("file.txt"), "content").unwrap(); - let branches = controller.list_virtual_branches(&project_id).await.unwrap(); + let (branches, _) = controller.list_virtual_branches(&project_id).await.unwrap(); assert_eq!(branches.len(), 1); let source_branch_id = branches[0].id; diff --git a/gitbutler-ui/src/lib/backend/projects.ts b/gitbutler-ui/src/lib/backend/projects.ts index 07823827e..2afbdfeb1 100644 --- a/gitbutler-ui/src/lib/backend/projects.ts +++ b/gitbutler-ui/src/lib/backend/projects.ts @@ -33,6 +33,7 @@ export type Project = { preferred_key: Key; ok_with_force_push: boolean; omit_certificate_check: boolean | undefined; + use_diff_context: boolean | undefined; }; export class ProjectService { diff --git a/gitbutler-ui/src/lib/backend/updater.ts b/gitbutler-ui/src/lib/backend/updater.ts new file mode 100644 index 000000000..4e597904e --- /dev/null +++ b/gitbutler-ui/src/lib/backend/updater.ts @@ -0,0 +1,122 @@ +import { showToast } from '$lib/notifications/toasts'; +import { + checkUpdate, + installUpdate, + onUpdaterEvent, + type UpdateResult, + type UpdateStatus +} from '@tauri-apps/api/updater'; +import posthog from 'posthog-js'; +import { + BehaviorSubject, + switchMap, + Observable, + from, + map, + shareReplay, + interval, + timeout, + catchError, + of, + startWith, + combineLatestWith, + tap +} from 'rxjs'; + +// TOOD: Investigate why 'DOWNLOADED' is not in the type provided by Tauri. +export type Update = + | { version?: string; status?: UpdateStatus | 'DOWNLOADED'; body?: string } + | undefined; + +export class UpdaterService { + private reload$ = new BehaviorSubject(undefined); + private status$ = new BehaviorSubject(undefined); + + /** + * Example output: + * {version: "0.5.303", date: "2024-02-25 3:09:58.0 +00:00:00", body: "", status: "DOWNLOADED"} + */ + update$: Observable; + + // We don't ever call this because the class is meant to be used as a singleton + unlistenFn: any; + + constructor() { + onUpdaterEvent((status) => { + const err = status.error; + if (err) showErrorToast(err); + this.status$.next(status.status); + }).then((unlistenFn) => (this.unlistenFn = unlistenFn)); + + this.update$ = this.reload$.pipe( + // Now and then every hour indefinitely + switchMap(() => interval(60 * 60 * 1000).pipe(startWith(0))), + tap(() => this.status$.next(undefined)), + // Timeout needed to prevent hanging in dev mode + switchMap(() => from(checkUpdate()).pipe(timeout(10000))), + // The property `shouldUpdate` seems useless, only indicates presence of manifest + map((update: UpdateResult | undefined) => { + if (update?.shouldUpdate) return update.manifest; + }), + // Hide offline/timeout errors since no app ever notifies you about this + catchError((err) => { + if (!isOffline(err) && !isTimeoutError(err)) { + posthog.capture('Updater Check Error', err); + showErrorToast(err); + console.log(err); + } + return of(undefined); + }), + // Status is irrelevant without a proposed update so we merge the streams + combineLatestWith(this.status$), + map(([update, status]) => { + if (update) return { ...update, status }; + return undefined; + }), + shareReplay(1) + ); + // Use this for testing component manually (until we have actual tests) + // this.update$ = new BehaviorSubject({ + // version: '0.5.303', + // date: '2024-02-25 3:09:58.0 +00:00:00', + // body: '- Improves the performance of virtual branch operations (quicker and lower CPU usage)\n- Large numbers of hunks for a file will only be rendered in the UI after confirmation' + // }); + } + + async install() { + try { + await installUpdate(); + posthog.capture('App Update Successful'); + } catch (e: any) { + // We expect toast to be shown by error handling in `onUpdaterEvent` + posthog.capture('App Update Failed', e); + } + } +} + +function isOffline(err: any): boolean { + return typeof err == 'string' && err.includes('Could not fetch a valid release'); +} + +function isTimeoutError(err: any): boolean { + return err?.name == 'TimeoutError'; +} + +function showErrorToast(err: any) { + if (isOffline(err)) return; + showToast({ + title: 'App update failed', + message: ` + Something went wrong while updating the app. + + You can download the latest release from our + [downloads](https://app.gitbutler.com/downloads) page. + + \`\`\` + ${err} + \`\`\` + `, + style: 'error' + }); + posthog.capture('Updater Status Error', err); +} diff --git a/gitbutler-ui/src/lib/branches/service.ts b/gitbutler-ui/src/lib/branches/service.ts index d16d29b88..53b11ac86 100644 --- a/gitbutler-ui/src/lib/branches/service.ts +++ b/gitbutler-ui/src/lib/branches/service.ts @@ -5,6 +5,7 @@ import { startWith, switchMap } from 'rxjs/operators'; import type { GitHubService } from '$lib/github/service'; import type { PullRequest } from '$lib/github/types'; import type { RemoteBranchService } from '$lib/stores/remoteBranches'; +import type { BranchController } from '$lib/vbranches/branchController'; import type { VirtualBranchService } from '$lib/vbranches/branchStoresCache'; import type { Branch, RemoteBranch } from '$lib/vbranches/types'; @@ -14,7 +15,8 @@ export class BranchService { constructor( private vbranchService: VirtualBranchService, remoteBranchService: RemoteBranchService, - private githubService: GitHubService + private githubService: GitHubService, + private branchController: BranchController ) { const vbranchesWithEmpty$ = vbranchService.branches$.pipe(startWith([])); const branchesWithEmpty$ = remoteBranchService.branches$.pipe(startWith([])); @@ -47,7 +49,7 @@ export class BranchService { // Push if local commits if (branch.commits.some((c) => !c.isRemote)) { - newBranch = await this.vbranchService.pushBranch(branch.id, branch.requiresForce); + newBranch = await this.branchController.pushBranch(branch.id, branch.requiresForce); } else { newBranch = branch; } diff --git a/gitbutler-ui/src/lib/components/AccountLink.svelte b/gitbutler-ui/src/lib/components/AccountLink.svelte index 3ac85c953..ea2af07cb 100644 --- a/gitbutler-ui/src/lib/components/AccountLink.svelte +++ b/gitbutler-ui/src/lib/components/AccountLink.svelte @@ -49,6 +49,8 @@ color var(--transition-fast), filter var(--transition-fast); + cursor: pointer; + &.pop { color: var(--clr-theme-scale-pop-10); background: color-mix( diff --git a/gitbutler-ui/src/lib/components/Board.svelte b/gitbutler-ui/src/lib/components/Board.svelte index 9d899d1f5..9dbd2ec06 100644 --- a/gitbutler-ui/src/lib/components/Board.svelte +++ b/gitbutler-ui/src/lib/components/Board.svelte @@ -1,4 +1,5 @@