1use crate::jira_doc_std_field;
2use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum};
3use regex::Regex;
4use std::error::Error;
5
6#[derive(Parser, Debug)]
9#[command(author, version, about, long_about = None)]
10pub struct JirustCliArgs {
11 #[clap(subcommand)]
13 pub subcmd: Commands,
14}
15
16#[derive(Subcommand, Clone, Debug)]
19pub enum Commands {
20 Config(ConfigArgs),
22 Issue(IssueArgs),
24 Link(LinkIssueArgs),
26 Project(ProjectArgs),
28 Transition(TransitionArgs),
30 Version(VersionArgs),
32}
33
34#[derive(Args, Clone, Debug)]
39pub struct PaginationArgs {
40 #[clap(
42 long,
43 short = 'l',
44 value_name = "page_size",
45 help = "page size for lists"
46 )]
47 pub page_size: Option<i32>,
48 #[clap(
50 long,
51 short = 's',
52 value_name = "page_offset",
53 help = "page offset for list"
54 )]
55 pub page_offset: Option<i64>,
56}
57
58#[derive(ValueEnum, Debug, Clone, Copy)]
64#[value(rename_all = "kebab-case")]
65pub enum OutputValues {
66 #[value(name = "table", help = "Print output in table format")]
68 Table,
69 #[value(name = "json", help = "Print output in json format")]
71 Json,
72}
73
74#[derive(ValueEnum, Debug, Clone, Copy)]
81#[value(rename_all = "kebab-case")]
82pub enum OutputTypes {
83 #[value(name = "basic", help = "Print basic output")]
85 Basic,
86 #[value(name = "single", help = "Print single row output")]
88 Single,
89 #[value(name = "full", help = "Print full output")]
91 Full,
92}
93
94#[derive(Args, Clone, Debug)]
98pub struct OutputArgs {
99 #[clap(long, short = 'o', value_name = "table|json", help = "Output format")]
101 pub output_format: Option<OutputValues>,
102 #[clap(
104 long,
105 short = 'z',
106 value_name = "basic|single|full",
107 help = "Output type"
108 )]
109 pub output_type: Option<OutputTypes>,
110}
111
112#[derive(Args, Clone, Debug)]
116pub struct ConfigArgs {
117 #[arg(
119 value_name = "auth|jira|setup|show",
120 help_heading = "Configuration management"
121 )]
122 pub cfg_act: ConfigActionValues,
123}
124
125#[derive(ValueEnum, Debug, Clone, Copy)]
133#[value(rename_all = "kebab-case")]
134pub enum ConfigActionValues {
135 #[value(name = "auth", help = "Set Jira API authentication (username, apikey)")]
137 Auth,
138 #[value(name = "jira", help = "Set Jira API base URL")]
140 Jira,
141 #[value(
143 name = "setup",
144 help = "Setup Jira API configuration (authentication data, jira base URL, etc.)"
145 )]
146 Setup,
147 #[value(name = "show", help = "Show current configuration")]
149 Show,
150}
151
152#[derive(Args, Clone, Debug)]
170pub struct VersionArgs {
171 #[arg(
173 value_name = "archive|create|delete|list|release|update",
174 help_heading = "Jira Project version management"
175 )]
176 pub version_act: VersionActionValues,
177 #[clap(
179 long,
180 short = 'k',
181 value_name = "project_key",
182 required = true,
183 help = "Jira Project key"
184 )]
185 pub project_key: String,
186 #[clap(long, short = 'i', value_name = "project_id", help = "Jira Project ID")]
188 pub project_id: Option<i64>,
189 #[clap(
191 long,
192 short = 'v',
193 value_name = "version_id",
194 help = "Jira Project version ID"
195 )]
196 pub version_id: Option<String>,
197 #[clap(
199 long,
200 short = 'n',
201 value_name = "version_name",
202 help = "Jira Project version name"
203 )]
204 pub version_name: Option<String>,
205 #[clap(
207 long,
208 short = 'd',
209 value_name = "version_description",
210 help = "Jira Project version description"
211 )]
212 pub version_description: Option<String>,
213 #[clap(
215 long,
216 value_name = "version_start_date",
217 help = "Jira Project version start date"
218 )]
219 pub version_start_date: Option<String>,
220 #[clap(
222 long,
223 value_name = "version_release_date",
224 help = "Jira Project version release date"
225 )]
226 pub version_release_date: Option<String>,
227 #[clap(
229 long,
230 short = 'a',
231 value_name = "version_archived",
232 help = "Jira Project version archived"
233 )]
234 pub version_archived: Option<bool>,
235 #[clap(
237 long,
238 short = 'm',
239 action = ArgAction::SetTrue,
240 value_name = "version_released",
241 help = "Jira Project version released"
242 )]
243 pub version_released: Option<bool>,
244 #[clap(
246 long,
247 short = 'c',
248 value_name = "changelog_file",
249 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)"
250 )]
251 pub changelog_file: Option<String>,
252 #[clap(
254 long,
255 short = 'r',
256 action = ArgAction::SetTrue,
257 value_name = "resolve_issues",
258 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\""
259 )]
260 pub transition_issues: Option<bool>,
261 #[clap(
263 long,
264 short = 'u',
265 value_name = "transition_assignee",
266 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)"
267 )]
268 pub transition_assignee: Option<String>,
269 #[clap(flatten)]
271 pub pagination: PaginationArgs,
272 #[clap(flatten)]
274 pub output: OutputArgs,
275}
276
277#[derive(ValueEnum, Debug, Clone, Copy)]
287#[value(rename_all = "kebab-case")]
288pub enum VersionActionValues {
289 #[value(name = "archive", help = "Archive a Jira Project version")]
291 Archive,
292 #[value(name = "create", help = "Create a Jira Project version")]
294 Create,
295 #[value(name = "delete", help = "Delete a Jira Project version")]
297 Delete,
298 #[value(name = "list", help = "List Jira Project versions")]
300 List,
301 #[value(name = "release", help = "Release a Jira Project version")]
303 Release,
304 #[value(name = "update", help = "Update a Jira Project version")]
306 Update,
307}
308
309#[derive(Args, Clone, Debug)]
317pub struct ProjectArgs {
318 #[arg(
320 value_name = "get-issue-types|get-issue-type-fields|list",
321 help_heading = "Jira Project management",
322 required = true
323 )]
324 pub project_act: ProjectActionValues,
325 #[clap(
327 long,
328 short = 'k',
329 value_name = "project_key",
330 help = "Jira Project key",
331 required = true
332 )]
333 pub project_key: Option<String>,
334 #[clap(
336 long,
337 short = 'i',
338 value_name = "project_issue_type",
339 help = "Jira Project issue type ID"
340 )]
341 pub project_issue_type: Option<String>,
342 #[clap(flatten)]
344 pub pagination: PaginationArgs,
345 #[clap(flatten)]
347 pub output: OutputArgs,
348}
349
350#[derive(ValueEnum, Debug, Clone, Copy)]
356#[value(rename_all = "kebab-case")]
357pub enum ProjectActionValues {
358 #[value(
360 name = "get-issue-types",
361 help = "Get Jira Project issue types by Jira project key"
362 )]
363 GetIssueTypes,
364 #[value(
366 name = "get-issue-type-fields",
367 help = "Get Jira Project issue type fields by Jira project key and issue type ID"
368 )]
369 GetIssueTypeFields,
370 #[value(name = "list", help = "List Jira Projects")]
372 List,
373}
374
375#[derive(Args, Clone, Debug)]
386pub struct IssueArgs {
387 #[arg(
389 value_name = "assign|create|delete|get|transition|update",
390 help_heading = "Jira Project issue management",
391 required = true
392 )]
393 pub issue_act: IssueActionValues,
394 #[clap(
396 long,
397 short = 'p',
398 value_name = "project_key",
399 help = "Jira Project key",
400 required = true
401 )]
402 pub project_key: String,
403 #[clap(
405 long,
406 short = 'i',
407 value_name = "issue_key",
408 help = "Jira Project issue key"
409 )]
410 pub issue_key: Option<String>,
411 #[clap(long,
413 short = 'f',
414 value_name = "issue_fields",
415 value_parser = parse_key_val::<String, String>,
416 help = "Jira Project issue fields (field_name=value)")]
417 pub issue_fields: Option<Vec<(String, String)>>,
418 #[clap(
420 long,
421 short = 't',
422 value_name = "transition_to",
423 help = "Jira Project issue transition to"
424 )]
425 pub transition_to: Option<String>,
426 #[clap(
428 long,
429 short = 'a',
430 value_name = "assignee",
431 help = "Jira Project issue assignee"
432 )]
433 pub assignee: Option<String>,
434 #[clap(flatten)]
436 pub pagination: PaginationArgs,
437 #[clap(flatten)]
439 pub output: OutputArgs,
440}
441
442#[derive(ValueEnum, Debug, Clone, Copy)]
451#[value(rename_all = "kebab-case")]
452pub enum IssueActionValues {
453 #[value(name = "assign", help = "Assign a Jira Project issue")]
455 Assign,
456 #[value(name = "create", help = "Create a Jira Project issue")]
458 Create,
459 #[value(name = "delete", help = "Delete a Jira Project issue")]
461 Delete,
462 #[value(name = "get", help = "Get a specific Jira Project issue")]
464 Get,
465 #[value(name = "transition", help = "Transition a Jira Project issue")]
467 Transition,
468 #[value(name = "update", help = "Update a Jira Project issue")]
470 Update,
471}
472
473#[derive(Args, Clone, Debug)]
482pub struct LinkIssueArgs {
483 #[arg(
485 value_name = "create",
486 help_heading = "Jira issues links management",
487 required = true
488 )]
489 pub link_act: LinkIssueActionValues,
490 #[clap(
492 long,
493 short = 'k',
494 value_name = "project_key",
495 help = "Jira Project key"
496 )]
497 pub project_key: Option<String>,
498 #[clap(
500 long,
501 short = 'i',
502 value_name = "issue_key",
503 help = "Jira issue link origin key",
504 required = true
505 )]
506 pub origin_issue_key: String,
507 #[clap(
509 long,
510 short = 'd',
511 value_name = "issue_key",
512 help = "Jira issue link destination key"
513 )]
514 pub destination_issue_key: Option<String>,
515 #[clap(
517 long,
518 short = 't',
519 value_name = "link_type",
520 help = "Jira issue link type",
521 required = true
522 )]
523 pub link_type: String,
524 #[clap(
526 long,
527 short = 'c',
528 value_name = "changelog_file",
529 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)"
530 )]
531 pub changelog_file: Option<String>,
532}
533
534#[derive(ValueEnum, Debug, Clone, Copy)]
538#[value(rename_all = "kebab-case")]
539pub enum LinkIssueActionValues {
540 #[value(name = "create", help = "Create a Jira link between issues")]
542 Create,
543}
544
545#[derive(Args, Clone, Debug)]
551pub struct TransitionArgs {
552 #[arg(value_name = "list", help_heading = "Jira issue transition list")]
554 pub transition_act: TransitionActionValues,
555 #[clap(
557 long,
558 short = 'i',
559 value_name = "issue_key",
560 help = "Jira Project issue key",
561 required = true
562 )]
563 pub issue_key: String,
564 #[clap(flatten)]
566 pub output: OutputArgs,
567}
568
569#[derive(ValueEnum, Debug, Clone, Copy)]
573#[value(rename_all = "kebab-case")]
574pub enum TransitionActionValues {
575 #[value(name = "list", help = "List Jira issue available transitions")]
577 List,
578}
579
580fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
583where
584 T: std::str::FromStr,
585 T::Err: Error + Send + Sync + 'static,
586 U: std::str::FromStr,
587 U::Err: Error + Send + Sync + 'static,
588{
589 let pos = s
590 .find('=')
591 .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?;
592 Ok((
593 s[..pos].parse()?,
594 manage_jira_document_field(s[pos + 1..].to_string()).parse()?,
595 ))
596}
597
598fn manage_jira_document_field(value: String) -> String {
601 let re = Regex::new(r"^jira_doc_field\[(.+)\]$").unwrap();
602 let captures = re.captures(&value);
603 let val = if Option::is_some(&captures) {
604 jira_doc_std_field![captures.unwrap().get(1).unwrap().as_str()].to_string()
605 } else {
606 value.to_string()
607 };
608 val
609}