use std::process::ExitCode;
use clap::Args;
use crate::config::ResolvedContext;
use super::client;
#[derive(Debug, Args)]
pub struct RejectArgs {
pub id: String,
#[arg(long)]
pub reason: Option<String>,
}
pub fn validate_reject_reason(reason: &Option<String>) -> Result<&str, &'static str> {
match reason.as_deref() {
Some(r) if !r.trim().is_empty() => Ok(r),
_ => Err("error: --reason is required for aasm approvals reject"),
}
}
pub fn run_reject(args: RejectArgs, ctx: &ResolvedContext) -> ExitCode {
let resolved = super::reason_io::resolve_reason_from_process_stdin(args.reason);
let reason = match validate_reject_reason(&resolved) {
Ok(r) => r.to_string(),
Err(msg) => {
eprintln!("{msg}");
return ExitCode::FAILURE;
}
};
let rt = tokio::runtime::Runtime::new().expect("failed to create tokio runtime");
let result = rt.block_on(client::reject_action(ctx, &args.id, &reason));
match result {
Ok(resp) => {
println!("Rejected: {} (status: {})", resp.id, resp.status);
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("error: {e}");
ExitCode::FAILURE
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validate_reject_reason_none_returns_error() {
let result = validate_reject_reason(&None);
assert!(result.is_err());
}
#[test]
fn validate_reject_reason_empty_returns_error() {
let empty = Some(" ".to_string());
let result = validate_reject_reason(&empty);
assert!(result.is_err());
}
#[test]
fn validate_reject_reason_valid_returns_ok() {
let reason = Some("policy violation".to_string());
let result = validate_reject_reason(&reason);
assert_eq!(result.unwrap(), "policy violation");
}
}