jirust_cli/runners/jira_cmd_runners/
version_cmd_runner.rs

1use std::collections::HashMap;
2
3use crate::args::commands::VersionArgs;
4use crate::config::config_file::{AuthData, ConfigFile};
5use crate::jira_doc_std_field;
6use crate::utils::changelog_extractor::ChangelogExtractor;
7use chrono::Utc;
8use jira_v3_openapi::apis::Error;
9use jira_v3_openapi::apis::configuration::Configuration;
10use jira_v3_openapi::apis::issues_api::{assign_issue, do_transition, edit_issue, get_transitions};
11use jira_v3_openapi::apis::project_versions_api::*;
12use jira_v3_openapi::models::user::AccountType;
13use jira_v3_openapi::models::{
14    DeleteAndReplaceVersionBean, FieldUpdateOperation, IssueTransition, IssueUpdateDetails, User,
15    Version, VersionRelatedWork,
16};
17use serde_json::Value;
18
19/// Version command runner struct
20///
21/// This struct is responsible for holding the version command runner parameters
22/// and it is used to pass the parameters to the version commands runner
23#[derive(Clone)]
24pub struct VersionCmdRunner {
25    cfg: Configuration,
26    resolution_value: Value,
27    resolution_comment: Value,
28    resolution_transition_name: Option<Vec<String>>,
29}
30
31/// Version command runner implementation.
32///
33///
34/// # Methods
35///
36/// * `new` - This method creates a new instance of the VersionCmdRunner struct
37/// * `create_jira_version` - This method creates a new Jira version
38/// * `get_jira_version` - This method gets a Jira version
39/// * `list_jira_versions` - This method lists Jira versions
40/// * `update_jira_version` - This method updates a Jira version
41/// * `delete_jira_version` - This method deletes a Jira version
42/// * `release_jira_version` - This method releases a Jira version
43/// * `archive_jira_version` - This method archives a Jira version
44impl VersionCmdRunner {
45    /// This method creates a new instance of the VersionCmdRunner struct
46    ///
47    /// # Arguments
48    ///
49    /// * `cfg_file` - A ConfigFile struct
50    ///
51    /// # Returns
52    ///
53    /// * A new instance of the VersionCmdRunner struct
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use jirust_cli::config::config_file::ConfigFile;
59    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdRunner;
60    /// use toml::Table;
61    ///
62    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
63    ///
64    /// let version_cmd_runner = VersionCmdRunner::new(&cfg_file);
65    /// ```
66    pub fn new(cfg_file: &ConfigFile) -> VersionCmdRunner {
67        let mut config = Configuration::new();
68        let auth_data = AuthData::from_base64(cfg_file.get_auth_key());
69        config.base_path = cfg_file.get_jira_url().to_string();
70        config.basic_auth = Some((auth_data.0, Some(auth_data.1)));
71        VersionCmdRunner {
72            cfg: config,
73            resolution_value: serde_json::from_str(cfg_file.get_standard_resolution().as_str())
74                .unwrap_or(Value::Null),
75            resolution_comment: serde_json::from_str(
76                format!(
77                    "{{\"body\": {}}}",
78                    jira_doc_std_field!(cfg_file.get_standard_resolution_comment().as_str())
79                )
80                .as_str(),
81            )
82            .unwrap_or(Value::Null),
83            resolution_transition_name: cfg_file.get_transition_name("resolve"),
84        }
85    }
86
87    /// This method creates a new Jira version with the given parameters
88    /// and returns the created version
89    ///
90    /// # Arguments
91    ///
92    /// * `params` - A VersionCmdParams struct
93    ///
94    /// # Returns
95    ///
96    /// * A Result containing a Version struct or a Box<dyn std::error::Error>
97    ///
98    /// # Examples
99    ///
100    /// ```no_run
101    /// use jira_v3_openapi::models::Version;
102    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
103    /// use jirust_cli::config::config_file::ConfigFile;
104    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdRunner;
105    /// use toml::Table;
106    ///
107    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
108    /// # tokio_test::block_on(async {
109    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
110    ///
111    /// let version_cmd_runner = VersionCmdRunner::new(&cfg_file);
112    /// let params = VersionCmdParams::new();
113    ///
114    /// let version = version_cmd_runner.create_jira_version(params).await?;
115    /// # Ok(())
116    /// # })
117    /// # }
118    /// ```
119    pub async fn create_jira_version(
120        &self,
121        params: VersionCmdParams,
122    ) -> Result<(Version, Option<Vec<(String, String, String, String)>>), Box<dyn std::error::Error>>
123    {
124        let version_description: Option<String>;
125        let mut resolved_issues = vec![];
126        let mut transitioned_issue: Vec<(String, String, String, String)> = vec![];
127        if Option::is_some(&params.changelog_file) {
128            let changelog_extractor = ChangelogExtractor::new(params.changelog_file.unwrap());
129            version_description = Some(changelog_extractor.extract_version_changelog().unwrap_or(
130                if Option::is_some(&params.version_description) {
131                    params.version_description.unwrap()
132                } else {
133                    "No changelog found for this version".to_string()
134                },
135            ));
136            if Option::is_some(&params.transition_issues) && params.transition_issues.unwrap() {
137                resolved_issues = changelog_extractor
138                    .extract_issues_from_changelog(
139                        &version_description.clone().unwrap(),
140                        &params.project,
141                    )
142                    .unwrap_or_default();
143            }
144        } else {
145            version_description = params.version_description;
146        }
147        let release_date =
148            if Option::is_some(&params.version_released) && params.version_released.unwrap() {
149                if Option::is_some(&params.version_release_date) {
150                    params.version_release_date
151                } else {
152                    Some(Utc::now().format("%Y-%m-%d").to_string())
153                }
154            } else {
155                None
156            };
157        let version = Version {
158            project: Some(params.project),
159            name: Some(
160                params
161                    .version_name
162                    .expect("VersionName is mandatory on cretion!"),
163            ),
164            description: version_description,
165            start_date: params.version_start_date,
166            release_date,
167            archived: params.version_archived,
168            released: params.version_released,
169            ..Default::default()
170        };
171        let version = create_version(&self.cfg, version).await?;
172        if !resolved_issues.is_empty() {
173            let user_data = if Option::is_some(&params.transition_assignee) {
174                Some(User {
175                    account_id: Some(params.transition_assignee.expect("Assignee is required")),
176                    account_type: Some(AccountType::Atlassian),
177                    ..Default::default()
178                })
179            } else {
180                None
181            };
182            for issue in resolved_issues {
183                let all_transitions: Vec<IssueTransition> = get_transitions(
184                    &self.cfg,
185                    issue.clone().as_str(),
186                    None,
187                    None,
188                    None,
189                    Some(false),
190                    None,
191                )
192                .await?
193                .transitions
194                .unwrap_or_default();
195                let transition_names: Vec<String> = self
196                    .resolution_transition_name
197                    .clone()
198                    .expect("Transition name is required and must be set in the config file");
199                let resolve_transitions: Vec<IssueTransition> = all_transitions
200                    .into_iter()
201                    .filter(|t| {
202                        transition_names.contains(&t.name.clone().unwrap_or("".to_string()))
203                    })
204                    .collect();
205                let transition_ids = resolve_transitions
206                    .into_iter()
207                    .map(|t| t.id.clone().unwrap_or("".to_string()))
208                    .collect::<Vec<String>>();
209                let transitions = transition_ids
210                    .into_iter()
211                    .map(|id| {
212                        Some(IssueTransition {
213                            id: Some(id),
214                            ..Default::default()
215                        })
216                    })
217                    .collect::<Vec<Option<IssueTransition>>>();
218                let mut update_fields_hashmap: HashMap<String, Vec<FieldUpdateOperation>> =
219                    HashMap::new();
220                let mut transition_fields_hashmap: HashMap<String, Vec<FieldUpdateOperation>> =
221                    HashMap::new();
222                let mut version_update_op = FieldUpdateOperation::new();
223                let mut version_resolution_update_field = HashMap::new();
224                let mut version_resolution_comment_op = FieldUpdateOperation::new();
225                let version_json: Value =
226                    serde_json::from_str(serde_json::to_string(&version).unwrap().as_str())
227                        .unwrap_or(Value::Null);
228                let resolution_value = self.resolution_value.clone();
229                let comment_value = self.resolution_comment.clone();
230                version_update_op.add = Some(Some(version_json));
231                version_resolution_update_field.insert("resolution".to_string(), resolution_value);
232                version_resolution_comment_op.add = Some(Some(comment_value));
233                update_fields_hashmap.insert("fixVersions".to_string(), vec![version_update_op]);
234                transition_fields_hashmap
235                    .insert("comment".to_string(), vec![version_resolution_comment_op]);
236                let issue_update_data = IssueUpdateDetails {
237                    fields: None,
238                    history_metadata: None,
239                    properties: None,
240                    transition: None,
241                    update: Some(update_fields_hashmap),
242                };
243                let mut transition_result: String = "KO".to_string();
244                if !Vec::is_empty(&transitions) {
245                    for transition in transitions {
246                        let issue_transition_data = IssueUpdateDetails {
247                            fields: Some(version_resolution_update_field.clone()),
248                            history_metadata: None,
249                            properties: None,
250                            transition: Some(transition.clone().unwrap()),
251                            update: Some(transition_fields_hashmap.clone()),
252                        };
253                        match do_transition(
254                            &self.cfg,
255                            issue.clone().as_str(),
256                            issue_transition_data,
257                        )
258                        .await
259                        {
260                            Ok(_) => {
261                                transition_result = "OK".to_string();
262                                break;
263                            }
264                            Err(Error::Serde(e)) => {
265                                if e.is_eof() {
266                                    transition_result = "OK".to_string();
267                                    break;
268                                } else {
269                                    transition_result = "KO".to_string()
270                                }
271                            }
272                            Err(_) => transition_result = "KO".to_string(),
273                        }
274                    }
275                }
276                let assign_result: String = match assign_issue(
277                    &self.cfg,
278                    issue.clone().as_str(),
279                    user_data.clone().unwrap(),
280                )
281                .await
282                {
283                    Ok(_) => "OK".to_string(),
284                    Err(Error::Serde(e)) => {
285                        if e.is_eof() {
286                            "OK".to_string()
287                        } else {
288                            "KO".to_string()
289                        }
290                    }
291                    Err(_) => "KO".to_string(),
292                };
293                let fixversion_result: String = match edit_issue(
294                    &self.cfg,
295                    issue.clone().as_str(),
296                    issue_update_data,
297                    Some(true),
298                    None,
299                    None,
300                    Some(true),
301                    None,
302                )
303                .await
304                {
305                    Ok(_) => version.clone().name.unwrap_or("".to_string()),
306                    Err(_) => "NO fixVersion set".to_string(),
307                };
308                transitioned_issue.push((
309                    issue.clone(),
310                    transition_result,
311                    assign_result,
312                    fixversion_result,
313                ));
314            }
315        }
316        Ok((
317            version,
318            if !transitioned_issue.is_empty() {
319                Some(transitioned_issue)
320            } else {
321                None
322            },
323        ))
324    }
325
326    /// This method gets a Jira version with the given parameters
327    /// and returns the version
328    /// If the version is not found, it returns an error
329    ///
330    /// # Arguments
331    ///
332    /// * `params` - A VersionCmdParams struct
333    ///
334    /// # Returns
335    ///
336    /// * A Result containing a Version struct or an Error<GetVersionError>
337    ///
338    /// # Examples
339    ///
340    /// ```no_run
341    /// use jira_v3_openapi::models::Version;
342    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
343    /// use jirust_cli::config::config_file::ConfigFile;
344    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdRunner;
345    /// use toml::Table;
346    ///
347    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
348    /// # tokio_test::block_on(async {
349    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
350    /// let version_cmd_runner = VersionCmdRunner::new(&cfg_file);
351    /// let params = VersionCmdParams::new();
352    ///
353    /// let version = version_cmd_runner.get_jira_version(params).await?;
354    /// # Ok(())
355    /// # })
356    /// # }
357    /// ```
358    pub async fn get_jira_version(
359        &self,
360        params: VersionCmdParams,
361    ) -> Result<Version, Error<GetVersionError>> {
362        get_version(
363            &self.cfg,
364            params.version_id.expect("VersionID is mandatory!").as_str(),
365            None,
366        )
367        .await
368    }
369
370    /// This method lists Jira versions with the given parameters
371    /// and returns the versions
372    /// If there are no versions, it returns an empty vector
373    /// If the version is not found, it returns an error
374    /// If the version page size is given, it returns the paginated versions
375    /// Otherwise, it returns all versions
376    ///
377    /// # Arguments
378    ///
379    /// * `params` - A VersionCmdParams struct
380    ///
381    /// # Returns
382    ///
383    /// * A Result containing a vector of Version structs or a Box<dyn std::error::Error>
384    ///
385    /// # Examples
386    ///
387    /// ```no_run
388    /// use jira_v3_openapi::models::Version;
389    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
390    /// use jirust_cli::config::config_file::ConfigFile;
391    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdRunner;
392    /// use toml::Table;
393    ///
394    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
395    /// # tokio_test::block_on(async {
396    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
397    /// let version_cmd_runner = VersionCmdRunner::new(&cfg_file);
398    /// let params = VersionCmdParams::new();
399    ///
400    /// let versions = version_cmd_runner.list_jira_versions(params).await?;
401    /// # Ok(())
402    /// # })
403    /// # }
404    /// ```
405    pub async fn list_jira_versions(
406        &self,
407        params: VersionCmdParams,
408    ) -> Result<Vec<Version>, Box<dyn std::error::Error>> {
409        if Option::is_some(&params.versions_page_size) {
410            match get_project_versions_paginated(
411                &self.cfg,
412                params.project.as_str(),
413                params.versions_page_offset,
414                params.versions_page_size,
415                None,
416                None,
417                None,
418                None,
419            )
420            .await?
421            .values
422            {
423                Some(values) => Ok(values),
424                None => Ok(vec![]),
425            }
426        } else {
427            Ok(get_project_versions(&self.cfg, params.project.as_str(), None).await?)
428        }
429    }
430
431    /// This method updates a Jira version with the given parameters
432    /// and returns the updated version
433    /// If the version is not found, it returns an error
434    /// If the version ID is not given, it returns an error
435    ///
436    /// # Arguments
437    ///
438    /// * `params` - A VersionCmdParams struct
439    ///
440    /// # Returns
441    ///
442    /// * A Result containing a Version struct or an Error<UpdateVersionError>
443    ///
444    /// # Examples
445    ///
446    /// ```no_run
447    /// use jira_v3_openapi::models::Version;
448    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
449    /// use jirust_cli::config::config_file::ConfigFile;
450    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdRunner;
451    /// use toml::Table;
452    ///
453    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
454    /// # tokio_test::block_on(async {
455    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
456    /// let version_cmd_runner = VersionCmdRunner::new(&cfg_file);
457    /// let params = VersionCmdParams::new();
458    ///
459    /// let version = version_cmd_runner.update_jira_version(params).await?;
460    /// # Ok(())
461    /// # })
462    /// # }
463    /// ```
464    pub async fn update_jira_version(
465        &self,
466        params: VersionCmdParams,
467    ) -> Result<Version, Error<UpdateVersionError>> {
468        let release_date =
469            if Option::is_some(&params.version_released) && params.version_released.unwrap() {
470                if Option::is_some(&params.version_release_date) {
471                    params.version_release_date
472                } else {
473                    Some(Utc::now().format("%Y-%m-%d").to_string())
474                }
475            } else {
476                None
477            };
478        let version = Version {
479            id: Some(params.version_id.clone().expect("VersionID is mandatory!")),
480            name: params.version_name,
481            description: params.version_description,
482            start_date: params.version_start_date,
483            release_date,
484            archived: params.version_archived,
485            released: params.version_released,
486            ..Default::default()
487        };
488        update_version(
489            &self.cfg,
490            params.version_id.expect("VersionID is mandatory!").as_str(),
491            version,
492        )
493        .await
494    }
495
496    /// This method deletes a Jira version with the given parameters
497    /// and returns the status of the deletion
498    ///
499    /// # Arguments
500    ///
501    /// * `params` - A VersionCmdParams struct
502    ///
503    /// # Returns
504    ///
505    /// * A Result containing a serde_json::Value or an Error<DeleteAndReplaceVersionError>
506    ///
507    /// # Examples
508    ///
509    /// ```no_run
510    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
511    /// use jirust_cli::config::config_file::ConfigFile;
512    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdRunner;
513    /// use toml::Table;
514    ///
515    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
516    /// # tokio_test::block_on(async {
517    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
518    /// let version_cmd_runner = VersionCmdRunner::new(&cfg_file);
519    /// let params = VersionCmdParams::new();
520    ///
521    /// let status = version_cmd_runner.delete_jira_version(params).await?;
522    /// # Ok(())
523    /// # })
524    /// # }
525    /// ```
526    pub async fn delete_jira_version(
527        &self,
528        params: VersionCmdParams,
529    ) -> Result<serde_json::Value, Error<DeleteAndReplaceVersionError>> {
530        match delete_and_replace_version(
531            &self.cfg,
532            params.version_id.expect("VersionID is mandatory!").as_str(),
533            DeleteAndReplaceVersionBean::new(),
534        )
535        .await
536        {
537            Ok(_) => Ok(serde_json::json!({"status": "success"})),
538            Err(e) => match e {
539                Error::Serde(_) => Ok(
540                    serde_json::json!({"status": "success", "warning": "Version was deleted, some issues in deserializing response!"}),
541                ),
542                _ => Err(e),
543            },
544        }
545    }
546
547    /// This method retrieves the related work for a given version.
548    ///
549    /// # Arguments
550    ///
551    /// * `params` - The parameters for the command.
552    ///
553    /// # Returns
554    ///
555    /// A `Result` containing a vector of `VersionRelatedWork` or an error.
556    ///
557    /// # Examples
558    ///
559    /// ```no_run
560    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
561    /// use jirust_cli::config::config_file::ConfigFile;
562    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdRunner;
563    /// use toml::Table;
564    ///
565    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
566    /// # tokio_test::block_on(async {
567    /// let cfg_file = ConfigFile::new("dXNlcm5hbWU6YXBpX2tleQ==".to_string(), "jira_url".to_string(), "standard_resolution".to_string(), "standard_resolution_comment".to_string(), Table::new());
568    /// let version_cmd_runner = VersionCmdRunner::new(&cfg_file);
569    /// let params = VersionCmdParams::new();
570    ///
571    /// let items = version_cmd_runner.get_jira_version_related_work(params).await?;
572    /// # Ok(())
573    /// # })
574    /// # }
575    /// ```
576    pub async fn get_jira_version_related_work(
577        &self,
578        params: VersionCmdParams,
579    ) -> Result<Vec<VersionRelatedWork>, Error<GetRelatedWorkError>> {
580        get_related_work(
581            &self.cfg,
582            params.version_id.expect("VersionID is mandatory!").as_str(),
583        )
584        .await
585    }
586}
587
588/// This struct defines the parameters for the Version commands
589///
590/// # Fields
591///
592/// * `project` - The project key, always **required**.
593/// * `project_id` - The project ID, optional.
594/// * `version_name` - The version name, optional.
595/// * `version_id` - The version ID, **required** for archive, delete, release and update.
596/// * `version_description` - The version description, optional.
597/// * `version_start_date` - The version start date, optional (default: today on create command).
598/// * `version_release_date` - The version release date, optional (default: today on release command).
599/// * `version_archived` - The version archived status, optional.
600/// * `version_released` - The version released status, optional.
601/// * `changelog_file` - The changelog file path, to be used for automatic description generation (changelog-based), optional: if set the script detects automatically the first tagged block in the changelog and use it as description
602/// * `resolve_issues` - The flag to resolve issues in the version, optional.
603/// * `versions_page_size` - The page size for the version, optional.
604/// * `versions_page_offset` - The page offset for the version, optional.
605pub struct VersionCmdParams {
606    pub project: String,
607    pub project_id: Option<i64>,
608    pub version_name: Option<String>,
609    pub version_id: Option<String>,
610    pub version_description: Option<String>,
611    pub version_start_date: Option<String>,
612    pub version_release_date: Option<String>,
613    pub version_archived: Option<bool>,
614    pub version_released: Option<bool>,
615    pub changelog_file: Option<String>,
616    pub transition_issues: Option<bool>,
617    pub transition_assignee: Option<String>,
618    pub versions_page_size: Option<i32>,
619    pub versions_page_offset: Option<i64>,
620}
621
622/// Implementation of the VersionCmdParams struct
623///
624/// # Methods
625///
626/// * `new` - returns a new VersionCmdParams struct
627/// * `merge_args` - merges the current version with the optional arguments
628/// * `mark_released` - marks the version as released
629/// * `mark_archived` - marks the version as archived
630impl VersionCmdParams {
631    /// This method returns a new VersionCmdParams struct
632    ///
633    /// # Returns
634    ///
635    /// * A VersionCmdParams struct
636    ///
637    /// # Examples
638    ///
639    /// ```
640    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
641    ///
642    /// let params = VersionCmdParams::new();
643    /// ```
644    pub fn new() -> VersionCmdParams {
645        VersionCmdParams {
646            project: "".to_string(),
647            project_id: None,
648            version_name: None,
649            version_id: None,
650            version_description: None,
651            version_start_date: None,
652            version_release_date: None,
653            version_archived: None,
654            version_released: None,
655            changelog_file: None,
656            transition_issues: None,
657            transition_assignee: None,
658            versions_page_size: None,
659            versions_page_offset: None,
660        }
661    }
662
663    /// This method merges the current version with the optional arguments
664    /// and returns a VersionCmdParams struct
665    /// If the optional arguments are not given, it uses the current version values
666    ///
667    /// # Arguments
668    ///
669    /// * `current_version` - A Version struct
670    /// * `opt_args` - An Option<&VersionArgs> struct
671    ///
672    /// # Returns
673    ///
674    /// * A VersionCmdParams struct
675    ///
676    /// # Examples
677    ///
678    /// ```
679    /// use jira_v3_openapi::models::Version;
680    /// use jirust_cli::args::commands::{VersionArgs, VersionActionValues, PaginationArgs, OutputArgs};
681    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
682    ///
683    /// let mut current_version: Version = Version::new();
684    /// current_version.id = Some("12345".to_string());
685    /// current_version.project_id = Some(9876);
686    /// current_version.project = Some("TEST_PROJECT".to_string());
687    /// current_version.name = Some("v1.0".to_string());
688    /// current_version.description = Some("This is the first version".to_string());
689    ///
690    /// let opt_args = VersionArgs {
691    ///   version_act: VersionActionValues::List,
692    ///   project_key: "project_key".to_string(),
693    ///   project_id: None,
694    ///   version_id: Some("97531".to_string()),
695    ///   version_name: Some("version_name".to_string()),
696    ///   version_description: Some("version_description".to_string()),
697    ///   version_start_date: None,
698    ///   version_release_date: None,
699    ///   version_archived: None,
700    ///   version_released: Some(true),
701    ///   changelog_file: None,
702    ///   pagination: PaginationArgs { page_size: None, page_offset: None },
703    ///   output: OutputArgs { output_format: None, output_type: None },
704    ///   transition_issues: None,
705    ///   transition_assignee: None,
706    /// };
707    ///
708    /// let params = VersionCmdParams::merge_args(current_version, Some(&opt_args));
709    ///
710    /// assert_eq!(params.project, "TEST_PROJECT".to_string());
711    /// assert_eq!(params.project_id, Some(9876));
712    /// assert_eq!(params.version_id, Some("12345".to_string()));
713    /// assert_eq!(params.version_name, Some("version_name".to_string()));
714    /// assert_eq!(params.version_description, Some("version_description".to_string()));
715    /// assert_eq!(params.version_released, Some(true));
716    /// ```
717    pub fn merge_args(
718        current_version: Version,
719        opt_args: Option<&VersionArgs>,
720    ) -> VersionCmdParams {
721        match opt_args {
722            Some(args) => VersionCmdParams {
723                project: current_version.project.clone().unwrap_or("".to_string()),
724                project_id: current_version.project_id,
725                version_id: current_version.id,
726                version_name: if Option::is_some(&args.version_name) {
727                    args.version_name.clone()
728                } else {
729                    current_version.name
730                },
731                version_description: if Option::is_some(&args.version_description) {
732                    args.version_description.clone()
733                } else {
734                    current_version.description
735                },
736                version_start_date: if Option::is_some(&args.version_start_date) {
737                    args.version_start_date.clone()
738                } else {
739                    current_version.start_date
740                },
741                version_release_date: if Option::is_some(&args.version_release_date) {
742                    args.version_release_date.clone()
743                } else {
744                    current_version.release_date
745                },
746                version_archived: if Option::is_some(&args.version_archived) {
747                    args.version_archived
748                } else {
749                    current_version.archived
750                },
751                version_released: if Option::is_some(&args.version_released) {
752                    args.version_released
753                } else {
754                    current_version.released
755                },
756                changelog_file: None,
757                transition_issues: None,
758                transition_assignee: None,
759                versions_page_size: None,
760                versions_page_offset: None,
761            },
762            None => VersionCmdParams {
763                project: current_version.project.clone().unwrap_or("".to_string()),
764                project_id: current_version.project_id,
765                version_id: current_version.id,
766                version_name: current_version.name,
767                version_description: current_version.description,
768                version_start_date: current_version.start_date,
769                version_release_date: current_version.release_date,
770                version_archived: current_version.archived,
771                version_released: current_version.released,
772                changelog_file: None,
773                transition_issues: None,
774                transition_assignee: None,
775                versions_page_size: None,
776                versions_page_offset: None,
777            },
778        }
779    }
780
781    /// This method marks the version as released
782    /// and returns a VersionCmdParams struct
783    /// It sets the version_released and version_release_date fields
784    /// with the current date
785    ///
786    /// # Arguments
787    ///
788    /// * `version` - A Version struct
789    ///
790    /// # Returns
791    ///
792    /// * A VersionCmdParams struct
793    ///
794    /// # Examples
795    ///
796    /// ```
797    /// use jira_v3_openapi::models::Version;
798    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
799    ///
800    /// let mut version: Version = Version::new();
801    /// version.id = Some("12345".to_string());
802    /// version.project_id = Some(9876);
803    /// version.project = Some("TEST_PROJECT".to_string());
804    /// version.name = Some("v1.0".to_string());
805    /// version.description = Some("This is the first version".to_string());
806    ///
807    /// assert_eq!(version.released, None);
808    ///
809    /// let params = VersionCmdParams::mark_released(version);
810    ///
811    /// assert_eq!(params.version_released, Some(true));
812    /// ```
813    pub fn mark_released(version: Version) -> VersionCmdParams {
814        let mut version_to_release = Self::merge_args(version, None);
815        version_to_release.version_released = Some(true);
816        version_to_release.version_release_date = Some(Utc::now().format("%Y-%m-%d").to_string());
817        version_to_release
818    }
819
820    /// This method marks the version as archived
821    /// and returns a VersionCmdParams struct
822    ///
823    /// # Arguments
824    ///
825    /// * `version` - A Version struct
826    ///
827    /// # Returns
828    ///
829    /// * A VersionCmdParams struct
830    ///
831    /// # Examples
832    ///
833    /// ```
834    /// use jira_v3_openapi::models::Version;
835    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
836    ///
837    /// let mut version: Version = Version::new();
838    /// version.id = Some("12345".to_string());
839    /// version.project_id = Some(9876);
840    /// version.project = Some("TEST_PROJECT".to_string());
841    /// version.name = Some("v1.0".to_string());
842    /// version.description = Some("This is the first version".to_string());
843    ///
844    /// assert_eq!(version.archived, None);
845    ///
846    /// let params = VersionCmdParams::mark_archived(version);
847    ///
848    /// assert_eq!(params.version_archived, Some(true));
849    /// ```
850    ///
851    pub fn mark_archived(version: Version) -> VersionCmdParams {
852        let mut version_to_archive = Self::merge_args(version, None);
853        version_to_archive.version_archived = Some(true);
854        version_to_archive
855    }
856}
857
858/// Implementation of the From trait for the VersionArgs struct
859/// This implementation allows the conversion of a VersionArgs struct to a VersionCmdParams struct.
860impl From<&VersionArgs> for VersionCmdParams {
861    /// This method converts the VersionArgs struct to a VersionCmdParams struct
862    /// and returns a VersionCmdParams struct
863    ///
864    /// # Arguments
865    ///
866    /// * `args` - A VersionArgs struct
867    ///
868    /// # Returns
869    ///
870    /// * A VersionCmdParams struct
871    ///
872    /// # Examples
873    ///
874    /// ```
875    /// use jirust_cli::args::commands::{VersionActionValues, VersionArgs, PaginationArgs, OutputArgs};
876    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
877    ///
878    /// let version_args = VersionArgs {
879    ///   version_act: VersionActionValues::List,
880    ///   project_key: "project_key".to_string(),
881    ///   project_id: None,
882    ///   version_id: None,
883    ///   version_name: Some("version_name".to_string()),
884    ///   version_description: Some("version_description".to_string()),
885    ///   version_start_date: None,
886    ///   version_release_date: None,
887    ///   version_archived: None,
888    ///   version_released: None,
889    ///   changelog_file: None,
890    ///   pagination: PaginationArgs { page_size: Some(10), page_offset: Some(0) },
891    ///   output: OutputArgs { output_format: None, output_type: None },
892    ///   transition_issues: None,
893    ///   transition_assignee: None,
894    /// };
895    ///
896    /// let params = VersionCmdParams::from(&version_args);
897    ///
898    /// assert_eq!(params.project, "project_key".to_string());
899    /// assert_eq!(params.version_name, Some("version_name".to_string()));
900    /// assert_eq!(params.version_description, Some("version_description".to_string()));
901    /// assert_eq!(params.versions_page_size, Some(10));
902    /// assert_eq!(params.versions_page_offset, Some(0));
903    /// ```
904    fn from(args: &VersionArgs) -> Self {
905        VersionCmdParams {
906            project: args.project_key.clone(),
907            project_id: args.project_id,
908            version_name: args.version_name.clone(),
909            version_id: args.version_id.clone(),
910            version_description: args.version_description.clone(),
911            version_start_date: Some(
912                args.version_start_date
913                    .clone()
914                    .unwrap_or(Utc::now().format("%Y-%m-%d").to_string()),
915            ),
916            version_release_date: args.version_release_date.clone(),
917            version_archived: args.version_archived,
918            version_released: args.version_released,
919            changelog_file: args.changelog_file.clone(),
920            transition_issues: args.transition_issues,
921            transition_assignee: args.transition_assignee.clone(),
922            versions_page_size: args.pagination.page_size,
923            versions_page_offset: args.pagination.page_offset,
924        }
925    }
926}
927
928/// Implementation of the Default trait for the VersionCmdParams struct
929impl Default for VersionCmdParams {
930    /// This method returns a VersionCmdParams struct with default values
931    /// and returns a VersionCmdParams struct
932    ///
933    /// # Returns
934    ///
935    /// * A VersionCmdParams struct initialized with default values
936    ///
937    /// # Examples
938    ///
939    /// ```
940    /// use jirust_cli::runners::jira_cmd_runners::version_cmd_runner::VersionCmdParams;
941    ///
942    /// let params = VersionCmdParams::default();
943    ///
944    /// assert_eq!(params.project, "".to_string());
945    /// assert_eq!(params.project_id, None);
946    /// assert_eq!(params.version_name, None);
947    /// assert_eq!(params.version_id, None);
948    /// assert_eq!(params.version_description, None);
949    /// assert_eq!(params.version_start_date, None);
950    /// assert_eq!(params.version_release_date, None);
951    /// assert_eq!(params.version_archived, None);
952    /// assert_eq!(params.version_released, None);
953    /// assert_eq!(params.changelog_file, None);
954    /// assert_eq!(params.transition_issues, None);
955    /// assert_eq!(params.transition_assignee, None);
956    /// assert_eq!(params.versions_page_size, None);
957    /// assert_eq!(params.versions_page_offset, None);
958    /// ```
959    fn default() -> Self {
960        VersionCmdParams::new()
961    }
962}