use std::option::Option;
use clap::{Parser, ValueEnum};
use crate::cmds::merge_request::{
CommentMergeRequestCliArgs, CommentMergeRequestListCliArgs, MergeRequestCliArgs,
MergeRequestGetCliArgs, MergeRequestListCliArgs, MergeRequestState,
};
use super::common::{validate_project_repo_path, CacheArgs, GetArgs, ListArgs};
#[derive(Parser)]
pub struct MergeRequestCommand {
#[clap(subcommand)]
subcommand: MergeRequestSubcommand,
}
#[derive(Parser)]
enum MergeRequestSubcommand {
#[clap(about = "Creates a merge request", visible_alias = "cr")]
Create(CreateMergeRequest),
#[clap(about = "Approve a merge request", visible_alias = "ap")]
Approve(ApproveMergeRequest),
#[clap(about = "Merge a merge request")]
Merge(MergeMergeRequest),
#[clap(about = "Git checkout a merge request branch for review")]
Checkout(CheckoutMergeRequest),
#[clap(
subcommand,
about = "Merge request comment operations",
visible_alias = "cm"
)]
Comment(CommentSubCommand),
#[clap(about = "Close a merge request")]
Close(CloseMergeRequest),
Get(GetMergeRequest),
#[clap(about = "List merge requests", visible_alias = "ls")]
List(ListMergeRequest),
}
#[derive(Parser)]
struct GetMergeRequest {
#[clap()]
id: i64,
#[clap(flatten)]
get_args: GetArgs,
}
#[derive(Parser)]
enum CommentSubCommand {
Create(CreateCommentMergeRequest),
List(ListCommentMergeRequest),
}
#[derive(Parser)]
struct CreateCommentMergeRequest {
#[clap(long)]
pub id: i64,
#[clap(group = "comment_msg")]
pub comment: Option<String>,
#[clap(long, value_name = "FILE", group = "comment_msg")]
pub comment_from_file: Option<String>,
}
#[derive(Parser)]
struct ListCommentMergeRequest {
#[clap()]
pub id: i64,
#[command(flatten)]
pub list_args: ListArgs,
}
#[derive(Parser)]
struct CreateMergeRequest {
#[clap(long, group = "title_msg")]
pub title: Option<String>,
#[clap(long, group = "title_msg", value_name = "SHA")]
pub title_from_commit: Option<String>,
#[clap(long)]
pub description: Option<String>,
#[clap(long, value_name = "FILE")]
pub description_from_file: Option<String>,
#[clap(long, short)]
pub auto: bool,
#[clap(long, value_name = "REMOTE_ALIAS")]
pub fetch: Option<String>,
#[clap(long, value_name = "REMOTE_ALIAS/BRANCH")]
pub rebase: Option<String>,
#[clap(long, value_name = "OWNER/PROJECT_NAME", value_parser=validate_project_repo_path, requires = "target_branch")]
pub target_repo: Option<String>,
#[clap(long)]
pub target_branch: Option<String>,
#[clap(long, short)]
pub browse: bool,
#[clap(long, short)]
pub yes: bool,
#[clap(long, value_name = "COMMIT_MSG")]
pub commit: Option<String>,
#[clap(long)]
pub amend: bool,
#[clap(long, short)]
pub force: bool,
#[clap(long, visible_alias = "wip")]
pub draft: bool,
#[clap(long)]
pub dry_run: bool,
#[clap(flatten)]
pub cache_args: CacheArgs,
}
#[derive(ValueEnum, Clone, PartialEq, Debug)]
pub enum MergeRequestStateStateCli {
Opened,
Closed,
Merged,
}
impl From<MergeRequestStateStateCli> for MergeRequestState {
fn from(state: MergeRequestStateStateCli) -> Self {
match state {
MergeRequestStateStateCli::Opened => MergeRequestState::Opened,
MergeRequestStateStateCli::Closed => MergeRequestState::Closed,
MergeRequestStateStateCli::Merged => MergeRequestState::Merged,
}
}
}
#[derive(Parser)]
pub struct ListMergeRequest {
#[clap()]
pub state: MergeRequestStateStateCli,
#[command(flatten)]
pub list_args: ListArgs,
}
#[derive(Parser)]
struct MergeMergeRequest {
#[clap()]
pub id: i64,
}
#[derive(Parser)]
struct CheckoutMergeRequest {
#[clap()]
pub id: i64,
}
#[derive(Parser)]
struct CloseMergeRequest {
#[clap()]
pub id: i64,
}
#[derive(Parser)]
struct ApproveMergeRequest {
#[clap()]
pub id: i64,
}
impl From<ListMergeRequest> for MergeRequestOptions {
fn from(options: ListMergeRequest) -> Self {
MergeRequestOptions::List(MergeRequestListCliArgs::new(
options.state.into(),
options.list_args.into(),
))
}
}
impl From<MergeMergeRequest> for MergeRequestOptions {
fn from(options: MergeMergeRequest) -> Self {
MergeRequestOptions::Merge { id: options.id }
}
}
impl From<CheckoutMergeRequest> for MergeRequestOptions {
fn from(options: CheckoutMergeRequest) -> Self {
MergeRequestOptions::Checkout { id: options.id }
}
}
impl From<CloseMergeRequest> for MergeRequestOptions {
fn from(options: CloseMergeRequest) -> Self {
MergeRequestOptions::Close { id: options.id }
}
}
impl From<ApproveMergeRequest> for MergeRequestOptions {
fn from(options: ApproveMergeRequest) -> Self {
MergeRequestOptions::Approve { id: options.id }
}
}
impl From<MergeRequestCommand> for MergeRequestOptions {
fn from(options: MergeRequestCommand) -> Self {
match options.subcommand {
MergeRequestSubcommand::Create(options) => options.into(),
MergeRequestSubcommand::List(options) => options.into(),
MergeRequestSubcommand::Merge(options) => options.into(),
MergeRequestSubcommand::Checkout(options) => options.into(),
MergeRequestSubcommand::Close(options) => options.into(),
MergeRequestSubcommand::Comment(options) => options.into(),
MergeRequestSubcommand::Get(options) => options.into(),
MergeRequestSubcommand::Approve(options) => options.into(),
}
}
}
impl From<CommentSubCommand> for MergeRequestOptions {
fn from(options: CommentSubCommand) -> Self {
match options {
CommentSubCommand::Create(options) => options.into(),
CommentSubCommand::List(options) => options.into(),
}
}
}
impl From<CreateMergeRequest> for MergeRequestOptions {
fn from(options: CreateMergeRequest) -> Self {
MergeRequestOptions::Create(
MergeRequestCliArgs::builder()
.title(options.title)
.title_from_commit(options.title_from_commit)
.description(options.description)
.description_from_file(options.description_from_file)
.target_branch(options.target_branch)
.target_repo(options.target_repo)
.fetch(options.fetch)
.rebase(options.rebase)
.auto(options.auto)
.cache_args(options.cache_args.into())
.open_browser(options.browse)
.accept_summary(options.yes)
.commit(options.commit)
.draft(options.draft)
.amend(options.amend)
.force(options.force)
.dry_run(options.dry_run)
.build()
.unwrap(),
)
}
}
impl From<ListCommentMergeRequest> for MergeRequestOptions {
fn from(options: ListCommentMergeRequest) -> Self {
MergeRequestOptions::ListComment(
CommentMergeRequestListCliArgs::builder()
.id(options.id)
.list_args(options.list_args.into())
.build()
.unwrap(),
)
}
}
impl From<CreateCommentMergeRequest> for MergeRequestOptions {
fn from(options: CreateCommentMergeRequest) -> Self {
MergeRequestOptions::CreateComment(
CommentMergeRequestCliArgs::builder()
.id(options.id)
.comment(options.comment)
.comment_from_file(options.comment_from_file)
.build()
.unwrap(),
)
}
}
impl From<GetMergeRequest> for MergeRequestOptions {
fn from(options: GetMergeRequest) -> Self {
MergeRequestOptions::Get(
MergeRequestGetCliArgs::builder()
.id(options.id)
.get_args(options.get_args.into())
.build()
.unwrap(),
)
}
}
pub enum MergeRequestOptions {
Create(MergeRequestCliArgs),
Get(MergeRequestGetCliArgs),
List(MergeRequestListCliArgs),
CreateComment(CommentMergeRequestCliArgs),
ListComment(CommentMergeRequestListCliArgs),
Approve { id: i64 },
Merge { id: i64 },
Checkout { id: i64 },
Close { id: i64 },
}
#[cfg(test)]
mod test {
use crate::cli::{Args, Command};
use super::*;
#[test]
fn test_list_merge_requests_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "list", "opened"]);
let list_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::List(options),
}) => {
assert_eq!(options.state, MergeRequestStateStateCli::Opened);
options
}
_ => panic!("Expected MergeRequestCommand::List"),
};
let options: MergeRequestOptions = list_merge_request.into();
match options {
MergeRequestOptions::List(args) => {
assert_eq!(args.state, MergeRequestState::Opened);
}
_ => panic!("Expected MergeRequestOptions::List"),
}
}
#[test]
fn test_merge_merge_request_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "merge", "123"]);
let merge_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Merge(options),
}) => {
assert_eq!(options.id, 123);
options
}
_ => panic!("Expected MergeRequestCommand::Merge"),
};
let options: MergeRequestOptions = merge_merge_request.into();
match options {
MergeRequestOptions::Merge { id } => {
assert_eq!(id, 123);
}
_ => panic!("Expected MergeRequestOptions::Merge"),
}
}
#[test]
fn test_checkout_merge_request_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "checkout", "123"]);
let checkout_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Checkout(options),
}) => {
assert_eq!(options.id, 123);
options
}
_ => panic!("Expected MergeRequestCommand::Checkout"),
};
let options: MergeRequestOptions = checkout_merge_request.into();
match options {
MergeRequestOptions::Checkout { id } => {
assert_eq!(id, 123);
}
_ => panic!("Expected MergeRequestOptions::Checkout"),
}
}
#[test]
fn test_close_merge_request_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "close", "123"]);
let close_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Close(options),
}) => {
assert_eq!(options.id, 123);
options
}
_ => panic!("Expected MergeRequestCommand::Close"),
};
let options: MergeRequestOptions = close_merge_request.into();
match options {
MergeRequestOptions::Close { id } => {
assert_eq!(id, 123);
}
_ => panic!("Expected MergeRequestOptions::Close"),
}
}
#[test]
fn test_comment_merge_request_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "comment", "create", "--id", "123", "LGTM"]);
let comment_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Comment(options),
}) => match options {
CommentSubCommand::Create(args) => {
assert_eq!(args.id, 123);
assert_eq!(args.comment, Some("LGTM".to_string()));
args
}
_ => panic!("Expected CommentSubCommand::Create"),
},
_ => panic!("Expected MergeRequestCommand::Comment"),
};
let options: MergeRequestOptions = comment_merge_request.into();
match options {
MergeRequestOptions::CreateComment(args) => {
assert_eq!(args.id, 123);
assert_eq!(args.comment, Some("LGTM".to_string()));
}
_ => panic!("Expected MergeRequestOptions::Comment"),
}
}
#[test]
fn test_list_all_comments_in_merge_request_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "comment", "list", "123"]);
let list_comment_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Comment(options),
}) => match options {
CommentSubCommand::List(args) => {
assert_eq!(args.id, 123);
args
}
_ => panic!("Expected CommentSubCommand::List"),
},
_ => panic!("Expected MergeRequestCommand::Comment"),
};
let options: MergeRequestOptions = list_comment_merge_request.into();
match options {
MergeRequestOptions::ListComment(args) => {
assert_eq!(args.id, 123);
}
_ => panic!("Expected MergeRequestOptions::ListComment"),
}
}
#[test]
fn test_create_merge_request_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "create", "--auto", "-y", "--browse"]);
let create_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Create(options),
}) => {
assert!(options.auto);
assert!(options.yes);
assert!(options.browse);
options
}
_ => panic!("Expected MergeRequestCommand::Create"),
};
let options: MergeRequestOptions = create_merge_request.into();
match options {
MergeRequestOptions::Create(args) => {
assert!(args.auto);
assert!(args.accept_summary);
assert!(args.open_browser);
}
_ => panic!("Expected MergeRequestOptions::Create"),
}
}
#[test]
fn test_get_merge_request_details_cli_args() {
let args = Args::parse_from(vec!["gr", "mr", "get", "123"]);
let get_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Get(options),
}) => {
assert_eq!(options.id, 123);
options
}
_ => panic!("Expected MergeRequestCommand::Get"),
};
let options: MergeRequestOptions = get_merge_request.into();
match options {
MergeRequestOptions::Get(args) => {
assert_eq!(args.id, 123);
}
_ => panic!("Expected MergeRequestOptions::Get"),
}
}
#[test]
fn test_wip_alias_as_draft() {
let args = Args::parse_from(vec!["gr", "mr", "create", "--auto", "--wip"]);
let create_merge_request = match args.command {
Command::MergeRequest(MergeRequestCommand {
subcommand: MergeRequestSubcommand::Create(options),
}) => {
assert!(options.draft);
options
}
_ => panic!("Expected MergeRequestCommand::Create"),
};
let options: MergeRequestOptions = create_merge_request.into();
match options {
MergeRequestOptions::Create(args) => {
assert!(args.draft);
}
_ => panic!("Expected MergeRequestOptions::Create"),
}
}
}