1use anyhow::Result;
2use std::path::PathBuf;
3
4use crate::git::{
5 bare_clone, branch_exists_local, branch_exists_remote, create_local_worktree, create_worktree,
6 detect_default_branch, git_fetch,
7};
8use crate::issue::IssueRef;
9
10pub struct Workspace {
11 pub path: PathBuf,
12 pub issue: IssueRef,
13 pub created: bool,
15}
16
17impl Workspace {
18 pub fn open_or_create(issue: IssueRef) -> Result<Self> {
20 let worktree_path = issue.temp_path();
21 let bare_path = issue.bare_clone_path();
22
23 if worktree_path.exists() {
25 return Ok(Self {
26 path: worktree_path,
27 issue,
28 created: false,
29 });
30 }
31
32 match &issue {
34 IssueRef::Local { project_path, .. } => {
35 eprintln!("Creating local worktree at {}…", worktree_path.display());
37 let branch = issue.branch_name();
38 let branch_exists = branch_exists_local(project_path, &branch);
39 std::fs::create_dir_all(worktree_path.parent().unwrap_or(&worktree_path))?;
40 create_local_worktree(project_path, &worktree_path, &branch, branch_exists)?;
41 }
42 _ => {
43 if !bare_path.exists() {
44 eprintln!(
45 "Cloning {} (bare) into {}…",
46 issue.clone_url(),
47 bare_path.display()
48 );
49 bare_clone(&issue.clone_url(), &bare_path)?;
50 } else {
51 eprintln!("Fetching origin…");
52 git_fetch(&bare_path)?;
53 }
54
55 let base_branch = detect_default_branch(&bare_path)?;
56 eprintln!("Default branch: {base_branch}");
57
58 let branch = issue.branch_name();
59 let branch_exists = branch_exists_remote(&bare_path, &branch);
60
61 eprintln!(
62 "Creating worktree {} at {}…",
63 branch,
64 worktree_path.display()
65 );
66 create_worktree(
67 &bare_path,
68 &worktree_path,
69 &branch,
70 &base_branch,
71 branch_exists,
72 )?;
73 }
74 }
75
76 Ok(Self {
77 path: worktree_path,
78 issue,
79 created: true,
80 })
81 }
83}
84
85#[cfg(test)]
86#[path = "workspace_tests.rs"]
87mod workspace_tests;