gr/cli/
my.rs

1use clap::Parser;
2
3use crate::cmds::{
4    gist::GistListCliArgs,
5    merge_request::{MergeRequestListCliArgs, MergeRequestUser},
6    project::ProjectListCliArgs,
7};
8
9use super::{common::ListArgs, merge_request::ListMergeRequest, project::ListProject};
10
11#[derive(Parser)]
12pub struct MyCommand {
13    #[clap(subcommand)]
14    subcommand: MySubcommand,
15}
16
17#[derive(Parser)]
18enum MySubcommand {
19    #[clap(
20        about = "Lists the merge requests where you are the author, assignee or the reviewer",
21        name = "mr"
22    )]
23    MergeRequest(ListMyMergeRequest),
24    #[clap(about = "Lists your projects", name = "pj")]
25    Project(ListProject),
26    #[clap(about = "Lists your starred projects", name = "st")]
27    Star(ListStar),
28    #[clap(about = "Lists your gists", name = "gs")]
29    Gist(ListGist),
30}
31
32#[derive(Parser)]
33struct ListMyMergeRequest {
34    /// Filter merge requests where you are the assignee. Gitlab and Github.
35    #[clap(long, group = "merge_request")]
36    assignee: bool,
37    /// Filter merge requests where you are the author. Default if none
38    /// provided. Gitlab and Github.
39    #[clap(long, group = "merge_request")]
40    author: bool,
41    /// Filter merge requests where you are the reviewer. Gitlab only.
42    #[clap(long, group = "merge_request")]
43    reviewer: bool,
44    #[clap(flatten)]
45    list_merge_request: ListMergeRequest,
46}
47
48pub enum MyOptions {
49    MergeRequest(MergeRequestListCliArgs),
50    Project(ProjectListCliArgs),
51    Gist(GistListCliArgs),
52}
53
54impl From<MyCommand> for MyOptions {
55    fn from(options: MyCommand) -> Self {
56        match options.subcommand {
57            MySubcommand::MergeRequest(options) => options.into(),
58            MySubcommand::Project(options) => options.into(),
59            MySubcommand::Star(options) => options.into(),
60            MySubcommand::Gist(options) => options.into(),
61        }
62    }
63}
64
65impl From<ListMyMergeRequest> for MyOptions {
66    fn from(options: ListMyMergeRequest) -> Self {
67        MyOptions::MergeRequest(
68            MergeRequestListCliArgs::builder()
69                .state(options.list_merge_request.state.into())
70                .list_args(options.list_merge_request.list_args.into())
71                .assignee(if options.assignee {
72                    Some(MergeRequestUser::Me)
73                } else {
74                    None
75                })
76                // Author is the default if none is provided.
77                .author(
78                    if options.author || (!options.assignee && !options.reviewer) {
79                        Some(MergeRequestUser::Me)
80                    } else {
81                        None
82                    },
83                )
84                .reviewer(if options.reviewer {
85                    Some(MergeRequestUser::Me)
86                } else {
87                    None
88                })
89                .build()
90                .unwrap(),
91        )
92    }
93}
94
95impl From<ListProject> for MyOptions {
96    fn from(options: ListProject) -> Self {
97        MyOptions::Project(
98            ProjectListCliArgs::builder()
99                .list_args(options.list_args.into())
100                .build()
101                .unwrap(),
102        )
103    }
104}
105
106#[derive(Parser)]
107pub struct ListStar {
108    #[clap(flatten)]
109    pub list_args: ListArgs,
110}
111
112impl From<ListStar> for MyOptions {
113    fn from(options: ListStar) -> Self {
114        MyOptions::Project(
115            ProjectListCliArgs::builder()
116                .list_args(options.list_args.into())
117                .stars(true)
118                .build()
119                .unwrap(),
120        )
121    }
122}
123
124#[derive(Parser)]
125pub struct ListGist {
126    #[clap(flatten)]
127    pub list_args: ListArgs,
128}
129
130impl From<ListGist> for MyOptions {
131    fn from(options: ListGist) -> Self {
132        MyOptions::Gist(
133            GistListCliArgs::builder()
134                .list_args(options.list_args.into())
135                .build()
136                .unwrap(),
137        )
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use crate::{
145        cli::{merge_request::MergeRequestStateStateCli, Args, Command},
146        cmds::merge_request::MergeRequestState,
147    };
148
149    #[test]
150    fn test_my_merge_request_cli_args() {
151        let args = Args::parse_from(vec!["gr", "my", "mr", "opened"]);
152        let my_command = match args.command {
153            Command::My(MyCommand {
154                subcommand: MySubcommand::MergeRequest(options),
155            }) => {
156                assert_eq!(
157                    options.list_merge_request.state,
158                    MergeRequestStateStateCli::Opened
159                );
160                options
161            }
162            _ => panic!("Expected MyCommand"),
163        };
164        let options: MyOptions = my_command.into();
165        match options {
166            MyOptions::MergeRequest(options) => {
167                assert_eq!(options.state, MergeRequestState::Opened);
168                assert_eq!(options.author, Some(MergeRequestUser::Me));
169            }
170            _ => panic!("Expected MyOptions::MergeRequest"),
171        }
172    }
173
174    #[test]
175    fn test_my_merge_request_cli_args_reviewer() {
176        let args = Args::parse_from(vec!["gr", "my", "mr", "opened", "--reviewer"]);
177        let my_command = match args.command {
178            Command::My(MyCommand {
179                subcommand: MySubcommand::MergeRequest(options),
180            }) => {
181                assert_eq!(
182                    options.list_merge_request.state,
183                    MergeRequestStateStateCli::Opened
184                );
185                assert!(options.reviewer);
186                options
187            }
188            _ => panic!("Expected MyCommand"),
189        };
190        let options: MyOptions = my_command.into();
191        match options {
192            MyOptions::MergeRequest(options) => {
193                assert_eq!(options.state, MergeRequestState::Opened);
194                assert_eq!(options.reviewer, Some(MergeRequestUser::Me));
195            }
196            _ => panic!("Expected MyOptions::MergeRequest"),
197        }
198    }
199
200    #[test]
201    fn test_my_merge_request_cli_args_author() {
202        let args = Args::parse_from(vec!["gr", "my", "mr", "opened", "--author"]);
203        let my_command = match args.command {
204            Command::My(MyCommand {
205                subcommand: MySubcommand::MergeRequest(options),
206            }) => {
207                assert_eq!(
208                    options.list_merge_request.state,
209                    MergeRequestStateStateCli::Opened
210                );
211                assert!(options.author);
212                options
213            }
214            _ => panic!("Expected MyCommand"),
215        };
216        let options: MyOptions = my_command.into();
217        match options {
218            MyOptions::MergeRequest(options) => {
219                assert_eq!(options.state, MergeRequestState::Opened);
220                assert_eq!(options.author, Some(MergeRequestUser::Me));
221            }
222            _ => panic!("Expected MyOptions::MergeRequest"),
223        }
224    }
225
226    #[test]
227    fn test_my_merge_request_cli_args_assignee() {
228        let args = Args::parse_from(vec!["gr", "my", "mr", "opened", "--assignee"]);
229        let my_command = match args.command {
230            Command::My(MyCommand {
231                subcommand: MySubcommand::MergeRequest(options),
232            }) => {
233                assert_eq!(
234                    options.list_merge_request.state,
235                    MergeRequestStateStateCli::Opened
236                );
237                assert!(options.assignee);
238                options
239            }
240            _ => panic!("Expected MyCommand"),
241        };
242        let options: MyOptions = my_command.into();
243        match options {
244            MyOptions::MergeRequest(options) => {
245                assert_eq!(options.state, MergeRequestState::Opened);
246                assert_eq!(options.assignee, Some(MergeRequestUser::Me));
247            }
248            _ => panic!("Expected MyOptions::MergeRequest"),
249        }
250    }
251
252    #[test]
253    fn test_my_projects_cli_args() {
254        let args = Args::parse_from(vec!["gr", "my", "pj"]);
255        let my_command = match args.command {
256            Command::My(MyCommand {
257                subcommand: MySubcommand::Project(options),
258            }) => options,
259            _ => panic!("Expected MyCommand"),
260        };
261        let options: MyOptions = my_command.into();
262        match options {
263            MyOptions::Project(_) => {}
264            _ => panic!("Expected MyOptions::Project"),
265        }
266    }
267
268    #[test]
269    fn test_my_stars_cli_args() {
270        let args = Args::parse_from(vec!["gr", "my", "st"]);
271        let my_command = match args.command {
272            Command::My(MyCommand {
273                subcommand: MySubcommand::Star(options),
274            }) => options,
275            _ => panic!("Expected MyCommand"),
276        };
277        let options: MyOptions = my_command.into();
278        match options {
279            MyOptions::Project(_) => {}
280            _ => panic!("Expected MyOptions::Star"),
281        }
282    }
283
284    #[test]
285    fn test_my_gists_cli_args() {
286        let args = Args::parse_from(vec!["gr", "my", "gs"]);
287        let my_command = match args.command {
288            Command::My(MyCommand {
289                subcommand: MySubcommand::Gist(options),
290            }) => options,
291            _ => panic!("Expected MyCommand"),
292        };
293        let options: MyOptions = my_command.into();
294        match options {
295            MyOptions::Gist(_) => {}
296            _ => panic!("Expected MyOptions::Gist"),
297        }
298    }
299}