diff options
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/api/worktrees.rs | 75 | ||||
| -rw-r--r-- | src/app/api/worktrees/deferred.rs | 23 | ||||
| -rw-r--r-- | src/app/worktrees.rs | 50 |
3 files changed, 111 insertions, 37 deletions
diff --git a/src/app/api/worktrees.rs b/src/app/api/worktrees.rs index 62a46fdb..111d50cf 100644 --- a/src/app/api/worktrees.rs +++ b/src/app/api/worktrees.rs @@ -1038,12 +1038,77 @@ mod tests { let _ = std::fs::remove_dir_all(plugin_root); } + #[tokio::test] + async fn deferred_api_worktree_create_checks_out_existing_branch() { + let repo = create_committed_repo("api-worktree-create-existing-branch-repo"); + let worktree_root = unique_temp_path("api-worktree-create-existing-branch-root"); + let branch = "foo"; + run_git(&repo, &["branch", branch]); + let mut app = test_app(); + let mut parent = Workspace::test_new("main"); + parent.identity_cwd = repo.clone(); + let parent_id = parent.id.clone(); + app.state.workspaces = vec![parent]; + app.state.ensure_test_terminals(); + app.state.worktree_directory = worktree_root.clone(); + let request = || Request { + id: "req".into(), + method: crate::api::schema::Method::WorktreeCreate(WorktreeCreateParams { + workspace_id: Some(parent_id.clone()), + branch: Some(branch.into()), + ..WorktreeCreateParams::default() + }), + }; + + let (response_tx, response_rx) = response_channel(); + assert!(app.handle_deferred_worktree_api_request(request(), response_tx)); + let event = wait_for_app_event(&mut app); + app.handle_internal_event(event); + let response = response_rx + .recv_timeout(std::time::Duration::from_secs(2)) + .expect("create should respond"); + let success: SuccessResponse = serde_json::from_str(&response).unwrap(); + let ResponseResult::WorktreeCreated { worktree, .. } = success.result else { + panic!("expected worktree_created response"); + }; + assert_eq!(worktree.branch.as_deref(), Some(branch)); + let checkout = Path::new(&worktree.path); + assert!(checkout.join("README.md").exists()); + let branch_name = std::process::Command::new("git") + .arg("-C") + .arg(checkout) + .args(["branch", "--show-current"]) + .output() + .unwrap(); + assert!(branch_name.status.success()); + assert_eq!( + String::from_utf8(branch_name.stdout).unwrap().trim(), + branch + ); + assert!(app.pending_api_worktree_creates.is_empty()); + + for (_, runtime) in app.terminal_runtimes.drain() { + runtime.shutdown(); + } + let _ = std::fs::remove_dir_all(worktree_root); + let _ = std::fs::remove_dir_all(repo); + } + #[test] fn deferred_api_worktree_create_failure_clears_pending_checkout() { let repo = create_committed_repo("api-worktree-create-failure-repo"); let worktree_root = unique_temp_path("api-worktree-create-failure-root"); - let branch = "foo"; - run_git(&repo, &["branch", branch]); + let branch_name = std::process::Command::new("git") + .arg("-C") + .arg(&repo) + .args(["branch", "--show-current"]) + .output() + .unwrap(); + assert!(branch_name.status.success()); + let branch = String::from_utf8(branch_name.stdout) + .unwrap() + .trim() + .to_string(); let mut app = test_app(); let mut parent = Workspace::test_new("main"); parent.identity_cwd = repo.clone(); @@ -1055,7 +1120,7 @@ mod tests { id: "req".into(), method: crate::api::schema::Method::WorktreeCreate(WorktreeCreateParams { workspace_id: Some(parent_id.clone()), - branch: Some(branch.into()), + branch: Some(branch.clone()), ..WorktreeCreateParams::default() }), }; @@ -1069,10 +1134,6 @@ mod tests { .expect("failed create should respond"); let error: ErrorResponse = serde_json::from_str(&response).unwrap(); assert_eq!(error.error.code, "worktree_create_failed"); - assert!(error - .error - .message - .contains("fatal: a branch named 'foo' already exists")); assert!(app.pending_api_worktree_creates.is_empty()); let (second_tx, second_rx) = response_channel(); diff --git a/src/app/api/worktrees/deferred.rs b/src/app/api/worktrees/deferred.rs index 19794a6e..f63a47fd 100644 --- a/src/app/api/worktrees/deferred.rs +++ b/src/app/api/worktrees/deferred.rs @@ -159,12 +159,6 @@ impl App { self.pending_api_worktree_creates .insert(checkout_key.clone(), operation_id); - let command = crate::worktree::build_worktree_add_new_branch_command( - &source.source_checkout_path, - &checkout_path, - &branch, - &base, - ); let parent_dir = checkout_path.parent().map(Path::to_path_buf); let source_workspace_id = source .workspace_idx @@ -191,15 +185,22 @@ impl App { respond_to, }; let path = checkout_path; + let source_checkout_path = api_request.source_checkout_path.clone(); let event_tx = self.event_tx.clone(); std::thread::spawn(move || { let result = if let Some(parent_dir) = parent_dir { - std::fs::create_dir_all(&parent_dir) - .map_err(|err| err.to_string()) - .and_then(|()| crate::worktree::run_worktree_command(&command)) + std::fs::create_dir_all(&parent_dir).map_err(|err| err.to_string()) } else { - crate::worktree::run_worktree_command(&command) - }; + Ok(()) + } + .and_then(|()| { + crate::worktree::run_worktree_add_command( + &source_checkout_path, + &path, + &branch, + &base, + ) + }); let _ = event_tx.blocking_send(AppEvent::WorktreeAddFinished(Box::new( crate::events::WorktreeAddResult { path, diff --git a/src/app/worktrees.rs b/src/app/worktrees.rs index e1c30a77..12e7ae84 100644 --- a/src/app/worktrees.rs +++ b/src/app/worktrees.rs @@ -521,12 +521,6 @@ impl App { create.creating = true; create.error = None; - let command = crate::worktree::build_worktree_add_new_branch_command( - &create.source_checkout_path, - &create.checkout_path, - &create.branch, - "HEAD", - ); let parent_dir = create .checkout_path .parent() @@ -538,15 +532,23 @@ impl App { "starting git worktree add" ); let path = create.checkout_path.clone(); + let source_checkout_path = create.source_checkout_path.clone(); + let branch = create.branch.clone(); let event_tx = self.event_tx.clone(); std::thread::spawn(move || { let result = if let Some(parent_dir) = parent_dir { - std::fs::create_dir_all(&parent_dir) - .map_err(|err| err.to_string()) - .and_then(|()| crate::worktree::run_worktree_command(&command)) + std::fs::create_dir_all(&parent_dir).map_err(|err| err.to_string()) } else { - crate::worktree::run_worktree_command(&command) - }; + Ok(()) + } + .and_then(|()| { + crate::worktree::run_worktree_add_command( + &source_checkout_path, + &path, + &branch, + "HEAD", + ) + }); let _ = event_tx.blocking_send(AppEvent::WorktreeAddFinished(Box::new( WorktreeAddResult { path, @@ -1632,7 +1634,7 @@ mod tests { } #[test] - fn start_worktree_add_existing_branch_clears_creating_and_shows_fatal_error() { + fn start_worktree_add_existing_branch_checks_out_branch() { let repo = create_committed_repo("app-worktree-add-existing-branch-repo"); let worktree_root = unique_temp_path("app-worktree-add-existing-branch-root"); let branch = "foo"; @@ -1664,18 +1666,28 @@ mod tests { let event = wait_for_worktree_event(&mut app); match event { AppEvent::WorktreeAddFinished(result) => { - app.handle_worktree_add_finished(*result); + let result = *result; + assert_eq!(result.path, checkout); + assert_eq!(result.result, Ok(())); } other => panic!("unexpected event: {other:?}"), } - let create = app.state.worktree_create.as_ref().unwrap(); - assert!(!create.creating); - let error = create.error.as_deref().unwrap(); - assert!(error.contains("Preparing worktree")); - assert!(error.contains("fatal: a branch named 'foo' already exists")); - assert!(!checkout.exists()); + assert!(checkout.join("README.md").exists()); + let branch_name = std::process::Command::new("git") + .arg("-C") + .arg(&checkout) + .args(["branch", "--show-current"]) + .output() + .unwrap(); + assert!(branch_name.status.success()); + assert_eq!( + String::from_utf8(branch_name.stdout).unwrap().trim(), + branch + ); + let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false); + crate::worktree::run_worktree_command(&remove).unwrap(); let _ = std::fs::remove_dir_all(worktree_root); let _ = std::fs::remove_dir_all(repo); } |
