Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
Set clap help_template
Christopher Fredén committed 2 years ago
commit 56b64c9d3959f4ab5a364504b418c9b006479aba
parent ef2949832b1a684526bce50cfdfea5db260a7d28
3 files changed +109 -138
modified radicle-cli/src/cli.rs
@@ -89,85 +89,3 @@ pub fn completer(cmd: Command, args: Vec<OsString>) -> () {
        dbg!("COMPLETER FAILED: args: {:?}, matches: {:?}", args, matches);
    }
}
-

-
// pub fn to_issue_options() -> anyhow::Result<rad_issue::Options> {
-
//     let args = CliArgs::parse();
-

-
//     // Default to List command.
-
//     // let command = args.command.unwrap_or(Commands::Issue(IssueArgs {
-
//     //     command: Some(IssueCommands::List(ListArgs {
-
//     //         assigned: None,
-
//     //         filter: ListFilter::All,
-
//     //     })),
-
//     //     header: false,
-
//     //     quiet: false,
-
//     //     no_announce: false,
-
//     // }));
-

-
//     let options = match args {
-
//         CliArgs { command } => match command {
-
//             Some(Commands::Issue(IssueArgs {
-
//                 command: subcommand,
-
//                 quiet,
-
//                 no_announce,
-
//                 header,
-
//             })) => match subcommand {
-
//                 Some(IssueCommands::List(args)) => Some(rad_issue::Options {
-
//                     op: rad_issue::Operation::List {
-
//                         assigned: args
-
//                             .assigned
-
//                             .map(|did| {
-
//                                 let did =
-
//                                     term::args::did(&OsString::from(format!("did:key:{did}")))?;
-
//                                 Ok::<Option<Assigned>, anyhow::Error>(Some(Assigned::Peer(did)))
-
//                             })
-
//                             .unwrap_or(Ok(None))?,
-
//                         state: match args.filter {
-
//                             ListFilter::All => None,
-
//                             ListFilter::Open => Some(radicle::cob::issue::State::Open),
-
//                             ListFilter::Closed => Some(State::Closed {
-
//                                 reason: CloseReason::Other,
-
//                             }),
-
//                             ListFilter::Solved => Some(State::Closed {
-
//                                 reason: CloseReason::Solved,
-
//                             }),
-
//                         },
-
//                     },
-
//                     announce: !no_announce,
-
//                     quiet: quiet,
-
//                 }),
-
//                 Some(IssueCommands::Show(args)) => Some(rad_issue::Options {
-
//                     op: rad_issue::Operation::Show {
-
//                         id: Rev::from(args.id),
-
//                         format: if header {
-
//                             term::issue::Format::Header
-
//                         } else {
-
//                             term::issue::Format::Full
-
//                         },
-
//                         debug: args.debug,
-
//                     },
-
//                     announce: !no_announce,
-
//                     quiet: quiet,
-
//                 }),
-
//                 // Default `issue` subcommand is `list`.
-
//                 _ => Some(rad_issue::Options {
-
//                     op: rad_issue::Operation::List {
-
//                         assigned: None,
-
//                         state: None,
-
//                     },
-
//                     announce: false,
-
//                     quiet: false,
-
//                 }),
-
//             },
-
//             _ => None,
-
//         },
-
//     };
-

-
//     let Some(option) = options else {
-
//         CliArgs::command().write_help(&mut std::io::stdout())?;
-
//         println!();
-
//         process::exit(0);
-
//     };
-

-
//     Ok(option)
-
// }
modified radicle-cli/src/commands/issue.rs
@@ -2,7 +2,7 @@
mod cache;

use anyhow::Context as _;
-
use clap::{Parser, Subcommand, ValueHint};
+
use clap::{ArgGroup, Parser, Subcommand, ValueHint};

