use thor_core::{find_repo, list_worktrees, remove_worktree};
use std::path::PathBuf;
use std::process::Command;
pub struct DoneOpts {
pub no_push: bool,
pub pr: bool,
}
pub enum DoneResult {
Merged { target_path: PathBuf },
PrCreated { url: String, target_path: PathBuf },
}
pub async fn done(target: &str, opts: &DoneOpts) -> anyhow::Result<DoneResult> {
let repo = find_repo()?;
let worktrees = list_worktrees(&repo).await?;
let cwd = std::env::current_dir()?;
let current_wt = worktrees.iter()
.find(|wt| cwd.starts_with(&wt.path))
.ok_or_else(|| anyhow::anyhow!("Not in a worktree"))?;
let current_branch = current_wt.branch.as_ref()
.ok_or_else(|| anyhow::anyhow!("Current worktree has no branch (detached HEAD)"))?
.clone();
if current_branch == target {
anyhow::bail!("Already on target branch '{}'", target);
}
let target_wt = worktrees.iter()
.find(|wt| wt.branch.as_deref() == Some(target))
.ok_or_else(|| anyhow::anyhow!("Target worktree '{}' not found", target))?;
let target_path = target_wt.path.clone();
if opts.pr {
let push = Command::new("git")
.args(["push", "-u", "origin", ¤t_branch])
.current_dir(&cwd)
.status()?;
if !push.success() {
anyhow::bail!("Failed to push branch '{}'", current_branch);
}
let gh_check = Command::new("gh")
.arg("--version")
.output();
if gh_check.is_err() || !gh_check.unwrap().status.success() {
anyhow::bail!("'gh' CLI not found. Install it: https://cli.github.com/");
}
let pr_output = Command::new("gh")
.args(["pr", "create", "--fill", "--base", target])
.current_dir(&cwd)
.output()?;
if !pr_output.status.success() {
let stderr = String::from_utf8_lossy(&pr_output.stderr);
anyhow::bail!("Failed to create PR: {}", stderr.trim());
}
let url = String::from_utf8_lossy(&pr_output.stdout).trim().to_string();
let _ = Command::new("git")
.args(["worktree", "remove", &cwd.display().to_string()])
.current_dir(&target_path)
.status();
Ok(DoneResult::PrCreated { url, target_path })
} else {
if target_wt.ahead > 0 || target_wt.behind > 0 || target_wt.has_upstream() {
let _ = Command::new("git")
.args(["pull", "--rebase"])
.current_dir(&target_path)
.status();
}
let merge_msg = format!("Merge branch '{}' into {}", current_branch, target);
let merge = Command::new("git")
.args(["merge", "--no-ff", ¤t_branch, "-m", &merge_msg])
.current_dir(&target_path)
.status()?;
if !merge.success() {
anyhow::bail!("Merge conflict. Resolve in {} and retry.", target_path.display());
}
if !opts.no_push {
let _ = Command::new("git")
.args(["push"])
.current_dir(&target_path)
.status();
}
let _ = remove_worktree(&repo, ¤t_branch, true).await;
Ok(DoneResult::Merged { target_path })
}
}