use std::path::PathBuf;
use crate::error::Result;
use crate::git::{self, CommitInfo};
use crate::output::{CYAN, GRAY, GREEN, RESET, YELLOW};
use crate::spec::Spec;
use crate::state::StateManager;
#[derive(Debug, Clone)]
pub struct BranchContext {
pub branch_name: String,
pub spec: Option<Spec>,
pub spec_path: Option<PathBuf>,
pub commits: Vec<CommitInfo>,
}
#[derive(Debug, Clone)]
pub enum BranchContextResult {
SuccessWithSpec(BranchContext),
SuccessNoSpec(BranchContext),
Error(String),
}
pub fn gather_branch_context(show_warning: bool) -> BranchContextResult {
let branch_name = match git::current_branch() {
Ok(b) => b,
Err(e) => {
return BranchContextResult::Error(format!("Failed to get current branch: {}", e))
}
};
let (spec, spec_path) = match find_spec_for_branch(&branch_name) {
Ok(Some((s, p))) => (Some(s), Some(p)),
Ok(None) => {
if show_warning {
println!(
"{YELLOW}Warning: No spec file found for branch '{}'{RESET}",
branch_name
);
println!("{GRAY}PR review will proceed with reduced context.{RESET}");
println!();
}
(None, None)
}
Err(e) => {
if show_warning {
println!("{YELLOW}Warning: Failed to load spec: {}{RESET}", e);
}
(None, None)
}
};
let commits = git::get_branch_commits(&branch_name).unwrap_or_default();
let context = BranchContext {
branch_name,
spec,
spec_path,
commits,
};
if context.spec.is_some() {
BranchContextResult::SuccessWithSpec(context)
} else {
BranchContextResult::SuccessNoSpec(context)
}
}
pub fn find_spec_for_branch(branch: &str) -> Result<Option<(Spec, PathBuf)>> {
let state_manager = StateManager::new()?;
let specs = state_manager.list_specs()?;
for spec_path in &specs {
if let Ok(spec) = Spec::load(spec_path) {
if spec.branch_name == branch {
return Ok(Some((spec, spec_path.clone())));
}
}
}
let branch_suffix = branch
.strip_prefix("feature/")
.or_else(|| branch.strip_prefix("feat/"))
.unwrap_or(branch);
for spec_path in &specs {
let filename = spec_path.file_stem().and_then(|s| s.to_str()).unwrap_or("");
if filename.ends_with(branch_suffix)
|| filename.replace("spec-", "").contains(branch_suffix)
{
if let Ok(spec) = Spec::load(spec_path) {
return Ok(Some((spec, spec_path.clone())));
}
}
}
Ok(None)
}
pub fn print_branch_context(context: &BranchContext) {
println!("{CYAN}Branch:{RESET} {}", context.branch_name);
if context.spec.is_some() {
println!("{GREEN} ✓ Spec file loaded{RESET}");
} else {
println!("{YELLOW} ⚠ No spec file (reduced context){RESET}");
}
if !context.commits.is_empty() {
println!(
"{GRAY} {} commit{} on branch{RESET}",
context.commits.len(),
if context.commits.len() == 1 { "" } else { "s" }
);
}
println!();
}