use radicle::cob::common::{Label, Reaction};
use radicle::cob::issue;
@@ -107,14 +107,14 @@ pub struct IssueArgs {

#[derive(Subcommand, Debug)]
enum IssueCommands {
-
    /// Delete an issue.
+
    /// Delete an issue
    Delete {
        #[arg(value_name = "issue-id")]
        #[clap(value_hint = ValueHint::Dynamic(get_issue_id_hints))]
        id: Rev,
    },

-
    /// Edit an issue.
+
    /// Edit an issue
    Edit {
        #[arg(value_name = "issue-id")]
        #[clap(value_hint = ValueHint::Dynamic(get_issue_id_hints))]
@@ -127,15 +127,10 @@ enum IssueCommands {
        description: Option<String>,
    },

-
    List {
-
        #[clap(value_hint = ValueHint::Dynamic(get_assignee_did_hints))]
-
        #[arg(long, name = "did")]
-
        assigned: Option<Did>,
-

-
        #[clap(value_enum, default_value_t=StateFilter::All)]
-
        state: StateFilter,
-
    },
+
    /// List and filter issues
+
    List(ListArgs),

+
    /// Create a new issue
    Open {
        #[arg(long, short)]
        title: Option<String>,
@@ -150,6 +145,7 @@ enum IssueCommands {
        assignees: Vec<Did>,
    },

+
    /// Add a reaction emoji to an issue or comment
    React {
        #[arg(value_name = "issue-id")]
        #[clap(value_hint = ValueHint::Dynamic(get_issue_id_hints))]
@@ -184,7 +180,7 @@ enum IssueCommands {
        delete: Vec<Did>,
    },

-
    /// Update lables on an issue.
+
    /// Update labels on an issue
    Label {
        /// The issue to label.
        #[arg(value_name = "issue-id")]
@@ -219,6 +215,7 @@ enum IssueCommands {
        reply_to: Option<Rev>,
    },

+
    /// Show a specific issue
    Show {
        #[arg(value_name = "issue-id")]
        #[clap(value_hint = ValueHint::Dynamic(get_issue_id_hints))]
@@ -229,57 +226,89 @@ enum IssueCommands {
        debug: bool,
    },

-
    State {
-
        #[arg(value_name = "issue-id")]
-
        #[clap(value_hint = ValueHint::Dynamic(get_issue_id_hints))]
-
        id: Rev,
-

-
        #[clap(value_enum)]
-
        state: StateChoice,
-
    },
    Cache {
        #[arg(value_name = "issue-id")]
        id: Option<Rev>,
    },
+

+
    State(StateArgs),
+
}
+

+
#[derive(Parser, Debug)]
+
struct ListArgs {
+
    /// List issues assigned to <did>
+
    #[clap(value_hint = ValueHint::Dynamic(get_assignee_did_hints))]
+
    #[arg(long, name = "did")]
+
    assigned: Option<Did>,
+

+
    /// List all issues (default)
+
    #[arg(long, group = "state")]
+
    all: bool,
+

+
    /// List only open issues
+
    #[arg(long, group = "state")]
+
    open: bool,
+

+
    /// List only closed issues
+
    #[arg(long, group = "state")]
+
    closed: bool,
+

+
    /// List only solved issues
+
    #[arg(long, group = "state")]
+
    solved: bool,
}

-
#[derive(clap::ValueEnum, Clone, Debug)]
-
enum StateFilter {
-
    All,
-
    Closed,
-
    Open,
-
    Solved,
+
#[derive(Parser, Debug)]
+
#[clap(group(ArgGroup::new("state").required(true)))]
+
struct StateArgs {
+
    #[arg(value_name = "issue-id")]
+
    #[clap(value_hint = ValueHint::Dynamic(get_issue_id_hints))]
+
    id: Rev,
+

+
    /// Set issue state to open
+
    #[arg(long, short, group = "state")]
+
    open: bool,
+

+
    /// Set issue state to closed
+
    #[arg(long, short, group = "state")]
+
    closed: bool,
+

+
    /// Set issue state to solved
+
    #[arg(long, short, group = "state")]
+
    solved: bool,
}

-
fn to_state_filter(list_state: StateFilter) -> Option<State> {
-
    match list_state {
-
        StateFilter::All => None,
-
        StateFilter::Open => Some(radicle::cob::issue::State::Open),
-
        StateFilter::Closed => Some(State::Closed {
+

+
fn to_state_filter(args: ListArgs) -> Option<State> {
+
    if args.open {
+
        Some(radicle::cob::issue::State::Open)
+
    } else if args.closed {
+
        Some(State::Closed {
            reason: CloseReason::Other,
-
        }),
-
        StateFilter::Solved => Some(State::Closed {
+
        })
+
    } else if args.solved {
+
        Some(State::Closed {
            reason: CloseReason::Solved,
-
        }),
+
        })
+
    } else {
+
        None
    }
}

-
#[derive(clap::ValueEnum, Clone, Debug)]
-
enum StateChoice {
-
    Closed,
-
    Open,
-
    Solved,
-
}
-

-
fn to_state_choice(choice: StateChoice) -> State {
-
    match choice {
-
        StateChoice::Open => radicle::cob::issue::State::Open,
-
        StateChoice::Closed => State::Closed {
+
fn to_state(args: StateArgs) -> State {
+
    if args.open {
+
        radicle::cob::issue::State::Open
+
    } else if args.closed {
+
        State::Closed {
            reason: CloseReason::Other,
-
        },
-
        StateChoice::Solved => State::Closed {
+
        }
+
    } else if args.solved {
+
        State::Closed {
            reason: CloseReason::Solved,
-
        },
+
        }
+
    } else {
+
        // FIXME:
+
        unreachable!("State flag needed");
    }
}

@@ -323,9 +352,9 @@ pub fn run(args: IssueArgs, ctx: impl term::Context) -> anyhow::Result<()> {
                    term::issue::show(&issue, issue.id(), Format::Header, &profile)?;
                }
            }
-
            IssueCommands::List { assigned, state } => {
-
                let assigned = assigned.map(Assigned::Peer);
-
                let state = to_state_filter(state);
+
            IssueCommands::List(list_args) => {
+
                let assigned = list_args.assigned.map(Assigned::Peer);
+
                let state = to_state_filter(list_args);
                list(issues, &assigned, &state, &profile)?;
            }
            IssueCommands::Show { id, debug } => {
@@ -346,11 +375,11 @@ pub fn run(args: IssueArgs, ctx: impl term::Context) -> anyhow::Result<()> {
                    term::issue::show(&issue, &id, format, &profile)?;
                }
            }
-
            IssueCommands::State { id, state } => {
+
            IssueCommands::State(state_args) => {
                let signer = term::signer(&profile)?;
-
                let id = id.resolve(&repo.backend)?;
+
                let id = state_args.id.resolve(&repo.backend)?;
                let mut issue = issues.get_mut(&id)?;
-
                issue.lifecycle(to_state_choice(state), &signer)?;
+
                issue.lifecycle(to_state(state_args), &signer)?;
            }
            IssueCommands::Assign { id, add, delete } => {
                let signer = term::signer(&profile)?;
modified radicle-cli/src/main.rs
@@ -3,6 +3,8 @@ use std::io::{self, Write};
use std::{io::ErrorKind, iter, process};

use anyhow::anyhow;
+
use clap::builder::styling::Style;
+
use clap::builder::Styles;
use clap::{CommandFactory, Parser, Subcommand};

use radicle::version;
@@ -14,6 +16,7 @@ use radicle_cli::terminal as term;
pub const NAME: &str = "rad";
pub const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const DESCRIPTION: &str = "Radicle command line interface";
+
pub const LONG_DESCRIPTION: &str = "Radicle is a distributed GIT forge.";
pub const GIT_HEAD: &str = env!("GIT_HEAD");
pub const TIMESTAMP: &str = env!("GIT_COMMIT_TIME");
pub const VERSION: Version = Version {
@@ -22,10 +25,28 @@ pub const VERSION: Version = Version {
    commit: GIT_HEAD,
    timestamp: TIMESTAMP,
};
+
pub const LONG_VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("GIT_HEAD"), ")");
+
pub const HELP_TEMPLATE: &str = r#"
+
{before-help}{bin} {version}
+
{about-with-newline}
+
Usage: {usage}

+
{all-args}
+
{after-help}
+
"#;
+

+
/// Radicle command line interface
+
///
+
/// Radicle is a distributed GIT forge.
#[derive(Parser, Debug)]
-
#[command(name = "rad")]
-
#[command(about = "The rad CLI", long_about = None)]
+
#[command(name = NAME)]
+
#[command(version = VERSION)]
+
#[command(long_version = LONG_VERSION)]
+
#[command(help_template = HELP_TEMPLATE)]
+
#[command(propagate_version = true)]
+
#[command(propagate_help_template = true)]
+
// #[command(styles = Styles::styled().usage(AnsiColor::Blue.on_default()))]
+
#[command(styles = Styles::plain().literal(Style::new().bold()))]
struct CliArgs {
    #[command(subcommand)]
    pub command: Option<Commands>,
@@ -33,6 +54,9 @@ struct CliArgs {

#[derive(Subcommand, Debug)]
enum Commands {
+
    /// Manage issues
+
    ///
+
    /// With issues you can organize your project and use it to discuss bugs and improvements.
    Issue(rad_issue::IssueArgs),
}