use clap::{Args, Subcommand};
use crate::cli::parse_id;
use crate::config::find_bmo_dir;
use crate::db::{Repository, open_db};
use crate::errors::{BmoError, ErrorCode};
use crate::model::RelationKind;
use crate::output::{OutputMode, make_printer};
#[derive(Subcommand)]
pub enum LinkCommands {
Add(AddArgs),
Remove(RemoveArgs),
List(ListArgs),
}
#[derive(Args)]
pub struct AddArgs {
pub from_id: String,
pub relation: String,
pub to_id: String,
}
#[derive(Args)]
pub struct RemoveArgs {
pub id: i64,
}
#[derive(Args)]
pub struct ListArgs {
pub id: String,
}
pub fn run_add(args: &AddArgs, json: bool) -> anyhow::Result<()> {
let bmo_dir = find_bmo_dir()?;
let repo = open_db(&bmo_dir.join("issues.db"))?;
let from_id = parse_id(&args.from_id)?;
let to_id = parse_id(&args.to_id)?;
if from_id == to_id {
let printer = make_printer(if json {
OutputMode::Json
} else {
OutputMode::Human
});
printer.print_error("Cannot link an issue to itself", ErrorCode::Validation);
std::process::exit(ErrorCode::Validation.exit_code());
}
let kind: RelationKind = args.relation.parse()?;
let relation = match repo.add_relation(from_id, kind, to_id) {
Ok(r) => r,
Err(e) => {
if let Some(BmoError::Validation(msg)) = e.downcast_ref::<BmoError>() {
let printer = make_printer(if json {
OutputMode::Json
} else {
OutputMode::Human
});
printer.print_error(msg, ErrorCode::Validation);
std::process::exit(ErrorCode::Validation.exit_code());
}
return Err(e);
}
};
if json {
let envelope = serde_json::json!({ "ok": true, "data": relation, "message": format!("Linked BMO-{from_id} {kind} BMO-{to_id}") });
println!("{}", serde_json::to_string_pretty(&envelope)?);
} else {
println!("Linked BMO-{from_id} {kind} BMO-{to_id}");
}
Ok(())
}
pub fn run_remove(args: &RemoveArgs, json: bool) -> anyhow::Result<()> {
let bmo_dir = find_bmo_dir()?;
let repo = open_db(&bmo_dir.join("issues.db"))?;
repo.remove_relation(args.id)?;
if json {
let envelope = serde_json::json!({ "ok": true, "data": null, "message": format!("Removed relation {}", args.id) });
println!("{}", serde_json::to_string_pretty(&envelope)?);
} else {
println!("Removed relation {}", args.id);
}
Ok(())
}
pub fn run_list(args: &ListArgs, json: bool) -> anyhow::Result<()> {
let bmo_dir = find_bmo_dir()?;
let repo = open_db(&bmo_dir.join("issues.db"))?;
let printer = make_printer(if json {
OutputMode::Json
} else {
OutputMode::Human
});
let issue_id = parse_id(&args.id)?;
let relations = repo.list_relations(issue_id)?;
printer.print_relations(&relations);
Ok(())
}