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