jirust_cli/runners/jira_cmd_runners/
issue_cmd_runner.rs

1use jira_v3_openapi::apis::issue_search_api::search_for_issues_using_jql_post;
2use jira_v3_openapi::apis::issues_api::*;
3use jira_v3_openapi::models::user::AccountType;
4use jira_v3_openapi::models::{
5    CreatedIssue, IssueBean, IssueTransition, SearchRequestBean, Transitions, User,
6};
7use jira_v3_openapi::{apis::configuration::Configuration, models::IssueUpdateDetails};
8use serde_json::Value;
9use std::collections::HashMap;
10use std::io::Error;
11
12use crate::args::commands::TransitionArgs;
13use crate::{
14    args::commands::IssueArgs,
15    config::config_file::{AuthData, ConfigFile},
16};
17
18/// Issue command runner
19/// This struct is responsible for running the issue command
20/// It uses the Jira API to perform the operations
21///
22/// # Fields
23///
24/// * `cfg` - Configuration object
25pub struct IssueCmdRunner {
26    /// Configuration object
27    cfg: Configuration,
28}
29
30/// Implementation of IssueCmdRunner
31///
32/// # Methods
33///
34/// * `new` - Creates a new instance of IssueCmdRunner
35/// * `assign_jira_issue` - Assigns a Jira issue to a user
36/// * `create_jira_issue` - Creates a Jira issue
37/// * `delete_jira_issue` - Deletes a Jira issue
38/// * `get_jira_issue` - Gets a Jira issue
39/// * `transition_jira_issue` - Transitions a Jira issue
40/// * `update_jira_issue` - Updates a Jira issue
41/// * `get_issue_available_transitions` - Gets available transitions for a Jira issue
42impl IssueCmdRunner {
43    /// Creates a new instance of IssueCmdRunner
44    ///
45    /// # Arguments
46    ///
47    /// * `cfg_file` - Configuration file
48    ///
49    /// # Returns
50    ///
51    /// * `IssueCmdRunner` - Instance of IssueCmdRunner
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use jirust_cli::config::config_file::ConfigFile;
57    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::IssueCmdRunner;
58    /// use toml::Table;
59    ///
60    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
61    ///
62    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
63    /// ```
64    pub fn new(cfg_file: &ConfigFile) -> IssueCmdRunner {
65        let mut config = Configuration::new();
66        let auth_data = AuthData::from_base64(cfg_file.get_auth_key());
67        config.base_path = cfg_file.get_jira_url().to_string();
68        config.basic_auth = Some((auth_data.0, Some(auth_data.1)));
69        IssueCmdRunner { cfg: config }
70    }
71
72    /// Assigns a Jira issue to a user
73    ///
74    /// # Arguments
75    ///
76    /// * `params` - Issue command parameters
77    ///
78    /// # Returns
79    ///
80    /// * `Value` - JSON value
81    ///
82    /// # Examples
83    ///
84    /// ```no_run
85    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueCmdParams};
86    /// use jirust_cli::config::config_file::ConfigFile;
87    /// use toml::Table;
88    ///
89    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
90    /// # tokio_test::block_on(async {
91    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
92    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
93    /// let mut params = IssueCmdParams::new();
94    /// params.assignee = Some("assignee".to_string());
95    ///
96    /// let result = issue_cmd_runner.assign_jira_issue(params).await?;
97    /// # Ok(())
98    /// # })
99    /// # }
100    /// ```
101    pub async fn assign_jira_issue(
102        &self,
103        params: IssueCmdParams,
104    ) -> Result<Value, Box<dyn std::error::Error>> {
105        let user_data = User {
106            account_id: Some(params.assignee.expect("Assignee is required")),
107            account_type: Some(AccountType::Atlassian),
108            ..Default::default()
109        };
110
111        let i_key = if let Some(key) = &params.issue_key {
112            key.as_str()
113        } else {
114            return Err(Box::new(Error::other(
115                "Error assigning issue: Empty issue key".to_string(),
116            )));
117        };
118
119        Ok(assign_issue(&self.cfg, i_key, user_data).await?)
120    }
121
122    /// Creates a Jira issue
123    ///
124    /// # Arguments
125    ///
126    /// * `params` - Issue command parameters
127    ///
128    /// # Returns
129    ///
130    /// * `CreatedIssue` - Created issue
131    ///
132    /// # Examples
133    ///
134    /// ```no_run
135    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueCmdParams};
136    /// use jirust_cli::config::config_file::ConfigFile;
137    /// use toml::Table;
138    ///
139    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
140    /// # tokio_test::block_on(async {
141    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
142    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
143    /// let params = IssueCmdParams::new();
144    ///
145    /// let result = issue_cmd_runner.create_jira_issue(params).await?;
146    /// # Ok(())
147    /// # })
148    /// # }
149    /// ```
150    pub async fn create_jira_issue(
151        &self,
152        params: IssueCmdParams,
153    ) -> Result<CreatedIssue, Box<dyn std::error::Error>> {
154        let mut issue_fields = params.issue_fields.unwrap_or_default();
155        issue_fields.insert(
156            "project".to_string(),
157            serde_json::json!({"key": params.project_key.expect("Project Key is required to create an issue!")}),
158        );
159        let issue_data = IssueUpdateDetails {
160            fields: Some(issue_fields),
161            history_metadata: None,
162            properties: None,
163            transition: None,
164            update: None,
165        };
166        Ok(create_issue(&self.cfg, issue_data, None).await?)
167    }
168
169    /// Deletes a Jira issue
170    ///
171    /// # Arguments
172    ///
173    /// * `params` - Issue command parameters
174    ///
175    /// # Returns
176    ///
177    /// * `()` - Empty tuple
178    ///
179    /// # Examples
180    ///
181    /// ```no_run
182    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueCmdParams};
183    /// use jirust_cli::config::config_file::ConfigFile;
184    /// use toml::Table;
185    ///
186    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
187    /// # tokio_test::block_on(async {
188    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
189    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
190    /// let mut params = IssueCmdParams::new();
191    /// params.issue_key = Some("issue_key".to_string());
192    ///
193    /// let result = issue_cmd_runner.delete_jira_issue(params).await?;
194    /// # Ok(())
195    /// # })
196    /// # }
197    /// ```
198    pub async fn delete_jira_issue(
199        &self,
200        params: IssueCmdParams,
201    ) -> Result<(), Box<dyn std::error::Error>> {
202        let i_key = if let Some(key) = &params.issue_key {
203            key.as_str()
204        } else {
205            return Err(Box::new(Error::other(
206                "Error deleting issue: Empty issue key".to_string(),
207            )));
208        };
209
210        Ok(delete_issue(&self.cfg, i_key, Some("true")).await?)
211    }
212
213    /// Gets a Jira issue
214    ///
215    /// # Arguments
216    ///
217    /// * `params` - Issue command parameters
218    ///
219    /// # Returns
220    ///
221    /// * `IssueBean` - Jira issue
222    ///
223    /// # Examples
224    ///
225    /// ```no_run
226    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueCmdParams};
227    /// use jirust_cli::config::config_file::ConfigFile;
228    /// use toml::Table;
229    ///
230    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
231    /// # tokio_test::block_on(async {
232    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
233    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
234    /// let mut params = IssueCmdParams::new();
235    /// params.issue_key = Some("issue_key".to_string());
236    ///
237    /// let result = issue_cmd_runner.get_jira_issue(params).await?;
238    /// # Ok(())
239    /// # })
240    /// # }
241    /// ```
242    pub async fn get_jira_issue(
243        &self,
244        params: IssueCmdParams,
245    ) -> Result<IssueBean, Box<dyn std::error::Error>> {
246        let i_key = if let Some(key) = &params.issue_key {
247            key.as_str()
248        } else {
249            return Err(Box::new(Error::other(
250                "Error retrieving issue: Empty issue key".to_string(),
251            )));
252        };
253        Ok(get_issue(&self.cfg, i_key, None, None, None, None, None, None).await?)
254    }
255
256    /// This method searches for Jira issues using the provided JQL query parameters.
257    ///
258    /// # Arguments
259    ///
260    /// * `params` - Issue command parameters
261    ///
262    /// # Returns
263    ///
264    /// * `Vec<IssueBean>` - A vector of Jira issue beans
265    ///
266    /// # Examples
267    ///
268    /// ```no_run
269    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueCmdParams};
270    /// use jirust_cli::config::config_file::ConfigFile;
271    /// use toml::Table;
272    ///
273    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
274    /// # tokio_test::block_on(async {
275    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
276    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
277    /// let mut params = IssueCmdParams::new();
278    /// params.query = Some("field=value".to_string());
279    ///
280    /// let result = issue_cmd_runner.search_jira_issues(params).await?;
281    /// # Ok(())
282    /// # })
283    /// # }
284    /// ```
285    pub async fn search_jira_issues(
286        &self,
287        params: IssueCmdParams,
288    ) -> Result<Vec<IssueBean>, Box<dyn std::error::Error>> {
289        let search_params: SearchRequestBean = SearchRequestBean {
290            jql: params.query,
291            ..Default::default()
292        };
293        match search_for_issues_using_jql_post(&self.cfg, search_params).await {
294            Ok(result) => {
295                if let Some(issues) = result.issues {
296                    Ok(issues)
297                } else {
298                    Ok(vec![])
299                }
300            }
301            Err(e) => Err(Box::new(e)),
302        }
303    }
304
305    /// Transitions a Jira issue
306    ///
307    /// # Arguments
308    ///
309    /// * `params` - Issue command parameters
310    ///
311    /// # Returns
312    ///
313    /// * `Value` - Jira issue transition
314    ///
315    /// # Examples
316    ///
317    /// ```no_run
318    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueCmdParams};
319    /// use jirust_cli::config::config_file::ConfigFile;
320    /// use toml::Table;
321    ///
322    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
323    /// # tokio_test::block_on(async {
324    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
325    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
326    ///
327    /// let mut params = IssueCmdParams::new();
328    /// params.transition = Some("transition_id".to_string());
329    ///
330    /// let result = issue_cmd_runner.transition_jira_issue(params).await?;
331    /// # Ok(())
332    /// # })
333    /// # }
334    /// ```
335    pub async fn transition_jira_issue(
336        &self,
337        params: IssueCmdParams,
338    ) -> Result<Value, Box<dyn std::error::Error>> {
339        let i_key = if let Some(key) = &params.issue_key {
340            key.as_str()
341        } else {
342            return Err(Box::new(Error::other(
343                "Error with issue transition: Empty issue key".to_string(),
344            )));
345        };
346
347        let trans = if let Some(transition) = &params.transition {
348            transition.as_str()
349        } else {
350            return Err(Box::new(Error::other(
351                "Error with issue transition: Empty transition".to_string(),
352            )));
353        };
354
355        let transition = IssueTransition {
356            id: Some(trans.to_string()),
357            ..Default::default()
358        };
359        let issue_data = IssueUpdateDetails {
360            fields: params.issue_fields,
361            history_metadata: None,
362            properties: None,
363            transition: Some(transition),
364            update: None,
365        };
366        Ok(do_transition(&self.cfg, i_key, issue_data).await?)
367    }
368
369    /// Updates a Jira issue
370    ///
371    /// # Arguments
372    ///
373    /// * `params` - Issue command parameters
374    ///
375    /// # Returns
376    ///
377    /// * `Value` - Jira issue update
378    ///
379    /// # Examples
380    ///
381    /// ```no_run
382    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueCmdParams};
383    /// use jirust_cli::config::config_file::ConfigFile;
384    /// use toml::Table;
385    ///
386    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
387    /// # tokio_test::block_on(async {
388    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
389    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
390    /// let params = IssueCmdParams::new();
391    ///
392    /// let result = issue_cmd_runner.update_jira_issue(params).await?;
393    /// # Ok(())
394    /// # })
395    /// # }
396    /// ```
397    pub async fn update_jira_issue(
398        &self,
399        params: IssueCmdParams,
400    ) -> Result<Value, Box<dyn std::error::Error>> {
401        let i_key = if let Some(key) = &params.issue_key {
402            key.as_str()
403        } else {
404            return Err(Box::new(Error::other(
405                "Error updating issue: Empty issue key".to_string(),
406            )));
407        };
408
409        let issue_data = IssueUpdateDetails {
410            fields: params.issue_fields,
411            history_metadata: None,
412            properties: None,
413            transition: None,
414            update: None,
415        };
416        Ok(edit_issue(
417            &self.cfg,
418            i_key,
419            issue_data,
420            None,
421            None,
422            None,
423            Some(true),
424            None,
425        )
426        .await?)
427    }
428
429    /// Gets available transitions for a Jira issue
430    ///
431    /// # Arguments
432    ///
433    /// * `params` - Issue command parameters
434    ///
435    /// # Returns
436    ///
437    /// * `Transitions` - Jira issue transitions
438    ///
439    /// # Examples
440    ///
441    /// ```no_run
442    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::{IssueCmdRunner, IssueTransitionCmdParams};
443    /// use jirust_cli::config::config_file::ConfigFile;
444    /// use toml::Table;
445    ///
446    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
447    /// # tokio_test::block_on(async {
448    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
449    /// let issue_cmd_runner = IssueCmdRunner::new(&cfg_file);
450    /// let mut params = IssueTransitionCmdParams::new();
451    /// params.issue_key = "issue_key".to_string();
452    ///
453    /// let result = issue_cmd_runner.get_issue_available_transitions(params).await?;
454    /// # Ok(())
455    /// # })
456    /// # }
457    /// ```
458    pub async fn get_issue_available_transitions(
459        &self,
460        params: IssueTransitionCmdParams,
461    ) -> Result<Transitions, Box<dyn std::error::Error>> {
462        Ok(get_transitions(
463            &self.cfg,
464            &params.issue_key,
465            None,
466            None,
467            None,
468            Some(false),
469            None,
470        )
471        .await?)
472    }
473}
474
475/// Issue command parameters
476///
477/// # Fields
478///
479/// * `project_key` - Jira project key
480/// * `issue_key` - Jira issue key
481/// * `issue_fields` - Jira issue fields
482/// * `transition` - Jira issue transition
483/// * `assignee` - Jira issue assignee
484/// * `query` - Jira issue query
485pub struct IssueCmdParams {
486    /// Jira project key
487    pub project_key: Option<String>,
488    /// Jira issue key
489    pub issue_key: Option<String>,
490    /// Jira issue fields
491    pub issue_fields: Option<HashMap<String, Value>>,
492    /// Jira issue transition
493    pub transition: Option<String>,
494    /// Jira issue assignee
495    pub assignee: Option<String>,
496    /// Jira issue query
497    pub query: Option<String>,
498}
499
500/// Implementation of IssueCmdParams struct
501///
502/// # Methods
503///
504/// * `new` - Creates a new IssueCmdParams instance
505impl IssueCmdParams {
506    /// Creates a new IssueCmdParams instance
507    ///
508    /// # Returns
509    ///
510    /// * `IssueCmdParams` - Issue command parameters
511    ///
512    /// # Examples
513    ///
514    /// ```
515    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::IssueCmdParams;
516    ///
517    /// let params = IssueCmdParams::new();
518    /// ```
519    pub fn new() -> IssueCmdParams {
520        IssueCmdParams {
521            project_key: Some("".to_string()),
522            issue_key: None,
523            issue_fields: None,
524            transition: None,
525            assignee: None,
526            query: None,
527        }
528    }
529}
530
531/// Implementation of From trait for IssueCmdParams struct
532/// to convert IssueArgs struct to IssueCmdParams struct
533impl From<&IssueArgs> for IssueCmdParams {
534    /// Converts IssueArgs struct to IssueCmdParams struct
535    /// to create a new IssueCmdParams instance
536    ///
537    /// # Arguments
538    ///
539    /// * `value` - IssueArgs struct
540    ///
541    /// # Returns
542    ///
543    /// * `IssueCmdParams` - Issue command parameters
544    ///
545    /// # Examples
546    ///
547    /// ```
548    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::IssueCmdParams;
549    /// use jirust_cli::args::commands::{IssueArgs, PaginationArgs, OutputArgs, IssueActionValues};
550    /// use std::collections::HashMap;
551    /// use serde_json::Value;
552    ///
553    /// let issue_args = IssueArgs {
554    ///    issue_act: IssueActionValues::Get,
555    ///    project_key: Some("project_key".to_string()),
556    ///    issue_key: Some("issue_key".to_string()),
557    ///    issue_fields: Some(vec![("key".to_string(), r#"{ "key": "value" }"#.to_string())]),
558    ///    transition_to: Some("transition_to".to_string()),
559    ///    assignee: Some("assignee".to_string()),
560    ///    query: None,
561    ///    pagination: PaginationArgs { page_size: Some(20), page_offset: None },
562    ///    output: OutputArgs { output_format: None, output_type: None },
563    /// };
564    ///
565    /// let params = IssueCmdParams::from(&issue_args);
566    ///
567    /// assert_eq!(params.project_key, Some("project_key".to_string()));
568    /// assert_eq!(params.issue_key.unwrap(), "issue_key".to_string());
569    /// assert_eq!(params.transition.unwrap(), "transition_to".to_string());
570    /// assert_eq!(params.assignee.unwrap(), "assignee".to_string());
571    /// ```
572    fn from(value: &IssueArgs) -> Self {
573        IssueCmdParams {
574            project_key: value.project_key.clone(),
575            issue_key: value.issue_key.clone(),
576            issue_fields: Some(
577                value
578                    .issue_fields
579                    .clone()
580                    .unwrap_or_default()
581                    .iter()
582                    .map(|elem| {
583                        (
584                            elem.0.clone(),
585                            serde_json::from_str(elem.1.clone().as_str()).unwrap_or(Value::Null),
586                        )
587                    })
588                    .collect::<HashMap<_, _>>(),
589            ),
590            transition: value.transition_to.clone(),
591            assignee: value.assignee.clone(),
592            query: value.query.clone(),
593        }
594    }
595}
596
597/// Issue transition command parameters
598///
599/// # Fields
600///
601/// * `issue_key` - Jira issue key
602pub struct IssueTransitionCmdParams {
603    /// Jira issue key
604    pub issue_key: String,
605}
606
607/// Implementation of IssueTransitionCmdParams struct
608///
609/// # Methods
610///
611/// * `new` - Creates a new IssueTransitionCmdParams instance
612impl IssueTransitionCmdParams {
613    /// Creates a new IssueTransitionCmdParams instance
614    ///
615    /// # Returns
616    ///
617    /// * `IssueTransitionCmdParams` - Issue transition command parameters
618    ///
619    /// # Examples
620    ///
621    /// ```
622    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::IssueTransitionCmdParams;
623    ///
624    /// let params = IssueTransitionCmdParams::new();
625    /// ```
626    pub fn new() -> IssueTransitionCmdParams {
627        IssueTransitionCmdParams {
628            issue_key: "".to_string(),
629        }
630    }
631}
632
633/// Implementation of From trait for IssueTransitionCmdParams struct
634/// to convert TransitionArgs struct to IssueTransitionCmdParams struct
635impl From<&TransitionArgs> for IssueTransitionCmdParams {
636    /// Converts TransitionArgs struct to IssueTransitionCmdParams struct
637    /// to create a new IssueTransitionCmdParams instance
638    ///
639    /// # Arguments
640    ///
641    /// * `value` - TransitionArgs struct
642    ///
643    /// # Returns
644    ///
645    /// * `IssueTransitionCmdParams` - Issue transition command parameters
646    ///
647    /// # Examples
648    ///
649    /// ```
650    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::IssueTransitionCmdParams;
651    /// use jirust_cli::args::commands::{TransitionArgs, TransitionActionValues, OutputArgs};
652    ///
653    /// let transition_args = TransitionArgs {
654    ///    transition_act: TransitionActionValues::List,
655    ///    issue_key: "issue_key".to_string(),
656    ///    output: OutputArgs { output_format: None, output_type: None },
657    /// };
658    ///
659    /// let params = IssueTransitionCmdParams::from(&transition_args);
660    ///
661    /// assert_eq!(params.issue_key, "issue_key".to_string());
662    /// ```
663    fn from(value: &TransitionArgs) -> Self {
664        IssueTransitionCmdParams {
665            issue_key: value.issue_key.clone(),
666        }
667    }
668}
669
670/// Default implementation for IssueCmdParams struct
671impl Default for IssueTransitionCmdParams {
672    /// Creates a default IssueTransitionCmdParams instance
673    ///
674    /// # Returns
675    ///
676    /// A IssueTransitionCmdParams instance with default values
677    ///
678    /// # Examples
679    ///
680    /// ```
681    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::IssueTransitionCmdParams;
682    ///
683    /// let params = IssueTransitionCmdParams::default();
684    ///
685    /// assert_eq!(params.issue_key, "".to_string());
686    /// ```
687    fn default() -> Self {
688        IssueTransitionCmdParams::new()
689    }
690}
691
692/// Default implementation for IssueCmdParams struct
693impl Default for IssueCmdParams {
694    /// Creates a default IssueCmdParams instance
695    ///
696    /// # Returns
697    ///
698    /// A IssueCmdParams instance with default values
699    ///
700    /// # Examples
701    ///
702    /// ```
703    /// use jirust_cli::runners::jira_cmd_runners::issue_cmd_runner::IssueCmdParams;
704    ///
705    /// let params = IssueCmdParams::default();
706    ///
707    /// assert_eq!(params.project_key, Some("".to_string()));
708    /// assert_eq!(params.issue_key, None);
709    /// assert_eq!(params.issue_fields, None);
710    /// assert_eq!(params.transition, None);
711    /// assert_eq!(params.assignee, None);
712    /// ```
713    fn default() -> Self {
714        IssueCmdParams::new()
715    }
716}