use std::path::PathBuf;
use usage_rs::{Args, Cli, Subcommands};
use crate::providers::Provider;
use crate::usage;
#[derive(Debug, Args)]
#[usage(effect = "read")]
pub struct Generate {
#[usage(arg)]
pub tag: String,
#[usage(arg)]
pub prev_tag: Option<String>,
#[usage(long, effect = "write")]
pub github_release: bool,
#[usage(long, effect = "write")]
pub changelog: bool,
#[usage(long)]
pub concise: bool,
#[usage(long, short = 'n')]
pub dry_run: bool,
#[usage(long)]
pub repo: Option<String>,
#[usage(long)]
pub model: Option<String>,
#[usage(long)]
pub max_tokens: Option<u32>,
#[usage(long)]
pub provider: Option<Provider>,
#[usage(long)]
pub base_url: Option<String>,
#[usage(long, short, effect = "write")]
pub output: Option<PathBuf>,
}
#[derive(Debug, Args)]
#[usage(effect = "write")]
pub struct Init {
#[usage(long, effect = "destructive")]
pub force: bool,
}
#[derive(Subcommands)]
pub enum Command {
Generate(Box<Generate>),
Init(Box<Init>),
#[usage(effect = "read")]
Sponsors,
#[usage(hide)]
Usage(Box<usage::Usage>),
}
#[derive(Cli)]
#[usage(
name = "communique",
bin = "communique",
version,
usage = "Usage: communique [OPTIONS] <COMMAND>",
min_usage_version = "4.0",
unknown_flags = "error"
)]
pub struct Cli {
#[usage(subcommand)]
pub command: Command,
#[usage(long, short, global)]
pub verbose: bool,
#[usage(long, short, global)]
pub quiet: bool,
#[usage(long, short, global)]
pub config: Option<PathBuf>,
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::OsStr;
#[test]
fn typed_commands_bind_their_fields() {
let argv: &[&OsStr] = &[
OsStr::new("--verbose"),
OsStr::new("generate"),
OsStr::new("v1.2.3"),
OsStr::new("v1.2.2"),
OsStr::new("--github-release"),
OsStr::new("--max-tokens"),
OsStr::new("2048"),
OsStr::new("--provider"),
OsStr::new("openai"),
];
let cli = Cli::parse_from(argv).expect("generate should parse");
assert!(cli.verbose);
check_command(cli.command, "generate");
for (argv, expected) in [
(&[OsStr::new("init"), OsStr::new("--force")][..], "init"),
(&[OsStr::new("sponsors")][..], "sponsors"),
(&[OsStr::new("usage")][..], "usage"),
] {
let cli = Cli::parse_from(argv).expect("command should parse");
check_command(cli.command, expected);
}
}
#[test]
fn a_later_command_line_merges_into_the_parsed_value() {
let mut cli = Cli::parse_from(&[OsStr::new("--verbose"), OsStr::new("sponsors")])
.expect("sponsors should parse");
cli.try_update_from(&[
OsStr::new("generate"),
OsStr::new("v1.2.3"),
OsStr::new("v1.2.2"),
OsStr::new("--github-release"),
OsStr::new("--max-tokens"),
OsStr::new("2048"),
OsStr::new("--provider"),
OsStr::new("openai"),
])
.expect("the second command line should merge");
assert!(cli.verbose, "the standing global survives the merge");
check_command(cli.command, "generate");
}
fn check_command(command: Command, expected: &str) {
match command {
Command::Generate(generate) => {
assert_eq!(expected, "generate");
assert_eq!(generate.tag, "v1.2.3");
assert_eq!(generate.prev_tag.as_deref(), Some("v1.2.2"));
assert!(generate.github_release);
assert_eq!(generate.max_tokens, Some(2048));
assert_eq!(generate.provider, Some(Provider::OpenAI));
}
Command::Init(init) => {
assert_eq!(expected, "init");
assert!(init.force);
}
Command::Sponsors => assert_eq!(expected, "sponsors"),
Command::Usage(_) => assert_eq!(expected, "usage"),
}
}
}