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/// * RelatedWorkItems: Get Project version related workitems
286/// * Release: Release a Jira Project version
287/// * Update: Update a Jira Project version
288#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
289#[value(rename_all = "kebab-case")]
290pub enum VersionActionValues {
291    /// Archive a Jira Project version
292    #[value(name = "archive", help = "Archive a Jira Project version")]
293    Archive,
294    /// Create a Jira Project version
295    #[value(name = "create", help = "Create a Jira Project version")]
296    Create,
297    /// Delete a Jira Project version
298    #[value(name = "delete", help = "Delete a Jira Project version")]
299    Delete,
300    /// List Jira Project versions
301    #[value(name = "list", help = "List Jira Project versions")]
302    List,
303    /// Get Project version related workitems
304    #[value(
305        name = "related-work-items",
306        help = "Get Project version related workitems"
307    )]
308    RelatedWorkItems,
309    /// Release a Jira Project version
310    #[value(name = "release", help = "Release a Jira Project version")]
311    Release,
312    /// Update a Jira Project version
313    #[value(name = "update", help = "Update a Jira Project version")]
314    Update,
315}
316
317/// Available project command line arguments
318///
319/// * project_act: ProjectActionValues - Project action
320/// * project_key: Option<String> - Jira Project key
321/// * project_issue_type: Option<String> - Jira Project issue type ID
322/// * project_name: Option<String> - Jira Project name
323/// * project_description: Option<String> - Jira Project description
324/// * project_field_configuration_id: Option<i64> - Jira Project field configuration ID
325/// * project_issue_security_scheme_id: Option<i64> - Jira Project issue security scheme ID
326/// * project_permission_scheme_id: Option<i64> - Jira Project permission scheme ID
327/// * project_issue_type_scheme_id: Option<i64> - Jira Project issue type scheme ID
328/// * project_issue_type_screen_scheme_id: Option<i64> - Jira Project issue type screen scheme ID
329/// * project_notification_scheme_id: Option<i64> - Jira Project notification scheme ID
330/// * project_workflow_scheme_id: Option<i64> - Jira Project workflow scheme ID
331/// * project_lead_account_id: Option<String> - Jira Project lead account ID
332/// * project_assignee_type: Option<String> - Jira Project assignee type
333/// * pagination: PaginationArgs - Jira Project pagination
334/// * output: OutputArgs - Jira Project actions result output format
335#[derive(Args, Clone, Debug, Serialize, Deserialize)]
336pub struct ProjectArgs {
337    /// Project action
338    #[arg(
339        value_name = "create|get-issue-types|get-issue-type-fields|list",
340        help_heading = "Jira Project management",
341        required = true
342    )]
343    pub project_act: ProjectActionValues,
344    /// Jira Project key
345    #[clap(
346        long,
347        short = 'k',
348        value_name = "project_key",
349        help = "Jira Project key"
350    )]
351    pub project_key: Option<String>,
352    /// Jira Project issue type ID
353    #[clap(
354        long,
355        short = 'i',
356        value_name = "project_issue_type",
357        help = "Jira Project issue type ID"
358    )]
359    pub project_issue_type: Option<String>,
360    /// Jira Project name
361    #[clap(long, value_name = "project_name", help = "Jira Project name")]
362    pub project_name: Option<String>,
363    /// Jira Project description
364    #[clap(
365        long,
366        value_name = "project_description",
367        help = "Jira Project description"
368    )]
369    pub project_description: Option<String>,
370    /// Jira Project field configuration ID
371    #[clap(
372        long,
373        value_name = "project_field_configuration_id",
374        help = "Jira Project field configuration ID"
375    )]
376    pub project_field_configuration_id: Option<i64>,
377    /// Jira Project issue security scheme ID
378    #[clap(
379        long,
380        value_name = "project_issue_security_scheme_id",
381        help = "Jira Project issue security scheme ID"
382    )]
383    pub project_issue_security_scheme_id: Option<i64>,
384    /// Jira Project issue type scheme ID
385    #[clap(
386        long,
387        value_name = "project_issue_type_scheme_id",
388        help = "Jira Project issue type scheme ID"
389    )]
390    pub project_issue_type_scheme_id: Option<i64>,
391    /// Jira Project issue type screen scheme ID
392    #[clap(
393        long,
394        value_name = "project_issue_type_screen_scheme_id",
395        help = "Jira Project issue type screen scheme ID"
396    )]
397    pub project_issue_type_screen_scheme_id: Option<i64>,
398    /// Jira Project notification scheme ID
399    #[clap(
400        long,
401        value_name = "project_notification_scheme_id",
402        help = "Jira Project notification scheme ID"
403    )]
404    pub project_notification_scheme_id: Option<i64>,
405    /// Jira Project permission scheme ID
406    #[clap(
407        long,
408        value_name = "project_permission_scheme_id",
409        help = "Jira Project permission scheme ID"
410    )]
411    pub project_permission_scheme_id: Option<i64>,
412    // Jira project workflow scheme ID
413    #[clap(
414        long,
415        value_name = "project_workflow_scheme_id",
416        help = "Jira Project workflow scheme ID"
417    )]
418    pub project_workflow_scheme_id: Option<i64>,
419    /// Jira Project lead account ID
420    #[clap(
421        long,
422        value_name = "project_lead_account_id",
423        help = "Jira Project lead account ID"
424    )]
425    pub project_lead_account_id: Option<String>,
426    /// Jira Project Assignee Type
427    #[clap(
428        long,
429        value_name = "project_assignee_type",
430        help = "Jira Project Assignee Type"
431    )]
432    pub project_assignee_type: Option<String>,
433    /// Jira Project pagination
434    #[clap(flatten)]
435    pub pagination: PaginationArgs,
436    /// Jira Project actions result output format
437    #[clap(flatten)]
438    pub output: OutputArgs,
439}
440
441/// Available project action values
442///
443/// * Create: Create new Jira Project
444/// * GetIssueTypes: Get Jira Project issue types by Jira project key
445/// * GetIssueTypeFields: Get Jira Project issue type fields by Jira project key and issue type ID
446/// * List: List Jira Projects
447#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
448#[value(rename_all = "kebab-case")]
449pub enum ProjectActionValues {
450    /// Create new Jira Project
451    #[value(name = "create", help = "Create new Jira Project")]
452    Create,
453    /// Get Jira Project issue types by Jira project key
454    #[value(
455        name = "get-issue-types",
456        help = "Get Jira Project issue types by Jira project key"
457    )]
458    GetIssueTypes,
459    /// Get Jira Project issue type fields by Jira project key and issue type ID
460    #[value(
461        name = "get-issue-type-fields",
462        help = "Get Jira Project issue type fields by Jira project key and issue type ID"
463    )]
464    GetIssueTypeFields,
465    /// List Jira Projects
466    #[value(name = "list", help = "List Jira Projects")]
467    List,
468}
469
470/// Available issue command line arguments
471///
472/// * issue_act: IssueActionValues - Issue action
473/// * project_key: String - Jira Project key
474/// * issue_key: Option<String> - Jira Project issue key
475/// * issue_fields: Option<Vec<(String, String)>> - Jira Project issue fields
476/// * transition_to: Option<String> - Jira Project issue transition to
477/// * assignee: Option<String> - Jira Project issue assignee
478/// * pagination: PaginationArgs - Jira Project issue pagination
479/// * output: OutputArgs - Jira Project issue actions result output format
480#[derive(Args, Clone, Debug, Serialize, Deserialize)]
481pub struct IssueArgs {
482    /// Issue action
483    #[arg(
484        value_name = "assign|create|delete|get|transition|update",
485        help_heading = "Jira Project issue management",
486        required = true
487    )]
488    pub issue_act: IssueActionValues,
489    /// Jira Project key
490    #[clap(
491        long,
492        short = 'p',
493        value_name = "project_key",
494        help = "Jira Project key"
495    )]
496    pub project_key: Option<String>,
497    /// Jira Project issue key
498    #[clap(
499        long,
500        short = 'i',
501        value_name = "issue_key",
502        help = "Jira Project issue key"
503    )]
504    pub issue_key: Option<String>,
505    /// Jira Project issue fields
506    #[clap(long,
507        short = 'f',
508        value_name = "issue_fields",
509        value_parser = parse_key_val::<String, String>,
510        help = "Jira Project issue fields (field_name=value)")]
511    pub issue_fields: Option<Vec<(String, String)>>,
512    /// Jira Project issue transition
513    #[clap(
514        long,
515        short = 't',
516        value_name = "transition_to",
517        help = "Jira Project issue transition to"
518    )]
519    pub transition_to: Option<String>,
520    /// Jira Project issue assignee
521    #[clap(
522        long,
523        short = 'a',
524        value_name = "assignee",
525        help = "Jira Project issue assignee"
526    )]
527    pub assignee: Option<String>,
528    /// Jira Project issue query
529    #[clap(
530        long,
531        short = 'q',
532        value_name = "query",
533        help = "Jira Project issue query"
534    )]
535    pub query: Option<String>,
536    /// Jira Project issue pagination
537    #[clap(flatten)]
538    pub pagination: PaginationArgs,
539    /// Jira Project issue actions result output format
540    #[clap(flatten)]
541    pub output: OutputArgs,
542}
543
544/// Available issue action values
545///
546/// * Assign: Assign a Jira Project issue
547/// * Create: Create a Jira Project issue
548/// * Delete: Delete a Jira Project issue
549/// * Get: Get a specific Jira Project issue
550/// * Transition: Transition a Jira Project issue
551/// * Update: Update a Jira Project issue
552#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
553#[value(rename_all = "kebab-case")]
554pub enum IssueActionValues {
555    /// Assign a Jira Project issue
556    #[value(name = "assign", help = "Assign a Jira Project issue")]
557    Assign,
558    /// Create a Jira Project issue
559    #[value(name = "create", help = "Create a Jira Project issue")]
560    Create,
561    /// Delete a Jira Project issue
562    #[value(name = "delete", help = "Delete a Jira Project issue")]
563    Delete,
564    /// Get a specific Jira Project issue
565    #[value(name = "get", help = "Get a specific Jira Project issue")]
566    Get,
567    /// Search for Jira Project issues
568    #[value(name = "search", help = "Search for Jira Project issues")]
569    Search,
570    /// Transition a Jira Project issue
571    #[value(name = "transition", help = "Transition a Jira Project issue")]
572    Transition,
573    /// Update a Jira Project issue
574    #[value(name = "update", help = "Update a Jira Project issue")]
575    Update,
576}
577
578/// Available issues' links command line arguments
579///
580/// * link_act: LinkIssueActionValues - Jira link issue command available actions
581/// * project_key: Option<String> - Jira Project key
582/// * origin_issue_key: String - Jira origin issue link key
583/// * destination_issue_key: Option<String> - Jira destination issue link key
584/// * link_type: String - Jira issue link type
585/// * changelog_file: Option<String> - Jira Project version changelog file
586#[derive(Args, Clone, Debug, Serialize, Deserialize)]
587pub struct LinkIssueArgs {
588    // Jira link issue command available actions
589    #[arg(
590        value_name = "create",
591        help_heading = "Jira issues links management",
592        required = true
593    )]
594    pub link_act: LinkIssueActionValues,
595    /// Jira Project key
596    #[clap(
597        long,
598        short = 'k',
599        value_name = "project_key",
600        help = "Jira Project key"
601    )]
602    pub project_key: Option<String>,
603    /// Jira origin issue link key
604    #[clap(
605        long,
606        short = 'i',
607        value_name = "issue_key",
608        help = "Jira issue link origin key",
609        required = true
610    )]
611    pub origin_issue_key: String,
612    /// Jira destination issue link key
613    #[clap(
614        long,
615        short = 'd',
616        value_name = "issue_key",
617        help = "Jira issue link destination key"
618    )]
619    pub destination_issue_key: Option<String>,
620    /// Jira issue link type
621    #[clap(
622        long,
623        short = 't',
624        value_name = "link_type",
625        help = "Jira issue link type",
626        required = true
627    )]
628    pub link_type: String,
629    /// Jira Project version changelog file
630    #[clap(
631        long,
632        short = 'c',
633        value_name = "changelog_file",
634        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)"
635    )]
636    pub changelog_file: Option<String>,
637}
638
639/// Available link issue action values
640///
641/// * Create: Create a Jira link between issues
642#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
643#[value(rename_all = "kebab-case")]
644pub enum LinkIssueActionValues {
645    /// Create a Jira link between issues
646    #[value(name = "create", help = "Create a Jira link between issues")]
647    Create,
648}
649
650/// Available transition command line arguments
651///
652/// * transition_act: TransitionActionValues - Transition action
653/// * issue_key: String - Jira issue key
654/// * output: OutputArgs - Jira issue output format
655#[derive(Args, Clone, Debug, Serialize, Deserialize)]
656pub struct TransitionArgs {
657    /// Transition action
658    #[arg(value_name = "list", help_heading = "Jira issue transition list")]
659    pub transition_act: TransitionActionValues,
660    /// Jira issue key
661    #[clap(
662        long,
663        short = 'i',
664        value_name = "issue_key",
665        help = "Jira Project issue key",
666        required = true
667    )]
668    pub issue_key: String,
669    /// Jira issue output format
670    #[clap(flatten)]
671    pub output: OutputArgs,
672}
673
674/// Available transition action values
675///
676/// * List: List Jira issue available transitions
677#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
678#[value(rename_all = "kebab-case")]
679pub enum TransitionActionValues {
680    /// List Jira issue available transitions
681    #[value(name = "list", help = "List Jira issue available transitions")]
682    List,
683}
684
685/// Parse a single key-value pair
686/// Thanks to the example from the clap documentation (https://github.com/clap-rs/clap/blob/master/examples/typed-derive.rs)
687fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
688where
689    T: std::str::FromStr,
690    T::Err: Error + Send + Sync + 'static,
691    U: std::str::FromStr,
692    U::Err: Error + Send + Sync + 'static,
693{
694    let pos = s
695        .find('=')
696        .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?;
697    Ok((
698        s[..pos].parse()?,
699        manage_jira_document_field(s[pos + 1..].to_string()).parse()?,
700    ))
701}
702
703/// Manage Jira document field
704/// Relies on the manage_jira_document_field macro to wrap the field in the correct format
705fn manage_jira_document_field(value: String) -> String {
706    let re = Regex::new(r"^jira_doc_field\[(.+)\]$").unwrap();
707    let captures = re.captures(&value);
708    if let Some(captures) = &captures {
709        if let Some(first_match) = captures.get(1) {
710            jira_doc_std_field![first_match.as_str()].to_string()
711        } else {
712            value.to_string()
713        }
714    } else {
715        value.to_string()
716    }
717}