jirust_cli/runners/
cfg_cmd_runner.rs

1use crate::config::config_file::{AuthData, ConfigFile};
2
3use rpassword::read_password;
4use std::{fs, io::BufRead, path::Path};
5
6/// ConfigCmdRunner is a struct that holds the configuration file path
7/// and provides methods to initialize, set, and show the configuration file.
8pub struct ConfigCmdRunner {
9    cfg_file: String,
10}
11
12/// Implementation of ConfigCmdRunner
13///
14/// # Methods
15///
16/// * `new(cfg_file: String) -> ConfigCmdRunner` - creates a new instance of ConfigCmdRunner
17/// * `init_file() -> Result<(), std::io::Error>` - initializes the configuration file
18/// * `set_cfg_auth(cfg: ConfigFile) -> Result<ConfigFile, std::io::Error>` - sets the authentication data in the configuration file
19/// * `set_cfg_jira(cfg: ConfigFile) -> Result<ConfigFile, std::io::Error>` - sets the Jira URL in the configuration file
20/// * `setup_cfg(cfg: ConfigFile) -> Result<(), std::io::Error>` - sets up the configuration file
21/// * `show_cfg(cfg: ConfigFile)` - shows the configuration file
22impl ConfigCmdRunner {
23    /// Creates a new instance of ConfigCmdRunner
24    ///
25    /// # Arguments
26    ///
27    /// * `cfg_file` - a String that holds the path to the configuration file
28    ///
29    /// # Returns
30    ///
31    /// * `ConfigCmdRunner` - a new instance of ConfigCmdRunner
32    ///
33    /// # Examples
34    ///
35    /// ```
36    /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
37    ///
38    /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
39    /// ```
40    pub fn new(cfg_file: String) -> ConfigCmdRunner {
41        ConfigCmdRunner { cfg_file }
42    }
43
44    /// Ensure the CLI can create or update the configuration file before asking for input.
45    fn ensure_cfg_writable(&self) -> Result<(), std::io::Error> {
46        let path = Path::new(&self.cfg_file);
47        if let Some(parent) = path.parent() {
48            if !parent.as_os_str().is_empty() && !parent.exists() {
49                fs::create_dir_all(parent)?;
50            }
51        }
52
53        fs::OpenOptions::new()
54            .write(true)
55            .create(true)
56            .open(path)
57            .map(|_| ())
58    }
59
60    /// Initializes the configuration file
61    ///
62    /// # Returns
63    ///
64    /// * `Result<(), std::io::Error>` - a Result that returns an empty tuple or an error
65    ///
66    /// # Examples
67    ///
68    /// ```
69    /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
70    ///
71    /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
72    /// cfg_runner.init_file();
73    /// ```
74    pub fn init_file(&self) -> Result<(), std::io::Error> {
75        let path = Path::new(&self.cfg_file);
76        fs::create_dir_all(path.parent().unwrap())?;
77        fs::File::create(path)?;
78        Ok(())
79    }
80
81    /// Sets the authentication data in the configuration file
82    ///
83    /// # Arguments
84    ///
85    /// * `cfg` - a ConfigFile that holds the configuration data
86    ///
87    /// # Returns
88    ///
89    /// * `Result<ConfigFile, std::io::Error>` - a Result that returns the updated ConfigFile or an error
90    ///
91    /// # Examples
92    ///
93    /// ```no_run
94    /// use jirust_cli::config::config_file::ConfigFile;
95    /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
96    ///
97    /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
98    /// let cfg = ConfigFile::default();
99    ///
100    /// cfg_runner.set_cfg_auth(cfg);
101    /// ```
102    pub fn set_cfg_auth(&self, cfg: ConfigFile) -> Result<ConfigFile, std::io::Error> {
103        self.ensure_cfg_writable()?;
104        println!("Your username: ");
105        let stdin = std::io::stdin();
106        let mut reader = stdin.lock();
107        self.read_auth_from_sources(cfg, &mut reader, read_password)
108    }
109
110    fn read_auth_from_sources<R, P>(
111        &self,
112        mut cfg: ConfigFile,
113        reader: &mut R,
114        mut password_reader: P,
115    ) -> Result<ConfigFile, std::io::Error>
116    where
117        R: BufRead,
118        P: FnMut() -> Result<String, std::io::Error>,
119    {
120        let mut user = String::new();
121        reader.read_line(&mut user)?;
122        println!("Your apikey: ");
123        let apikey = password_reader()?;
124        let config_data = AuthData::new(user, apikey);
125        cfg.set_auth_key(config_data.to_base64());
126        cfg.write_to_file(self.cfg_file.as_str())?;
127        Ok(cfg)
128    }
129
130    /// Sets the Jira URL in the configuration file
131    ///
132    /// # Arguments
133    ///
134    /// * `cfg` - a ConfigFile that holds the configuration data
135    ///
136    /// # Returns
137    ///
138    /// * `Result<ConfigFile, std::io::Error>` - a Result that returns the updated ConfigFile or an error
139    ///
140    /// # Examples
141    ///
142    /// ```no_run
143    /// use jirust_cli::config::config_file::ConfigFile;
144    /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
145    ///
146    /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
147    /// let cfg = ConfigFile::default();
148    /// cfg_runner.set_cfg_jira(cfg);
149    /// ```
150    pub fn set_cfg_jira(&self, cfg: ConfigFile) -> Result<ConfigFile, std::io::Error> {
151        self.ensure_cfg_writable()?;
152        println!("Your Jira instance URL: ");
153        let stdin = std::io::stdin();
154        let mut reader = stdin.lock();
155        self.read_jira_from_reader(cfg, &mut reader)
156    }
157
158    fn read_jira_from_reader<R>(
159        &self,
160        mut cfg: ConfigFile,
161        reader: &mut R,
162    ) -> Result<ConfigFile, std::io::Error>
163    where
164        R: BufRead,
165    {
166        let mut read_data = String::new();
167        reader.read_line(&mut read_data)?;
168        cfg.set_jira_url(read_data.clone());
169        read_data.clear();
170        println!("Default Jira issue resolution JSON Value: ");
171        reader.read_line(&mut read_data)?;
172        cfg.set_standard_resolution(read_data.clone());
173        read_data.clear();
174        println!("Default Jira issue resolution comment JSON: ");
175        reader.read_line(&mut read_data)?;
176        cfg.set_standard_resolution_comment(read_data);
177        cfg.write_to_file(self.cfg_file.as_str())?;
178        Ok(cfg)
179    }
180
181    /// Sets up the configuration file
182    ///
183    /// # Arguments
184    ///
185    /// * `cfg` - a ConfigFile that holds the configuration data
186    ///
187    /// # Returns
188    ///
189    /// * `Result<(), std::io::Error>` - a Result that returns an empty tuple or an error
190    ///
191    /// # Examples
192    ///
193    /// ```no_run
194    /// use jirust_cli::config::config_file::ConfigFile;
195    /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
196    ///
197    /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
198    /// let cfg = ConfigFile::default();
199    /// cfg_runner.setup_cfg(cfg);
200    /// ```
201    pub fn setup_cfg(&self, mut cfg: ConfigFile) -> Result<(), std::io::Error> {
202        self.init_file()?;
203        cfg = self.set_cfg_jira(cfg)?;
204        self.set_cfg_auth(cfg)?;
205        Ok(())
206    }
207
208    /// Shows the configuration file data
209    ///
210    /// # Arguments
211    ///
212    /// * `cfg` - a ConfigFile that holds the configuration data
213    ///
214    /// # Examples
215    ///
216    /// ```
217    /// use jirust_cli::config::config_file::ConfigFile;
218    /// use jirust_cli::runners::cfg_cmd_runner::ConfigCmdRunner;
219    ///
220    /// let cfg = ConfigFile::default();
221    ///
222    /// let cfg_runner = ConfigCmdRunner::new("test_path/to/config/file".to_string());
223    /// cfg_runner.show_cfg(cfg);
224    /// ```
225    pub fn show_cfg(&self, cfg: ConfigFile) {
226        println!("Auth token: {}", cfg.get_auth_key());
227        println!("Jira URL: {}", cfg.get_jira_url());
228        println!(
229            "Jira default resolution: {:?}",
230            cfg.get_standard_resolution()
231        );
232        println!(
233            "Jira default resolution comment: {:?}",
234            cfg.get_standard_resolution_comment()
235        );
236    }
237
238    #[cfg(test)]
239    pub(crate) fn set_cfg_auth_with_reader<R, P>(
240        &self,
241        cfg: ConfigFile,
242        reader: &mut R,
243        password_reader: P,
244    ) -> Result<ConfigFile, std::io::Error>
245    where
246        R: BufRead,
247        P: FnMut() -> Result<String, std::io::Error>,
248    {
249        self.ensure_cfg_writable()?;
250        self.read_auth_from_sources(cfg, reader, password_reader)
251    }
252
253    #[cfg(test)]
254    pub(crate) fn set_cfg_jira_with_reader<R>(
255        &self,
256        cfg: ConfigFile,
257        reader: &mut R,
258    ) -> Result<ConfigFile, std::io::Error>
259    where
260        R: BufRead,
261    {
262        self.ensure_cfg_writable()?;
263        self.read_jira_from_reader(cfg, reader)
264    }
265}