gitswitch 0.1.0

Switch between GitHub accounts (git identity + gh auth) on the fly
//! Command-line interface: clap definitions and bare-alias dispatch.

use clap::{Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(
    name = "gitswitch",
    about = "Switch between GitHub accounts (identity + gh auth) on the fly",
    version
)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,
}

#[derive(Subcommand, Debug)]
pub enum Command {
    /// Interactively add (or overwrite) an account profile
    Add { alias: String },
    /// List all account profiles
    List,
    /// Show the current git identity and active gh user
    Current,
    /// Remove an account profile
    Remove { alias: String },
    /// Switch to an account by alias (the default: `gitswitch <alias>`)
    #[command(external_subcommand)]
    Switch(Vec<String>),
}

/// Resolve the alias from an `external_subcommand` capture, rejecting extra args.
///
/// clap routes an unknown bare token here as `["work"]`; anything longer than a
/// single token is a usage error.
pub fn resolve_switch_alias(args: &[String]) -> Result<&str, String> {
    match args {
        [alias] => Ok(alias.as_str()),
        [] => Err("expected an account alias to switch to".to_string()),
        _ => Err(format!(
            "unexpected extra arguments after '{}'; usage: gitswitch <alias>",
            args[0]
        )),
    }
}

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

    #[test]
    fn single_token_resolves_to_alias() {
        let args = vec!["work".to_string()];
        assert_eq!(resolve_switch_alias(&args), Ok("work"));
    }

    #[test]
    fn empty_is_error() {
        assert!(resolve_switch_alias(&[]).is_err());
    }

    #[test]
    fn extra_args_are_error() {
        let args = vec!["work".to_string(), "extra".to_string()];
        assert!(resolve_switch_alias(&args).is_err());
    }
}