use std::path::{Path, PathBuf};
use anyhow::Result;
use crate::git;
macro_rules! domain_bail {
($kind:ident, $fmt:literal $(, $arg:expr)* , hint: $hint:expr) => {
return Err($crate::DomainError::with_hint(
$crate::ErrorKind::$kind,
format!($fmt $(, $arg)*),
$hint.to_string(),
).into())
};
($kind:ident, $fmt:literal $(, $arg:expr)*) => {
return Err($crate::DomainError::new(
$crate::ErrorKind::$kind,
format!($fmt $(, $arg)*),
).into())
};
($($arg:tt)*) => {
return Err($crate::DomainError::new(
$crate::ErrorKind::Validation,
format!($($arg)*),
).into())
};
}
pub(crate) use domain_bail;
pub(crate) fn is_quiet() -> bool {
crate::QUIET.load(std::sync::atomic::Ordering::Relaxed)
}
pub(crate) fn is_json_output() -> bool {
crate::JSON_OUTPUT.load(std::sync::atomic::Ordering::Relaxed)
}
pub(crate) fn is_dry_run() -> bool {
crate::DRY_RUN.load(std::sync::atomic::Ordering::Relaxed)
}
pub(crate) fn tickets_dir() -> Result<PathBuf> {
let cwd = std::env::current_dir()?;
let root = git::repo_root(&cwd)?;
let dir = root.join(".tickets");
if !dir.is_dir() {
domain_bail!("no .tickets/ directory in {}", root.display());
}
Ok(dir)
}
pub(crate) fn project_config(tickets_dir: &Path) -> crate::config::ProjectConfig {
let cfg = crate::config::ProjectConfig::load(tickets_dir);
for key in &cfg.unknown_keys {
eprintln!(
"warning: unknown config key {:?} in .tickets/config.toml",
key
);
}
cfg
}
pub(crate) fn success_msg(verb: &str, id: &str, slug: &str, detail: &str) -> String {
format!(
"{} {} {} {} ({})",
crate::color::sym_ok(),
verb,
id,
slug,
detail
)
}
pub(crate) fn print_success(verb: &str, id: &str, slug: &str, detail: &str) {
if is_json_output() {
let result = format!("{} {} {} ({})", verb, id, slug, detail);
crate::cli::emit_json_success(&result);
} else {
println!("{}", success_msg(verb, id, slug, detail));
}
}
pub(crate) fn slug_from_filename(path: &Path) -> String {
let name = path
.file_name()
.unwrap_or_default()
.to_string_lossy()
.to_string();
if let Some(pos) = name.find('-') {
name[pos + 1..].trim_end_matches(".md").to_string()
} else {
name.trim_end_matches(".md").to_string()
}
}