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/// * query: Option<String> - Jira Project issue JQL query to search for issues
479/// * pagination: PaginationArgs - Jira Project issue pagination
480/// * output: OutputArgs - Jira Project issue actions result output format
481#[derive(Args, Clone, Debug, Serialize, Deserialize)]
482pub struct IssueArgs {
483    /// Issue action
484    #[arg(
485        value_name = "assign|create|delete|get|search|transition|update",
486        help_heading = "Jira Project issue management",
487        required = true
488    )]
489    pub issue_act: IssueActionValues,
490    /// Jira Project key
491    #[clap(
492        long,
493        short = 'p',
494        value_name = "project_key",
495        help = "Jira Project key"
496    )]
497    pub project_key: Option<String>,
498    /// Jira Project issue key
499    #[clap(
500        long,
501        short = 'i',
502        value_name = "issue_key",
503        help = "Jira Project issue key"
504    )]
505    pub issue_key: Option<String>,
506    /// Jira Project issue fields
507    #[clap(long,
508        short = 'f',
509        value_name = "issue_fields",
510        value_parser = parse_key_val::<String, String>,
511        help = "Jira Project issue fields (field_name=value)")]
512    pub issue_fields: Option<Vec<(String, String)>>,
513    /// Jira Project issue transition
514    #[clap(
515        long,
516        short = 't',
517        value_name = "transition_to",
518        help = "Jira Project issue transition to"
519    )]
520    pub transition_to: Option<String>,
521    /// Jira Project issue assignee
522    #[clap(
523        long,
524        short = 'a',
525        value_name = "assignee",
526        help = "Jira Project issue assignee"
527    )]
528    pub assignee: Option<String>,
529    /// Jira Project issue query
530    #[clap(
531        long,
532        short = 'q',
533        value_name = "query",
534        help = "Jira Project issue query"
535    )]
536    pub query: Option<String>,
537    /// Jira Project issue pagination
538    #[clap(flatten)]
539    pub pagination: PaginationArgs,
540    /// Jira Project issue actions result output format
541    #[clap(flatten)]
542    pub output: OutputArgs,
543}
544
545/// Available issue action values
546///
547/// * Assign: Assign a Jira Project issue
548/// * Create: Create a Jira Project issue
549/// * Delete: Delete a Jira Project issue
550/// * Get: Get a specific Jira Project issue
551/// * Search: Search for Jira Project issues using JQL
552/// * Transition: Transition a Jira Project issue
553/// * Update: Update a Jira Project issue
554#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
555#[value(rename_all = "kebab-case")]
556pub enum IssueActionValues {
557    /// Assign a Jira Project issue
558    #[value(name = "assign", help = "Assign a Jira Project issue")]
559    Assign,
560    /// Create a Jira Project issue
561    #[value(name = "create", help = "Create a Jira Project issue")]
562    Create,
563    /// Delete a Jira Project issue
564    #[value(name = "delete", help = "Delete a Jira Project issue")]
565    Delete,
566    /// Get a specific Jira Project issue
567    #[value(name = "get", help = "Get a specific Jira Project issue")]
568    Get,
569    /// Search for Jira Project issues using JQL query
570    #[value(name = "search", help = "Search for Jira Project issues")]
571    Search,
572    /// Transition a Jira Project issue
573    #[value(name = "transition", help = "Transition a Jira Project issue")]
574    Transition,
575    /// Update a Jira Project issue
576    #[value(name = "update", help = "Update a Jira Project issue")]
577    Update,
578}
579
580/// Available issues' links command line arguments
581///
582/// * link_act: LinkIssueActionValues - Jira link issue command available actions
583/// * project_key: Option<String> - Jira Project key
584/// * origin_issue_key: String - Jira origin issue link key
585/// * destination_issue_key: Option<String> - Jira destination issue link key
586/// * link_type: String - Jira issue link type
587/// * changelog_file: Option<String> - Jira Project version changelog file
588#[derive(Args, Clone, Debug, Serialize, Deserialize)]
589pub struct LinkIssueArgs {
590    // Jira link issue command available actions
591    #[arg(
592        value_name = "create",
593        help_heading = "Jira issues links management",
594        required = true
595    )]
596    pub link_act: LinkIssueActionValues,
597    /// Jira Project key
598    #[clap(
599        long,
600        short = 'k',
601        value_name = "project_key",
602        help = "Jira Project key"
603    )]
604    pub project_key: Option<String>,
605    /// Jira origin issue link key
606    #[clap(
607        long,
608        short = 'i',
609        value_name = "issue_key",
610        help = "Jira issue link origin key",
611        required = true
612    )]
613    pub origin_issue_key: String,
614    /// Jira destination issue link key
615    #[clap(
616        long,
617        short = 'd',
618        value_name = "issue_key",
619        help = "Jira issue link destination key"
620    )]
621    pub destination_issue_key: Option<String>,
622    /// Jira issue link type
623    #[clap(
624        long,
625        short = 't',
626        value_name = "link_type",
627        help = "Jira issue link type",
628        required = true
629    )]
630    pub link_type: String,
631    /// Jira Project version changelog file
632    #[clap(
633        long,
634        short = 'c',
635        value_name = "changelog_file",
636        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)"
637    )]
638    pub changelog_file: Option<String>,
639}
640
641/// Available link issue action values
642///
643/// * Create: Create a Jira link between issues
644#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
645#[value(rename_all = "kebab-case")]
646pub enum LinkIssueActionValues {
647    /// Create a Jira link between issues
648    #[value(name = "create", help = "Create a Jira link between issues")]
649    Create,
650}
651
652/// Available transition command line arguments
653///
654/// * transition_act: TransitionActionValues - Transition action
655/// * issue_key: String - Jira issue key
656/// * output: OutputArgs - Jira issue output format
657#[derive(Args, Clone, Debug, Serialize, Deserialize)]
658pub struct TransitionArgs {
659    /// Transition action
660    #[arg(value_name = "list", help_heading = "Jira issue transition list")]
661    pub transition_act: TransitionActionValues,
662    /// Jira issue key
663    #[clap(
664        long,
665        short = 'i',
666        value_name = "issue_key",
667        help = "Jira Project issue key",
668        required = true
669    )]
670    pub issue_key: String,
671    /// Jira issue output format
672    #[clap(flatten)]
673    pub output: OutputArgs,
674}
675
676/// Available transition action values
677///
678/// * List: List Jira issue available transitions
679#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
680#[value(rename_all = "kebab-case")]
681pub enum TransitionActionValues {
682    /// List Jira issue available transitions
683    #[value(name = "list", help = "List Jira issue available transitions")]
684    List,
685}
686
687/// Parse a single key-value pair
688/// Thanks to the example from the clap documentation (https://github.com/clap-rs/clap/blob/master/examples/typed-derive.rs)
689fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
690where
691    T: std::str::FromStr,
692    T::Err: Error + Send + Sync + 'static,
693    U: std::str::FromStr,
694    U::Err: Error + Send + Sync + 'static,
695{
696    let pos = s
697        .find('=')
698        .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?;
699    Ok((
700        s[..pos].parse()?,
701        manage_jira_document_field(s[pos + 1..].to_string()).parse()?,
702    ))
703}
704
705/// Manage Jira document field
706/// Relies on the manage_jira_document_field macro to wrap the field in the correct format
707fn manage_jira_document_field(value: String) -> String {
708    let re = Regex::new(r"^jira_doc_field\[(.+)\]$").unwrap();
709    let captures = re.captures(&value);
710    if let Some(captures) = &captures {
711        if let Some(first_match) = captures.get(1) {
712            jira_doc_std_field![first_match.as_str()].to_string()
713        } else {
714            value.to_string()
715        }
716    } else {
717        value.to_string()
718    }
719}