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#[derive(Parser, Debug)]
10#[command(author, version, about, long_about = None)]
11pub struct JirustCliArgs {
12 #[clap(subcommand)]
14 pub subcmd: Commands,
15}
16
17#[derive(Subcommand, Clone, Debug, Serialize, Deserialize)]
20pub enum Commands {
21 Config(ConfigArgs),
23 Issue(IssueArgs),
25 Link(LinkIssueArgs),
27 Project(ProjectArgs),
29 Transition(TransitionArgs),
31 Version(VersionArgs),
33}
34
35#[derive(Args, Clone, Debug, Serialize, Deserialize)]
40pub struct PaginationArgs {
41 #[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 #[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#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
65#[value(rename_all = "kebab-case")]
66pub enum OutputValues {
67 #[value(name = "table", help = "Print output in table format")]
69 Table,
70 #[value(name = "json", help = "Print output in json format")]
72 Json,
73}
74
75#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
82#[value(rename_all = "kebab-case")]
83pub enum OutputTypes {
84 #[value(name = "basic", help = "Print basic output")]
86 Basic,
87 #[value(name = "single", help = "Print single row output")]
89 Single,
90 #[value(name = "full", help = "Print full output")]
92 Full,
93}
94
95#[derive(Args, Clone, Debug, Serialize, Deserialize)]
99pub struct OutputArgs {
100 #[clap(long, short = 'o', value_name = "table|json", help = "Output format")]
102 pub output_format: Option<OutputValues>,
103 #[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#[derive(Args, Clone, Debug, Serialize, Deserialize)]
117pub struct ConfigArgs {
118 #[arg(
120 value_name = "auth|jira|setup|show",
121 help_heading = "Configuration management"
122 )]
123 pub cfg_act: ConfigActionValues,
124}
125
126#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
134#[value(rename_all = "kebab-case")]
135pub enum ConfigActionValues {
136 #[value(name = "auth", help = "Set Jira API authentication (username, apikey)")]
138 Auth,
139 #[value(name = "jira", help = "Set Jira API base URL")]
141 Jira,
142 #[value(
144 name = "setup",
145 help = "Setup Jira API configuration (authentication data, jira base URL, etc.)"
146 )]
147 Setup,
148 #[value(name = "show", help = "Show current configuration")]
150 Show,
151}
152
153#[derive(Args, Clone, Debug, Serialize, Deserialize)]
171pub struct VersionArgs {
172 #[arg(
174 value_name = "archive|create|delete|list|release|update",
175 help_heading = "Jira Project version management"
176 )]
177 pub version_act: VersionActionValues,
178 #[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 #[clap(long, short = 'i', value_name = "project_id", help = "Jira Project ID")]
189 pub project_id: Option<i64>,
190 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[clap(flatten)]
272 pub pagination: PaginationArgs,
273 #[clap(flatten)]
275 pub output: OutputArgs,
276}
277
278#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
288#[value(rename_all = "kebab-case")]
289pub enum VersionActionValues {
290 #[value(name = "archive", help = "Archive a Jira Project version")]
292 Archive,
293 #[value(name = "create", help = "Create a Jira Project version")]
295 Create,
296 #[value(name = "delete", help = "Delete a Jira Project version")]
298 Delete,
299 #[value(name = "list", help = "List Jira Project versions")]
301 List,
302 #[value(name = "release", help = "Release a Jira Project version")]
304 Release,
305 #[value(name = "update", help = "Update a Jira Project version")]
307 Update,
308}
309
310#[derive(Args, Clone, Debug, Serialize, Deserialize)]
329pub struct ProjectArgs {
330 #[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 #[clap(
339 long,
340 short = 'k',
341 value_name = "project_key",
342 help = "Jira Project key"
343 )]
344 pub project_key: Option<String>,
345 #[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 #[clap(long, value_name = "project_name", help = "Jira Project name")]
355 pub project_name: Option<String>,
356 #[clap(
358 long,
359 value_name = "project_description",
360 help = "Jira Project description"
361 )]
362 pub project_description: Option<String>,
363 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[clap(
421 long,
422 value_name = "project_assignee_type",
423 help = "Jira Project Assignee Type"
424 )]
425 pub project_assignee_type: Option<String>,
426 #[clap(flatten)]
428 pub pagination: PaginationArgs,
429 #[clap(flatten)]
431 pub output: OutputArgs,
432}
433
434#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
441#[value(rename_all = "kebab-case")]
442pub enum ProjectActionValues {
443 #[value(name = "create", help = "Create new Jira Project")]
445 Create,
446 #[value(
448 name = "get-issue-types",
449 help = "Get Jira Project issue types by Jira project key"
450 )]
451 GetIssueTypes,
452 #[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 #[value(name = "list", help = "List Jira Projects")]
460 List,
461}
462
463#[derive(Args, Clone, Debug, Serialize, Deserialize)]
474pub struct IssueArgs {
475 #[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 #[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 #[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 #[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 #[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 #[clap(
516 long,
517 short = 'a',
518 value_name = "assignee",
519 help = "Jira Project issue assignee"
520 )]
521 pub assignee: Option<String>,
522 #[clap(flatten)]
524 pub pagination: PaginationArgs,
525 #[clap(flatten)]
527 pub output: OutputArgs,
528}
529
530#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
539#[value(rename_all = "kebab-case")]
540pub enum IssueActionValues {
541 #[value(name = "assign", help = "Assign a Jira Project issue")]
543 Assign,
544 #[value(name = "create", help = "Create a Jira Project issue")]
546 Create,
547 #[value(name = "delete", help = "Delete a Jira Project issue")]
549 Delete,
550 #[value(name = "get", help = "Get a specific Jira Project issue")]
552 Get,
553 #[value(name = "transition", help = "Transition a Jira Project issue")]
555 Transition,
556 #[value(name = "update", help = "Update a Jira Project issue")]
558 Update,
559}
560
561#[derive(Args, Clone, Debug, Serialize, Deserialize)]
570pub struct LinkIssueArgs {
571 #[arg(
573 value_name = "create",
574 help_heading = "Jira issues links management",
575 required = true
576 )]
577 pub link_act: LinkIssueActionValues,
578 #[clap(
580 long,
581 short = 'k',
582 value_name = "project_key",
583 help = "Jira Project key"
584 )]
585 pub project_key: Option<String>,
586 #[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 #[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 #[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 #[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#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
626#[value(rename_all = "kebab-case")]
627pub enum LinkIssueActionValues {
628 #[value(name = "create", help = "Create a Jira link between issues")]
630 Create,
631}
632
633#[derive(Args, Clone, Debug, Serialize, Deserialize)]
639pub struct TransitionArgs {
640 #[arg(value_name = "list", help_heading = "Jira issue transition list")]
642 pub transition_act: TransitionActionValues,
643 #[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 #[clap(flatten)]
654 pub output: OutputArgs,
655}
656
657#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
661#[value(rename_all = "kebab-case")]
662pub enum TransitionActionValues {
663 #[value(name = "list", help = "List Jira issue available transitions")]
665 List,
666}
667
668fn 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
686fn 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}