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)]
289#[value(rename_all = "kebab-case")]
290pub enum VersionActionValues {
291 #[value(name = "archive", help = "Archive a Jira Project version")]
293 Archive,
294 #[value(name = "create", help = "Create a Jira Project version")]
296 Create,
297 #[value(name = "delete", help = "Delete a Jira Project version")]
299 Delete,
300 #[value(name = "list", help = "List Jira Project versions")]
302 List,
303 #[value(
305 name = "related-work-items",
306 help = "Get Project version related workitems"
307 )]
308 RelatedWorkItems,
309 #[value(name = "release", help = "Release a Jira Project version")]
311 Release,
312 #[value(name = "update", help = "Update a Jira Project version")]
314 Update,
315}
316
317#[derive(Args, Clone, Debug, Serialize, Deserialize)]
336pub struct ProjectArgs {
337 #[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 #[clap(
346 long,
347 short = 'k',
348 value_name = "project_key",
349 help = "Jira Project key"
350 )]
351 pub project_key: Option<String>,
352 #[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 #[clap(long, value_name = "project_name", help = "Jira Project name")]
362 pub project_name: Option<String>,
363 #[clap(
365 long,
366 value_name = "project_description",
367 help = "Jira Project description"
368 )]
369 pub project_description: Option<String>,
370 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[clap(
428 long,
429 value_name = "project_assignee_type",
430 help = "Jira Project Assignee Type"
431 )]
432 pub project_assignee_type: Option<String>,
433 #[clap(flatten)]
435 pub pagination: PaginationArgs,
436 #[clap(flatten)]
438 pub output: OutputArgs,
439}
440
441#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
448#[value(rename_all = "kebab-case")]
449pub enum ProjectActionValues {
450 #[value(name = "create", help = "Create new Jira Project")]
452 Create,
453 #[value(
455 name = "get-issue-types",
456 help = "Get Jira Project issue types by Jira project key"
457 )]
458 GetIssueTypes,
459 #[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 #[value(name = "list", help = "List Jira Projects")]
467 List,
468}
469
470#[derive(Args, Clone, Debug, Serialize, Deserialize)]
481pub struct IssueArgs {
482 #[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 #[clap(
491 long,
492 short = 'p',
493 value_name = "project_key",
494 help = "Jira Project key"
495 )]
496 pub project_key: Option<String>,
497 #[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 #[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 #[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 #[clap(
522 long,
523 short = 'a',
524 value_name = "assignee",
525 help = "Jira Project issue assignee"
526 )]
527 pub assignee: Option<String>,
528 #[clap(
530 long,
531 short = 'q',
532 value_name = "query",
533 help = "Jira Project issue query"
534 )]
535 pub query: Option<String>,
536 #[clap(flatten)]
538 pub pagination: PaginationArgs,
539 #[clap(flatten)]
541 pub output: OutputArgs,
542}
543
544#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
553#[value(rename_all = "kebab-case")]
554pub enum IssueActionValues {
555 #[value(name = "assign", help = "Assign a Jira Project issue")]
557 Assign,
558 #[value(name = "create", help = "Create a Jira Project issue")]
560 Create,
561 #[value(name = "delete", help = "Delete a Jira Project issue")]
563 Delete,
564 #[value(name = "get", help = "Get a specific Jira Project issue")]
566 Get,
567 #[value(name = "search", help = "Search for Jira Project issues")]
569 Search,
570 #[value(name = "transition", help = "Transition a Jira Project issue")]
572 Transition,
573 #[value(name = "update", help = "Update a Jira Project issue")]
575 Update,
576}
577
578#[derive(Args, Clone, Debug, Serialize, Deserialize)]
587pub struct LinkIssueArgs {
588 #[arg(
590 value_name = "create",
591 help_heading = "Jira issues links management",
592 required = true
593 )]
594 pub link_act: LinkIssueActionValues,
595 #[clap(
597 long,
598 short = 'k',
599 value_name = "project_key",
600 help = "Jira Project key"
601 )]
602 pub project_key: Option<String>,
603 #[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 #[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 #[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 #[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#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
643#[value(rename_all = "kebab-case")]
644pub enum LinkIssueActionValues {
645 #[value(name = "create", help = "Create a Jira link between issues")]
647 Create,
648}
649
650#[derive(Args, Clone, Debug, Serialize, Deserialize)]
656pub struct TransitionArgs {
657 #[arg(value_name = "list", help_heading = "Jira issue transition list")]
659 pub transition_act: TransitionActionValues,
660 #[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 #[clap(flatten)]
671 pub output: OutputArgs,
672}
673
674#[derive(ValueEnum, Debug, Clone, Copy, Serialize, Deserialize)]
678#[value(rename_all = "kebab-case")]
679pub enum TransitionActionValues {
680 #[value(name = "list", help = "List Jira issue available transitions")]
682 List,
683}
684
685fn 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
703fn 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}