jirust_cli/args/
commands.rs

1use crate::jira_doc_std_field;
2use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum};
3use regex::Regex;
4use serde::{Deserialize, Serialize};
5use std::error::Error;
6
7/// Command line arguments base
8/// subcommands: Config, Version
9#[derive(Parser, Debug)]
10#[command(author, version, about, long_about = None)]
11pub struct JirustCliArgs {
12    /// Subcommands
13    #[clap(subcommand)]
14    pub subcmd: Commands,
15}
16
17/// Available CLI commands
18/// Config, Issue, Project, Transition, Version
19#[derive(Subcommand, Clone, Debug, Serialize, Deserialize)]
20pub enum Commands {
21    /// Configuration management
22    Config(ConfigArgs),
23    /// Issue management
24    Issue(IssueArgs),
25    /// Issue links management
26    Link(LinkIssueArgs),
27    /// Project management
28    Project(ProjectArgs),
29    /// Transition management
30    Transition(TransitionArgs),
31    /// Version management
32    Version(VersionArgs),
33}
34
35/// Available pagination command line arguments
36///
37/// * page_size: Option<i32>
38/// * page_offset: Option<i64>
39#[derive(Args, Clone, Debug, Serialize, Deserialize)]
40pub struct PaginationArgs {
41    /// page size for lists
42    #[clap(
43        long,
44        short = 'l',
45        value_name = "page_size",
46        help = "page size for lists"
47    )]
48    pub page_size: Option<i32>,
49    /// page offset for list
50    #[clap(
51        long,
52        short = 's',
53        value_name = "page_offset",
54        help = "page offset for list"
55    )]
56    pub page_offset: Option<i64>,
57}
58
59/// Available output values
60/// Table, Json
61///
62/// * Table: Print output in table format
63/// * Json: Print output in json format
64#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
65#[value(rename_all = "kebab-case")]
66pub enum OutputValues {
67    /// Print output in table format
68    #[value(name = "table", help = "Print output in table format")]
69    Table,
70    /// Print output in json format
71    #[value(name = "json", help = "Print output in json format")]
72    Json,
73}
74
75/// Available output types
76/// Table, Json
77///
78/// * Basic: Print basic output
79/// * Single: Print single row output
80/// * Full: Print full output
81#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
82#[value(rename_all = "kebab-case")]
83pub enum OutputTypes {
84    /// Print basic output
85    #[value(name = "basic", help = "Print basic output")]
86    Basic,
87    /// Print single row output
88    #[value(name = "single", help = "Print single row output")]
89    Single,
90    /// Print full output
91    #[value(name = "full", help = "Print full output")]
92    Full,
93}
94
95/// Available output values
96///
97/// * output: Option<OutputValues> - Output format
98#[derive(Args, Clone, Debug, Serialize, Deserialize)]
99pub struct OutputArgs {
100    /// Output format
101    #[clap(long, short = 'o', value_name = "table|json", help = "Output format")]
102    pub output_format: Option<OutputValues>,
103    /// Output type
104    #[clap(
105        long,
106        short = 'z',
107        value_name = "basic|single|full",
108        help = "Output type"
109    )]
110    pub output_type: Option<OutputTypes>,
111}
112
113/// Available configuration command line arguments
114/// cfg_act: ConfigActionValues
115///    Auth, Jira, Setup, Show
116#[derive(Args, Clone, Debug, Serialize, Deserialize)]
117pub struct ConfigArgs {
118    /// Configuration action
119    #[arg(
120        value_name = "auth|jira|setup|show",
121        help_heading = "Configuration management"
122    )]
123    pub cfg_act: ConfigActionValues,
124}
125
126/// Available configuration action values
127/// Auth, Jira, Setup, Show
128///
129/// * Auth: Set Jira API authentication (username, apikey)
130/// * Jira: Set Jira API base URL
131/// * Setup: Setup Jira API configuration (authentication data, jira base URL, etc.)
132/// * Show: Show current configuration
133#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
134#[value(rename_all = "kebab-case")]
135pub enum ConfigActionValues {
136    /// Set Jira API authentication (username, apikey)
137    #[value(name = "auth", help = "Set Jira API authentication (username, apikey)")]
138    Auth,
139    /// Set Jira API base URL
140    #[value(name = "jira", help = "Set Jira API base URL")]
141    Jira,
142    /// Setup Jira API configuration (authentication data, jira base URL, etc.)
143    #[value(
144        name = "setup",
145        help = "Setup Jira API configuration (authentication data, jira base URL, etc.)"
146    )]
147    Setup,
148    /// Show current configuration
149    #[value(name = "show", help = "Show current configuration")]
150    Show,
151}
152
153/// Available version command line arguments
154/// * version_act: VersionActionValues - Version action
155/// * project_key: String - Jira Project key
156/// * project_id: Option<i64> - Jira Project ID
157/// * version_id: Option<String> - Jira Project version ID
158/// * version_name: Option<String> - Jira Project version name
159/// * version_description: Option<String> - Jira Project version description
160/// * version_start_date: Option<String> - Jira Project version start date
161/// * version_release_date: Option<String> - Jira Project version release date
162/// * version_archived: Option<bool> - Jira Project version archived
163/// * version_released: Option<bool> - Jira Project version released
164/// * changelog_file: Option<String> - Jira Project version changelog file
165/// * transition_issues: Option<bool> - Jira Project version automatically transition issues in changelog
166/// * transition_assignee: Option<String> - Jira Project version transition assignee
167/// * pagination: PaginationArgs - Jira Project version pagination
168/// * output: OutputArgs - Jira Project version actions result output format
169///
170#[derive(Args, Clone, Debug, Serialize, Deserialize)]
171pub struct VersionArgs {
172    /// Version action
173    #[arg(
174        value_name = "archive|create|delete|list|release|update",
175        help_heading = "Jira Project version management"
176    )]
177    pub version_act: VersionActionValues,
178    /// Jira Project key
179    #[clap(
180        long,
181        short = 'k',
182        value_name = "project_key",
183        required = true,
184        help = "Jira Project key"
185    )]
186    pub project_key: String,
187    /// Jira Project ID
188    #[clap(long, short = 'i', value_name = "project_id", help = "Jira Project ID")]
189    pub project_id: Option<i64>,
190    /// Jira Project version ID
191    #[clap(
192        long,
193        short = 'v',
194        value_name = "version_id",
195        help = "Jira Project version ID"
196    )]
197    pub version_id: Option<String>,
198    /// Jira Project version name
199    #[clap(
200        long,
201        short = 'n',
202        value_name = "version_name",
203        help = "Jira Project version name"
204    )]
205    pub version_name: Option<String>,
206    /// Jira Project version description
207    #[clap(
208        long,
209        short = 'd',
210        value_name = "version_description",
211        help = "Jira Project version description"
212    )]
213    pub version_description: Option<String>,
214    /// Jira Project version start date
215    #[clap(
216        long,
217        value_name = "version_start_date",
218        help = "Jira Project version start date"
219    )]
220    pub version_start_date: Option<String>,
221    /// Jira Project version release date
222    #[clap(
223        long,
224        value_name = "version_release_date",
225        help = "Jira Project version release date"
226    )]
227    pub version_release_date: Option<String>,
228    /// Jira Project version archived
229    #[clap(
230        long,
231        short = 'a',
232        value_name = "version_archived",
233        help = "Jira Project version archived"
234    )]
235    pub version_archived: Option<bool>,
236    /// Jira Project version released
237    #[clap(
238        long,
239        short = 'm',
240        action = ArgAction::SetTrue,
241        value_name = "version_released",
242        help = "Jira Project version released"
243    )]
244    pub version_released: Option<bool>,
245    /// Jira Project version changelog file
246    #[clap(
247        long,
248        short = 'c',
249        value_name = "changelog_file",
250        help = "changelog file path to be used for automatic description generation (if set the script detects automatically the first tagged block in the changelog and use it as description)"
251    )]
252    pub changelog_file: Option<String>,
253    /// Jira Project version automatically transition issues in changelog
254    #[clap(
255        long,
256        short = 'r',
257        action = ArgAction::SetTrue,
258        value_name = "resolve_issues",
259        help = "if changelog is set and this flag is set, the script will transition all issues in the changelog of the current version release to the \"resolved\" status setting the version as \"fixVersion\""
260    )]
261    pub transition_issues: Option<bool>,
262    /// Jira Project version transition assignee
263    #[clap(
264        long,
265        short = 'u',
266        value_name = "transition_assignee",
267        help = "if changelog is set and the resolve_issues flag is set, the script will assigned all the resolved issue to the user specified in this field (if not set the assignee will not be changed)"
268    )]
269    pub transition_assignee: Option<String>,
270    /// Jira Project version pagination
271    #[clap(flatten)]
272    pub pagination: PaginationArgs,
273    /// Jira Project version actions result output format
274    #[clap(flatten)]
275    pub output: OutputArgs,
276}
277
278/// Available version action values
279/// Archive, Create, Delete, List, Release, Update
280///
281/// * Archive: Archive a Jira Project version
282/// * Create: Create a Jira Project version
283/// * Delete: Delete a Jira Project version
284/// * List: List Jira Project versions
285/// * Release: Release a Jira Project version
286/// * Update: Update a Jira Project version
287#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
288#[value(rename_all = "kebab-case")]
289pub enum VersionActionValues {
290    /// Archive a Jira Project version
291    #[value(name = "archive", help = "Archive a Jira Project version")]
292    Archive,
293    /// Create a Jira Project version
294    #[value(name = "create", help = "Create a Jira Project version")]
295    Create,
296    /// Delete a Jira Project version
297    #[value(name = "delete", help = "Delete a Jira Project version")]
298    Delete,
299    /// List Jira Project versions
300    #[value(name = "list", help = "List Jira Project versions")]
301    List,
302    /// Release a Jira Project version
303    #[value(name = "release", help = "Release a Jira Project version")]
304    Release,
305    /// Update a Jira Project version
306    #[value(name = "update", help = "Update a Jira Project version")]
307    Update,
308}
309
310/// Available project command line arguments
311///
312/// * project_act: ProjectActionValues - Project action
313/// * project_key: Option<String> - Jira Project key
314/// * project_issue_type: Option<String> - Jira Project issue type ID
315/// * project_name: Option<String> - Jira Project name
316/// * project_description: Option<String> - Jira Project description
317/// * project_field_configuration_id: Option<i64> - Jira Project field configuration ID
318/// * project_issue_security_scheme_id: Option<i64> - Jira Project issue security scheme ID
319/// * project_permission_scheme_id: Option<i64> - Jira Project permission scheme ID
320/// * project_issue_type_scheme_id: Option<i64> - Jira Project issue type scheme ID
321/// * project_issue_type_screen_scheme_id: Option<i64> - Jira Project issue type screen scheme ID
322/// * project_notification_scheme_id: Option<i64> - Jira Project notification scheme ID
323/// * project_workflow_scheme_id: Option<i64> - Jira Project workflow scheme ID
324/// * project_lead_account_id: Option<String> - Jira Project lead account ID
325/// * project_assignee_type: Option<String> - Jira Project assignee type
326/// * pagination: PaginationArgs - Jira Project pagination
327/// * output: OutputArgs - Jira Project actions result output format
328#[derive(Args, Clone, Debug, Serialize, Deserialize)]
329pub struct ProjectArgs {
330    /// Project action
331    #[arg(
332        value_name = "create|get-issue-types|get-issue-type-fields|list",
333        help_heading = "Jira Project management",
334        required = true
335    )]
336    pub project_act: ProjectActionValues,
337    /// Jira Project key
338    #[clap(
339        long,
340        short = 'k',
341        value_name = "project_key",
342        help = "Jira Project key"
343    )]
344    pub project_key: Option<String>,
345    /// Jira Project issue type ID
346    #[clap(
347        long,
348        short = 'i',
349        value_name = "project_issue_type",
350        help = "Jira Project issue type ID"
351    )]
352    pub project_issue_type: Option<String>,
353    /// Jira Project name
354    #[clap(long, value_name = "project_name", help = "Jira Project name")]
355    pub project_name: Option<String>,
356    /// Jira Project description
357    #[clap(
358        long,
359        value_name = "project_description",
360        help = "Jira Project description"
361    )]
362    pub project_description: Option<String>,
363    /// Jira Project field configuration ID
364    #[clap(
365        long,
366        value_name = "project_field_configuration_id",
367        help = "Jira Project field configuration ID"
368    )]
369    pub project_field_configuration_id: Option<i64>,
370    /// Jira Project issue security scheme ID
371    #[clap(
372        long,
373        value_name = "project_issue_security_scheme_id",
374        help = "Jira Project issue security scheme ID"
375    )]
376    pub project_issue_security_scheme_id: Option<i64>,
377    /// Jira Project issue type scheme ID
378    #[clap(
379        long,
380        value_name = "project_issue_type_scheme_id",
381        help = "Jira Project issue type scheme ID"
382    )]
383    pub project_issue_type_scheme_id: Option<i64>,
384    /// Jira Project issue type screen scheme ID
385    #[clap(
386        long,
387        value_name = "project_issue_type_screen_scheme_id",
388        help = "Jira Project issue type screen scheme ID"
389    )]
390    pub project_issue_type_screen_scheme_id: Option<i64>,
391    /// Jira Project notification scheme ID
392    #[clap(
393        long,
394        value_name = "project_notification_scheme_id",
395        help = "Jira Project notification scheme ID"
396    )]
397    pub project_notification_scheme_id: Option<i64>,
398    /// Jira Project permission scheme ID
399    #[clap(
400        long,
401        value_name = "project_permission_scheme_id",
402        help = "Jira Project permission scheme ID"
403    )]
404    pub project_permission_scheme_id: Option<i64>,
405    // Jira project workflow scheme ID
406    #[clap(
407        long,
408        value_name = "project_workflow_scheme_id",
409        help = "Jira Project workflow scheme ID"
410    )]
411    pub project_workflow_scheme_id: Option<i64>,
412    /// Jira Project lead account ID
413    #[clap(
414        long,
415        value_name = "project_lead_account_id",
416        help = "Jira Project lead account ID"
417    )]
418    pub project_lead_account_id: Option<String>,
419    /// Jira Project Assignee Type
420    #[clap(
421        long,
422        value_name = "project_assignee_type",
423        help = "Jira Project Assignee Type"
424    )]
425    pub project_assignee_type: Option<String>,
426    /// Jira Project pagination
427    #[clap(flatten)]
428    pub pagination: PaginationArgs,
429    /// Jira Project actions result output format
430    #[clap(flatten)]
431    pub output: OutputArgs,
432}
433
434/// Available project action values
435///
436/// * Create: Create new Jira Project
437/// * GetIssueTypes: Get Jira Project issue types by Jira project key
438/// * GetIssueTypeFields: Get Jira Project issue type fields by Jira project key and issue type ID
439/// * List: List Jira Projects
440#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
441#[value(rename_all = "kebab-case")]
442pub enum ProjectActionValues {
443    /// Create new Jira Project
444    #[value(name = "create", help = "Create new Jira Project")]
445    Create,
446    /// Get Jira Project issue types by Jira project key
447    #[value(
448        name = "get-issue-types",
449        help = "Get Jira Project issue types by Jira project key"
450    )]
451    GetIssueTypes,
452    /// Get Jira Project issue type fields by Jira project key and issue type ID
453    #[value(
454        name = "get-issue-type-fields",
455        help = "Get Jira Project issue type fields by Jira project key and issue type ID"
456    )]
457    GetIssueTypeFields,
458    /// List Jira Projects
459    #[value(name = "list", help = "List Jira Projects")]
460    List,
461}
462
463/// Available issue command line arguments
464///
465/// * issue_act: IssueActionValues - Issue action
466/// * project_key: String - Jira Project key
467/// * issue_key: Option<String> - Jira Project issue key
468/// * issue_fields: Option<Vec<(String, String)>> - Jira Project issue fields
469/// * transition_to: Option<String> - Jira Project issue transition to
470/// * assignee: Option<String> - Jira Project issue assignee
471/// * pagination: PaginationArgs - Jira Project issue pagination
472/// * output: OutputArgs - Jira Project issue actions result output format
473#[derive(Args, Clone, Debug, Serialize, Deserialize)]
474pub struct IssueArgs {
475    /// Issue action
476    #[arg(
477        value_name = "assign|create|delete|get|transition|update",
478        help_heading = "Jira Project issue management",
479        required = true
480    )]
481    pub issue_act: IssueActionValues,
482    /// Jira Project key
483    #[clap(
484        long,
485        short = 'p',
486        value_name = "project_key",
487        help = "Jira Project key",
488        required = true
489    )]
490    pub project_key: String,
491    /// Jira Project issue key
492    #[clap(
493        long,
494        short = 'i',
495        value_name = "issue_key",
496        help = "Jira Project issue key"
497    )]
498    pub issue_key: Option<String>,
499    /// Jira Project issue fields
500    #[clap(long,
501        short = 'f',
502        value_name = "issue_fields",
503        value_parser = parse_key_val::<String, String>,
504        help = "Jira Project issue fields (field_name=value)")]
505    pub issue_fields: Option<Vec<(String, String)>>,
506    /// Jira Project issue transition
507    #[clap(
508        long,
509        short = 't',
510        value_name = "transition_to",
511        help = "Jira Project issue transition to"
512    )]
513    pub transition_to: Option<String>,
514    /// Jira Project issue assignee
515    #[clap(
516        long,
517        short = 'a',
518        value_name = "assignee",
519        help = "Jira Project issue assignee"
520    )]
521    pub assignee: Option<String>,
522    /// Jira Project issue pagination
523    #[clap(flatten)]
524    pub pagination: PaginationArgs,
525    /// Jira Project issue actions result output format
526    #[clap(flatten)]
527    pub output: OutputArgs,
528}
529
530/// Available issue action values
531///
532/// * Assign: Assign a Jira Project issue
533/// * Create: Create a Jira Project issue
534/// * Delete: Delete a Jira Project issue
535/// * Get: Get a specific Jira Project issue
536/// * Transition: Transition a Jira Project issue
537/// * Update: Update a Jira Project issue
538#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
539#[value(rename_all = "kebab-case")]
540pub enum IssueActionValues {
541    /// Assign a Jira Project issue
542    #[value(name = "assign", help = "Assign a Jira Project issue")]
543    Assign,
544    /// Create a Jira Project issue
545    #[value(name = "create", help = "Create a Jira Project issue")]
546    Create,
547    /// Delete a Jira Project issue
548    #[value(name = "delete", help = "Delete a Jira Project issue")]
549    Delete,
550    /// Get a specific Jira Project issue
551    #[value(name = "get", help = "Get a specific Jira Project issue")]
552    Get,
553    /// Transition a Jira Project issue
554    #[value(name = "transition", help = "Transition a Jira Project issue")]
555    Transition,
556    /// Update a Jira Project issue
557    #[value(name = "update", help = "Update a Jira Project issue")]
558    Update,
559}
560
561/// Available issues' links command line arguments
562///
563/// * link_act: LinkIssueActionValues - Jira link issue command available actions
564/// * project_key: Option<String> - Jira Project key
565/// * origin_issue_key: String - Jira origin issue link key
566/// * destination_issue_key: Option<String> - Jira destination issue link key
567/// * link_type: String - Jira issue link type
568/// * changelog_file: Option<String> - Jira Project version changelog file
569#[derive(Args, Clone, Debug, Serialize, Deserialize)]
570pub struct LinkIssueArgs {
571    // Jira link issue command available actions
572    #[arg(
573        value_name = "create",
574        help_heading = "Jira issues links management",
575        required = true
576    )]
577    pub link_act: LinkIssueActionValues,
578    /// Jira Project key
579    #[clap(
580        long,
581        short = 'k',
582        value_name = "project_key",
583        help = "Jira Project key"
584    )]
585    pub project_key: Option<String>,
586    /// Jira origin issue link key
587    #[clap(
588        long,
589        short = 'i',
590        value_name = "issue_key",
591        help = "Jira issue link origin key",
592        required = true
593    )]
594    pub origin_issue_key: String,
595    /// Jira destination issue link key
596    #[clap(
597        long,
598        short = 'd',
599        value_name = "issue_key",
600        help = "Jira issue link destination key"
601    )]
602    pub destination_issue_key: Option<String>,
603    /// Jira issue link type
604    #[clap(
605        long,
606        short = 't',
607        value_name = "link_type",
608        help = "Jira issue link type",
609        required = true
610    )]
611    pub link_type: String,
612    /// Jira Project version changelog file
613    #[clap(
614        long,
615        short = 'c',
616        value_name = "changelog_file",
617        help = "changelog file path to be used for automatic issues' links generation (if set the script detects automatically the first tagged block in the changelog and use it as description)"
618    )]
619    pub changelog_file: Option<String>,
620}
621
622/// Available link issue action values
623///
624/// * Create: Create a Jira link between issues
625#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
626#[value(rename_all = "kebab-case")]
627pub enum LinkIssueActionValues {
628    /// Create a Jira link between issues
629    #[value(name = "create", help = "Create a Jira link between issues")]
630    Create,
631}
632
633/// Available transition command line arguments
634///
635/// * transition_act: TransitionActionValues - Transition action
636/// * issue_key: String - Jira issue key
637/// * output: OutputArgs - Jira issue output format
638#[derive(Args, Clone, Debug, Serialize, Deserialize)]
639pub struct TransitionArgs {
640    /// Transition action
641    #[arg(value_name = "list", help_heading = "Jira issue transition list")]
642    pub transition_act: TransitionActionValues,
643    /// Jira issue key
644    #[clap(
645        long,
646        short = 'i',
647        value_name = "issue_key",
648        help = "Jira Project issue key",
649        required = true
650    )]
651    pub issue_key: String,
652    /// Jira issue output format
653    #[clap(flatten)]
654    pub output: OutputArgs,
655}
656
657/// Available transition action values
658///
659/// * List: List Jira issue available transitions
660#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
661#[value(rename_all = "kebab-case")]
662pub enum TransitionActionValues {
663    /// List Jira issue available transitions
664    #[value(name = "list", help = "List Jira issue available transitions")]
665    List,
666}
667
668/// Parse a single key-value pair
669/// Thanks to the example from the clap documentation (https://github.com/clap-rs/clap/blob/master/examples/typed-derive.rs)
670fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
671where
672    T: std::str::FromStr,
673    T::Err: Error + Send + Sync + 'static,
674    U: std::str::FromStr,
675    U::Err: Error + Send + Sync + 'static,
676{
677    let pos = s
678        .find('=')
679        .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?;
680    Ok((
681        s[..pos].parse()?,
682        manage_jira_document_field(s[pos + 1..].to_string()).parse()?,
683    ))
684}
685
686/// Manage Jira document field
687/// Relies on the manage_jira_document_field macro to wrap the field in the correct format
688fn manage_jira_document_field(value: String) -> String {
689    let re = Regex::new(r"^jira_doc_field\[(.+)\]$").unwrap();
690    let captures = re.captures(&value);
691    let val = if Option::is_some(&captures) {
692        jira_doc_std_field![captures.unwrap().get(1).unwrap().as_str()].to_string()
693    } else {
694        value.to_string()
695    };
696    val
697}