communique 1.3.1

Editorialized release notes powered by AI
use crate::cli::Cli;
use clap::CommandFactory;

/// Generates a usage spec for the CLI
///
/// https://usage.jdx.dev
#[derive(Debug, clap::Args)]
#[clap(hide = true, verbatim_doc_comment)]
pub struct Usage {}

/// The spec written to communique.usage.kdl, shared by `communique usage` and
/// the test that keeps the checked-in copy in sync.
fn generate_to_string() -> String {
    let mut cmd = Cli::command();
    let mut spec = clap_usage::spec(&mut cmd, "communique");
    // Declare what each command does to the world; clap cannot express it.
    crate::command_effects::apply(&mut spec);
    // 3.6 added `effect=`; older `usage` CLIs reject the spec outright with
    // "unsupported cmd prop effect".
    format!(
        "// @generated by `communique usage` from clap metadata\nmin_usage_version \"4.0\"\n{spec}"
    )
}

impl Usage {
    pub fn run(&self) -> miette::Result<()> {
        println!("{}", generate_to_string());
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// `run` is thin, but it is the only path that actually emits the spec —
    /// leaving it untested meant nothing checked that `communique usage`
    /// succeeds at all.
    #[test]
    fn run_succeeds() {
        assert!(Usage {}.run().is_ok());
    }

    #[test]
    fn test_usage_kdl_in_sync() {
        let generated = generate_to_string();
        let on_disk = std::fs::read_to_string(
            std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("communique.usage.kdl"),
        )
        .expect("communique.usage.kdl should exist");
        assert_eq!(
            generated.trim(),
            on_disk.trim(),
            "communique.usage.kdl is out of sync — run `cargo run -- usage > communique.usage.kdl` to update"
        );
    }
}