mod internal;
use anyhow::Result;
#[derive(Debug, Clone, clap::Subcommand)]
pub enum SpecCommands {
Archive {
id: Option<String>,
#[arg(long)]
dry_run: bool,
#[arg(long)]
stale: bool,
},
Ready {
#[arg(long)]
json: bool,
},
Blocked {
#[arg(long)]
json: bool,
},
Status {
id: String,
status: String,
#[arg(long)]
major: bool,
#[arg(long)]
no_archive: bool,
},
List {
#[arg(long)]
status: Option<String>,
#[arg(long)]
target: Option<String>,
#[arg(long)]
json: bool,
},
}
pub fn archive(id: &str, dry_run: bool) -> Result<()> {
internal::archive_spec(id, dry_run)
}
pub fn archive_stale(dry_run: bool) -> Result<()> {
internal::archive_stale_specs(dry_run)
}
pub fn ready(json: bool) -> Result<()> {
internal::show_ready_specs(json)
}
pub fn blocked(json: bool) -> Result<()> {
internal::show_blocked_specs(json)
}
pub fn status(id: &str, new_status: &str, major: bool, no_archive: bool) -> Result<()> {
internal::update_spec_status(id, new_status, major, no_archive)
}
pub fn list(status: Option<String>, target: Option<String>, json: bool) -> Result<()> {
let filters = internal::ListFilters { status, target };
internal::show_spec_list(&filters, json)
}
#[cfg(test)]
mod tests {
use super::SpecCommands;
use clap::Parser;
#[derive(Parser)]
struct TestCli {
#[command(subcommand)]
command: SpecCommands,
}
fn parse(args: &[&str]) -> Result<SpecCommands, clap::Error> {
TestCli::try_parse_from(std::iter::once("patina-spec").chain(args.iter().copied()))
.map(|cli| cli.command)
}
#[test]
fn status_with_no_archive_flag() {
let cmd = parse(&["status", "my-spec", "complete", "--no-archive"]).unwrap();
match cmd {
SpecCommands::Status {
id,
status,
no_archive,
major,
} => {
assert_eq!(id, "my-spec");
assert_eq!(status, "complete");
assert!(no_archive);
assert!(!major);
}
_ => panic!("expected Status"),
}
}
#[test]
fn status_defaults_archive_on() {
let cmd = parse(&["status", "my-spec", "complete"]).unwrap();
match cmd {
SpecCommands::Status { no_archive, .. } => {
assert!(!no_archive, "--no-archive should default to false");
}
_ => panic!("expected Status"),
}
}
#[test]
fn archive_with_id() {
let cmd = parse(&["archive", "my-spec"]).unwrap();
match cmd {
SpecCommands::Archive { id, stale, dry_run } => {
assert_eq!(id.as_deref(), Some("my-spec"));
assert!(!stale);
assert!(!dry_run);
}
_ => panic!("expected Archive"),
}
}
#[test]
fn archive_stale_no_id() {
let cmd = parse(&["archive", "--stale"]).unwrap();
match cmd {
SpecCommands::Archive { id, stale, .. } => {
assert!(id.is_none());
assert!(stale);
}
_ => panic!("expected Archive"),
}
}
#[test]
fn archive_stale_dry_run() {
let cmd = parse(&["archive", "--stale", "--dry-run"]).unwrap();
match cmd {
SpecCommands::Archive { id, stale, dry_run } => {
assert!(id.is_none());
assert!(stale);
assert!(dry_run);
}
_ => panic!("expected Archive"),
}
}
#[test]
fn archive_no_id_no_stale_still_parses() {
let cmd = parse(&["archive"]).unwrap();
match cmd {
SpecCommands::Archive { id, stale, .. } => {
assert!(id.is_none());
assert!(!stale);
}
_ => panic!("expected Archive"),
}
}
}