use clap::{Args, Subcommand};
use serde::Serialize;
use super::CmdResult;
use homeboy::changelog::{self, AddItemsOutput, InitOutput};
#[derive(Args)]
pub struct ChangelogArgs {
#[arg(long = "self")]
pub show_self: bool,
#[command(subcommand)]
pub command: Option<ChangelogCommand>,
}
#[derive(Subcommand)]
pub enum ChangelogCommand {
Add {
#[arg(long)]
cwd: bool,
#[arg(long)]
json: Option<String>,
component_id: Option<String>,
positional_message: Option<String>,
#[arg(short = 'm', long = "message", action = clap::ArgAction::Append)]
messages: Vec<String>,
},
Init {
#[arg(long)]
cwd: bool,
#[arg(long)]
path: Option<String>,
#[arg(long)]
configure: bool,
component_id: Option<String>,
},
}
#[derive(Serialize)]
pub struct ChangelogShowOutput {
pub topic_label: String,
pub content: String,
}
#[derive(Serialize)]
#[serde(tag = "command")]
pub enum ChangelogOutput {
Show(ChangelogShowOutput),
Add(AddItemsOutput),
Init(InitOutput),
}
pub fn run_markdown(args: ChangelogArgs) -> CmdResult<String> {
match (&args.command, args.show_self) {
(None, true) => show_markdown(),
(None, false) => Err(homeboy::Error::validation_invalid_argument(
"command",
"No subcommand provided. Use a subcommand (add, init) or --self to view Homeboy's changelog",
None,
Some(vec![
"homeboy changelog add <component_id> <message>".to_string(),
"homeboy changelog init <component_id>".to_string(),
"homeboy changelog --self".to_string(),
]),
)),
(Some(ChangelogCommand::Add { .. }) | Some(ChangelogCommand::Init { .. }), _) => {
Err(homeboy::Error::validation_invalid_argument(
"command",
"Markdown output is only supported for 'changelog --self'",
None,
None,
))
}
}
}
pub fn is_show_markdown(args: &ChangelogArgs) -> bool {
args.command.is_none() && args.show_self
}
pub fn run(
args: ChangelogArgs,
_global: &crate::commands::GlobalArgs,
) -> CmdResult<ChangelogOutput> {
match (&args.command, args.show_self) {
(None, true) => {
let (out, code) = show_json()?;
Ok((ChangelogOutput::Show(out), code))
}
(None, false) => Err(homeboy::Error::validation_invalid_argument(
"command",
"No subcommand provided. Use a subcommand (add, init) or --self to view Homeboy's changelog",
None,
Some(vec![
"homeboy changelog add <component_id> <message>".to_string(),
"homeboy changelog init <component_id>".to_string(),
"homeboy changelog --self".to_string(),
]),
)),
(Some(ChangelogCommand::Add {
cwd,
json,
component_id,
positional_message,
messages,
}), _) => {
let mut all_messages: Vec<String> = Vec::new();
if let Some(msg) = positional_message {
all_messages.push(msg.clone());
}
all_messages.extend(messages.iter().cloned());
if *cwd {
let output = changelog::add_items_cwd(&all_messages)?;
return Ok((ChangelogOutput::Add(output), 0));
}
if let Some(spec) = json.as_deref() {
let output = changelog::add_items_bulk(spec)?;
return Ok((ChangelogOutput::Add(output), 0));
}
let output = changelog::add_items(component_id.as_deref(), &all_messages)?;
Ok((ChangelogOutput::Add(output), 0))
}
(Some(ChangelogCommand::Init {
cwd,
path,
configure,
component_id,
}), _) => {
if *cwd {
let output = changelog::init_cwd(path.as_deref())?;
return Ok((ChangelogOutput::Init(output), 0));
}
let id = component_id.as_ref().ok_or_else(|| {
homeboy::Error::validation_invalid_argument(
"componentId",
"Missing component ID (or use --cwd). List components: homeboy component list",
None,
None,
)
})?;
let output = changelog::init(id, path.as_deref(), *configure)?;
Ok((ChangelogOutput::Init(output), 0))
}
}
}
const HOMEBOY_CHANGELOG: &str = include_str!("../../docs/changelog.md");
fn show_markdown() -> CmdResult<String> {
Ok((HOMEBOY_CHANGELOG.to_string(), 0))
}
fn show_json() -> CmdResult<ChangelogShowOutput> {
Ok((
ChangelogShowOutput {
topic_label: "changelog".to_string(),
content: HOMEBOY_CHANGELOG.to_string(),
},
0,
))
}