Skip to main content

apm/
util.rs

1use anyhow::Result;
2use apm_core::{config::Config, git, ticket, ticket_fmt, worktree};
3use std::io::{self, BufRead, Write};
4use std::path::{Path, PathBuf};
5
6/// Run `git fetch --all` when `aggressive` is true; emit a warning on failure.
7pub fn fetch_if_aggressive(root: &Path, aggressive: bool) {
8    if aggressive {
9        if let Err(e) = git::fetch_all(root) {
10            eprintln!("warning: fetch failed: {e:#}");
11        }
12    }
13}
14
15/// Run `git fetch <branch>` when `aggressive` is true; emit a warning on failure.
16pub fn fetch_branch_if_aggressive(root: &Path, branch: &str, aggressive: bool) {
17    if aggressive {
18        if let Err(e) = git::fetch_branch(root, branch) {
19            eprintln!("warning: fetch failed: {e:#}");
20        }
21    }
22}
23
24/// Print `prompt`, flush stdout, read one line, return true iff the answer is "y".
25pub fn prompt_yes_no(prompt: &str) -> io::Result<bool> {
26    print!("{prompt}");
27    io::stdout().flush()?;
28    let mut line = String::new();
29    io::stdin().lock().read_line(&mut line)?;
30    Ok(line.trim().eq_ignore_ascii_case("y"))
31}
32
33/// Print `prompt`, flush stdout, read one line; returns true unless the user types "n" (default yes).
34pub fn prompt_yes_no_default_yes(prompt: &str) -> io::Result<bool> {
35    print!("{prompt}");
36    io::stdout().flush()?;
37    let mut line = String::new();
38    io::stdin().lock().read_line(&mut line)?;
39    Ok(!line.trim().eq_ignore_ascii_case("n"))
40}
41
42/// Resolve a ticket ID argument to its worktree path and canonical ticket ID.
43/// Loads config and tickets from git internally.
44pub fn worktree_for_ticket(root: &Path, id_arg: &str) -> Result<(PathBuf, String)> {
45    let config = Config::load(root)?;
46    let tickets = ticket::load_all_from_git(root, &config.tickets.dir)?;
47    let id = ticket::resolve_id_in_slice(&tickets, id_arg)?;
48    let t = tickets
49        .iter()
50        .find(|t| t.frontmatter.id == id)
51        .ok_or_else(|| anyhow::anyhow!("ticket {id:?} not found"))?;
52    let branch = t
53        .frontmatter
54        .branch
55        .clone()
56        .or_else(|| ticket_fmt::branch_name_from_path(&t.path))
57        .unwrap_or_else(|| format!("ticket/{id}"));
58    let wt = worktree::find_worktree_for_branch(root, &branch)
59        .ok_or_else(|| anyhow::anyhow!("no worktree for ticket {id:?}"))?;
60    Ok((wt, id))
61}