@ -14,7 +14,8 @@ mod tests;
use clap ::{ Parser , Subcommand } ;
use clap ::{ Parser , Subcommand } ;
use crate ::store ::{
use crate ::store ::{
ensure_tickets_dir , find_nbd_root , list_tickets , migrate_tickets , read_ticket , write_ticket ,
ensure_tickets_dir , find_nbd_root , list_tickets , migrate_tickets , read_ticket , resolve_id ,
write_ticket ,
} ;
} ;
use crate ::ticket ::{ generate_id , validate_priority , Status , Ticket , TicketType } ;
use crate ::ticket ::{ generate_id , validate_priority , Status , Ticket , TicketType } ;
@ -226,16 +227,21 @@ fn parse_deps(deps: Option<&str>) -> Vec<String> {
/// Verify that every ID in `deps` refers to an existing ticket.
/// Verify that every ID in `deps` refers to an existing ticket.
///
///
/// Each entry may be a full ID or a unique prefix; `resolve_id` is used to
/// expand prefixes before checking existence. The `deps` slice is mutated
/// in-place so that all entries are replaced with their resolved full IDs.
///
/// # Errors
/// # Errors
///
///
/// Returns an error that names the first missing dependency.
/// Returns an error that names the first missing or ambiguous dependency.
async fn validate_deps ( root : & std ::path ::Path , deps : & [ String ] ) -> store ::Result < ( ) > {
async fn validate_deps ( root : & std ::path ::Path , deps : & mut [ String ] ) -> store ::Result < ( ) > {
for dep_id in deps {
for dep_id in deps . iter_mut ( ) {
read_ticket ( root , dep_id ) . await . map_err (
let resolved = resolve_id ( root , dep_id ) . await . map_err (
| _ | -> Box < dyn std ::error ::Error + Send + Sync > {
| _ | -> Box < dyn std ::error ::Error + Send + Sync > {
format! ( "dependency '{dep_id}' not found" ) . into ( )
format! ( "dependency '{dep_id}' not found" ) . into ( )
} ,
} ,
) ? ;
) ? ;
* dep_id = resolved ;
}
}
Ok ( ( ) )
Ok ( ( ) )
}
}
@ -279,8 +285,8 @@ async fn cmd_create(
let root = find_nbd_root ( ) ? ;
let root = find_nbd_root ( ) ? ;
ensure_tickets_dir ( & root ) . await ? ;
ensure_tickets_dir ( & root ) . await ? ;
let dependencies = parse_deps ( deps . as_deref ( ) ) ;
let mut dependencies = parse_deps ( deps . as_deref ( ) ) ;
validate_deps ( & root , & dependencies ) . await ? ;
validate_deps ( & root , & mut dependencies ) . await ? ;
let id = generate_id ( ) ;
let id = generate_id ( ) ;
let mut ticket = Ticket ::new ( id , title ) ;
let mut ticket = Ticket ::new ( id , title ) ;
@ -301,9 +307,10 @@ async fn cmd_create(
Ok ( ( ) )
Ok ( ( ) )
}
}
/// Read a ticket by ID and print it.
/// Read a ticket by ID (or unique prefix) and print it.
async fn cmd_read ( id : String , json : bool ) -> store ::Result < ( ) > {
async fn cmd_read ( id : String , json : bool ) -> store ::Result < ( ) > {
let root = find_nbd_root ( ) ? ;
let root = find_nbd_root ( ) ? ;
let id = resolve_id ( & root , & id ) . await ? ;
let ticket = read_ticket ( & root , & id ) . await ? ;
let ticket = read_ticket ( & root , & id ) . await ? ;
if json {
if json {
@ -332,7 +339,8 @@ async fn cmd_list(json: bool) -> store::Result<()> {
/// Update the specified fields of an existing ticket, persist it, and print it.
/// Update the specified fields of an existing ticket, persist it, and print it.
///
///
/// Only the flags explicitly passed on the command line are applied; all other
/// Only the flags explicitly passed on the command line are applied; all other
/// fields keep their current values.
/// fields keep their current values. `id` may be a full 6-character ID or a
/// unique prefix.
#[ allow(clippy::too_many_arguments) ]
#[ allow(clippy::too_many_arguments) ]
async fn cmd_update (
async fn cmd_update (
id : String ,
id : String ,
@ -345,6 +353,7 @@ async fn cmd_update(
json : bool ,
json : bool ,
) -> store ::Result < ( ) > {
) -> store ::Result < ( ) > {
let root = find_nbd_root ( ) ? ;
let root = find_nbd_root ( ) ? ;
let id = resolve_id ( & root , & id ) . await ? ;
let mut ticket = read_ticket ( & root , & id ) . await ? ;
let mut ticket = read_ticket ( & root , & id ) . await ? ;
if let Some ( t ) = title {
if let Some ( t ) = title {
@ -365,8 +374,8 @@ async fn cmd_update(
ticket . ticket_type = parse_ticket_type ( & tt ) ? ;
ticket . ticket_type = parse_ticket_type ( & tt ) ? ;
}
}
if deps . is_some ( ) {
if deps . is_some ( ) {
let dependencies = parse_deps ( deps . as_deref ( ) ) ;
let mut dependencies = parse_deps ( deps . as_deref ( ) ) ;
validate_deps ( & root , & dependencies ) . await ? ;
validate_deps ( & root , & mut dependencies ) . await ? ;
ticket . dependencies = dependencies ;
ticket . dependencies = dependencies ;
}
}