1use core::panic;
2use std::process::Command;
3
4use anyhow::{Error, Result};
5
6use crate::cli::DryRunAndCopyFlag;
7use crate::run_mode::get_run_mode_from_options;
8use crate::run_mode::run_copy;
9use crate::run_mode::RunMode;
10use crate::template::interpolate_on_custom_val;
11use crate::template::validate_interpolation_places_on_custom_pattern;
12use crate::{
13 cli::CommitOperationArguments,
14 git_config::GitConfig,
15 template::{interpolate, validate_interpolation_places_count},
16};
17
18pub fn commit_with_formatted_message(
19 options: CommitOperationArguments,
20 config: GitConfig,
21) -> Result<(), Error> {
22 let selected_commit_format = options.use_template.key;
23
24 let _use_autocomplete_values = &options.use_template.use_autocomplete;
25 let _autocomplete_values = &config.data.autocomplete_values;
26
27 let picked_commit_format = config
28 .data
29 .commit_template_variants
30 .get(&selected_commit_format)
31 .unwrap_or_else(|| {
32 panic!(
33 "No commit template under given key {} \n \
34 You should add it prior to trying to use",
35 selected_commit_format
36 )
37 });
38
39 let is_valid = validate_interpolation_places_count(
40 picked_commit_format,
41 options.use_template.interpolate_values.len(),
42 );
43
44 if is_valid.is_err() {
45 let err: Error = is_valid.err().unwrap();
46 return Err(err);
47 }
48
49 let interpolated_commit = interpolate(
50 picked_commit_format,
51 options.use_template.interpolate_values,
52 )?;
53
54 let interpolated_commit = if options.flags.use_branch_number {
55 let branch_output = Command::new("git").arg("status").output().unwrap().stdout;
56
57 let branch_number = get_branch_number_from_git_status_output(branch_output).unwrap();
58
59 let branch_number_as_interpolate_value = vec![branch_number];
60
61 validate_interpolation_places_on_custom_pattern(
62 &interpolated_commit,
63 branch_number_as_interpolate_value.len(),
64 "{b}",
65 )
66 .unwrap();
67
68 interpolate_on_custom_val(
69 &interpolated_commit,
70 branch_number_as_interpolate_value,
71 "{b}",
72 )
73 .unwrap()
74 } else {
75 interpolated_commit
76 };
77
78 let run_mode = get_run_mode_from_options(DryRunAndCopyFlag {
79 dry_run: options.flags.dry_run,
80 copy: options.flags.copy,
81 });
82
83 return match run_mode {
84 RunMode::Normal => {
85 let cmd = Command::new("git")
86 .arg("commit")
87 .arg("-m")
88 .arg(interpolated_commit)
89 .output()
90 .unwrap()
91 .stdout;
92 println!("{}", String::from_utf8_lossy(&cmd));
93
94 Ok(())
95 }
96 RunMode::DryRun => {
97 println!(
98 "Going to run: \n \
99 git commit -m \"{}\"",
100 interpolated_commit
101 );
102 Ok(())
103 }
104 RunMode::DryRunAndCopy => {
105 let copy_command = config.data.clipboard_commands.copy;
106 println!(
107 "Going to run: \n \
108 echo 'git commit -m \"{}\"' > {}",
109 interpolated_commit, copy_command
110 );
111 Ok(())
112 }
113 RunMode::Copy => run_copy(
114 &config,
115 format!("git commit -m \"{}\"", interpolated_commit),
116 ),
117 };
118}
119
120fn get_branch_number_from_git_status_output(git_status_output: Vec<u8>) -> Result<String, Error> {
121 let higher_bound_of_digits_in_utf8 = &58;
122 let lower_bound_of_digits_in_utf8 = &47;
123 let line_with_branch_name: Vec<u8> = String::from_utf8(git_status_output)
124 .unwrap()
125 .split("\n")
126 .collect::<Vec<&str>>()[0]
127 .into();
128
129 let branch_number: Vec<u8> = line_with_branch_name
130 .into_iter()
131 .filter(|u8_char| {
132 u8_char < higher_bound_of_digits_in_utf8 && u8_char > lower_bound_of_digits_in_utf8
133 })
134 .collect();
135 let branch_number: String = String::from_utf8_lossy(&branch_number).to_string();
136 if branch_number == "" {
137 return Err(Error::msg("There is no number in branch name"));
138 }
139
140 Ok(branch_number)
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn get_branch_number_from_git_status_output_when_no_numbers_in_branch() {
149 let git_output: Vec<u8> = vec![
150 79, 110, 32, 98, 114, 97, 110, 99, 104, 32, 109, 97, 105, 110, 10, 89, 111, 117, 114,
151 32, 98, 114, 97, 110, 99, 104, 32, 105, 115, 32, 117, 112, 32, 116, 111, 32, 100, 97,
152 116, 101, 32, 119, 105, 116, 104, 32, 39, 111, 114, 105, 103, 105, 110, 47, 109, 97,
153 105, 110, 39, 46, 10, 10, 67, 104, 97, 110, 103, 101, 115, 32, 110, 111, 116, 32, 115,
154 116, 97, 103, 101, 100, 32, 102, 111, 114, 32, 99, 111, 109, 109, 105, 116, 58, 10, 32,
155 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 97, 100, 100, 32, 60, 102, 105, 108,
156 101, 62, 46, 46, 46, 34, 32, 116, 111, 32, 117, 112, 100, 97, 116, 101, 32, 119, 104,
157 97, 116, 32, 119, 105, 108, 108, 32, 98, 101, 32, 99, 111, 109, 109, 105, 116, 116,
158 101, 100, 41, 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 114, 101, 115,
159 116, 111, 114, 101, 32, 60, 102, 105, 108, 101, 62, 46, 46, 46, 34, 32, 116, 111, 32,
160 100, 105, 115, 99, 97, 114, 100, 32, 99, 104, 97, 110, 103, 101, 115, 32, 105, 110, 32,
161 119, 111, 114, 107, 105, 110, 103, 32, 100, 105, 114, 101, 99, 116, 111, 114, 121, 41,
162 10, 9, 109, 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99, 47, 98,
163 114, 97, 110, 99, 104, 46, 114, 115, 10, 9, 109, 111, 100, 105, 102, 105, 101, 100, 58,
164 32, 32, 32, 115, 114, 99, 47, 99, 111, 109, 109, 105, 116, 46, 114, 115, 10, 9, 109,
165 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99, 47, 114, 117, 110, 95,
166 109, 111, 100, 101, 46, 114, 115, 10, 10, 110, 111, 32, 99, 104, 97, 110, 103, 101,
167 115, 32, 97, 100, 100, 101, 100, 32, 116, 111, 32, 99, 111, 109, 109, 105, 116, 32, 40,
168 117, 115, 101, 32, 34, 103, 105, 116, 32, 97, 100, 100, 34, 32, 97, 110, 100, 47, 111,
169 114, 32, 34, 103, 105, 116, 32, 99, 111, 109, 109, 105, 116, 32, 45, 97, 34, 41, 10,
170 ];
171
172 let output = get_branch_number_from_git_status_output(git_output);
173 match output {
174 Ok(_) => assert!(false),
175 Err(_) => assert!(true),
176 }
177 }
178 #[test]
179 fn get_branch_number_from_git_status_output_when_no_numbers_beside_branch() {
180 let output: Vec<u8> = vec![
181 79, 110, 32, 98, 114, 97, 110, 99, 104, 32, 102, 101, 97, 116, 117, 114, 101, 47, 49,
182 50, 51, 52, 47, 115, 111, 109, 101, 116, 104, 105, 110, 103, 45, 100, 105, 102, 102,
183 101, 114, 101, 110, 116, 10, 67, 104, 97, 110, 103, 101, 115, 32, 110, 111, 116, 32,
184 115, 116, 97, 103, 101, 100, 32, 102, 111, 114, 32, 99, 111, 109, 109, 105, 116, 58,
185 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 97, 100, 100, 32, 60, 102,
186 105, 108, 101, 62, 46, 46, 46, 34, 32, 116, 111, 32, 117, 112, 100, 97, 116, 101, 32,
187 119, 104, 97, 116, 32, 119, 105, 108, 108, 32, 98, 101, 32, 99, 111, 109, 109, 105,
188 116, 116, 101, 100, 41, 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 114,
189 101, 115, 116, 111, 114, 101, 32, 60, 102, 105, 108, 101, 62, 46, 46, 46, 34, 32, 116,
190 111, 32, 100, 105, 115, 99, 97, 114, 100, 32, 99, 104, 97, 110, 103, 101, 115, 32, 105,
191 110, 32, 119, 111, 114, 107, 105, 110, 103, 32, 100, 105, 114, 101, 99, 116, 111, 114,
192 121, 41, 10, 9, 109, 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99,
193 47, 98, 114, 97, 110, 99, 104, 46, 114, 115, 10, 9, 109, 111, 100, 105, 102, 105, 101,
194 100, 58, 32, 32, 32, 115, 114, 99, 47, 99, 111, 109, 109, 105, 116, 46, 114, 115, 10,
195 9, 109, 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99, 47, 114, 117,
196 110, 95, 109, 111, 100, 101, 46, 114, 115, 10, 10, 110, 111, 32, 99, 104, 97, 110, 103,
197 101, 115, 32, 97, 100, 100, 101, 100, 32, 116, 111, 32, 99, 111, 109, 109, 105, 116,
198 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 97, 100, 100, 34, 32, 97, 110, 100,
199 47, 111, 114, 32, 34, 103, 105, 116, 32, 99, 111, 109, 109, 105, 116, 32, 45, 97, 34,
200 41, 10,
201 ];
202 let output = get_branch_number_from_git_status_output(output).unwrap();
203 assert_eq!(output, "1234");
204 }
205 #[test]
206 fn get_branch_number_from_git_status_output_when_numbers_in_files_in_status() {
207 let output: Vec<u8> = vec![
208 79, 110, 32, 98, 114, 97, 110, 99, 104, 32, 102, 101, 97, 116, 117, 114, 101, 47, 49,
209 50, 51, 52, 47, 115, 111, 109, 101, 116, 104, 105, 110, 103, 45, 100, 105, 102, 102,
210 101, 114, 101, 110, 116, 10, 67, 104, 97, 110, 103, 101, 115, 32, 110, 111, 116, 32,
211 115, 116, 97, 103, 101, 100, 32, 102, 111, 114, 32, 99, 111, 109, 109, 105, 116, 58,
212 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 97, 100, 100, 32, 60, 102,
213 105, 108, 101, 62, 46, 46, 46, 34, 32, 116, 111, 32, 117, 112, 100, 97, 116, 101, 32,
214 119, 104, 97, 116, 32, 119, 105, 108, 108, 32, 98, 101, 32, 99, 111, 109, 109, 105,
215 116, 116, 101, 100, 41, 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 114,
216 101, 115, 116, 111, 114, 101, 32, 60, 102, 105, 108, 101, 62, 46, 46, 46, 34, 32, 116,
217 111, 32, 100, 105, 115, 99, 97, 114, 100, 32, 99, 104, 97, 110, 103, 101, 115, 32, 105,
218 110, 32, 119, 111, 114, 107, 105, 110, 103, 32, 100, 105, 114, 101, 99, 116, 111, 114,
219 121, 41, 10, 9, 109, 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99,
220 47, 98, 114, 97, 110, 99, 104, 46, 114, 115, 10, 9, 109, 111, 100, 105, 102, 105, 101,
221 100, 58, 32, 32, 32, 115, 114, 99, 47, 99, 111, 109, 109, 105, 116, 46, 114, 115, 10,
222 9, 109, 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99, 47, 114, 117,
223 110, 95, 109, 111, 100, 101, 46, 114, 115, 10, 10, 85, 110, 116, 114, 97, 99, 107, 101,
224 100, 32, 102, 105, 108, 101, 115, 58, 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105,
225 116, 32, 97, 100, 100, 32, 60, 102, 105, 108, 101, 62, 46, 46, 46, 34, 32, 116, 111,
226 32, 105, 110, 99, 108, 117, 100, 101, 32, 105, 110, 32, 119, 104, 97, 116, 32, 119,
227 105, 108, 108, 32, 98, 101, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100, 41, 10, 9,
228 115, 111, 109, 101, 95, 102, 105, 108, 101, 95, 49, 50, 51, 46, 116, 120, 116, 10, 9,
229 115, 111, 109, 101, 95, 102, 105, 108, 101, 95, 55, 56, 57, 46, 116, 120, 116, 10, 10,
230 110, 111, 32, 99, 104, 97, 110, 103, 101, 115, 32, 97, 100, 100, 101, 100, 32, 116,
231 111, 32, 99, 111, 109, 109, 105, 116, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32,
232 97, 100, 100, 34, 32, 97, 110, 100, 47, 111, 114, 32, 34, 103, 105, 116, 32, 99, 111,
233 109, 109, 105, 116, 32, 45, 97, 34, 41, 10,
234 ];
235 let output = get_branch_number_from_git_status_output(output).unwrap();
236 assert_eq!(output, "1234")
237 }
238 #[test]
239 fn get_branch_number_from_git_status_output_when_numbers_only_in_files_in_status() {
240 let output: Vec<u8> = vec![
241 79, 110, 32, 98, 114, 97, 110, 99, 104, 32, 109, 97, 105, 110, 10, 89, 111, 117, 114,
242 32, 98, 114, 97, 110, 99, 104, 32, 105, 115, 32, 117, 112, 32, 116, 111, 32, 100, 97,
243 116, 101, 32, 119, 105, 116, 104, 32, 39, 111, 114, 105, 103, 105, 110, 47, 109, 97,
244 105, 110, 39, 46, 10, 10, 67, 104, 97, 110, 103, 101, 115, 32, 110, 111, 116, 32, 115,
245 116, 97, 103, 101, 100, 32, 102, 111, 114, 32, 99, 111, 109, 109, 105, 116, 58, 10, 32,
246 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 97, 100, 100, 32, 60, 102, 105, 108,
247 101, 62, 46, 46, 46, 34, 32, 116, 111, 32, 117, 112, 100, 97, 116, 101, 32, 119, 104,
248 97, 116, 32, 119, 105, 108, 108, 32, 98, 101, 32, 99, 111, 109, 109, 105, 116, 116,
249 101, 100, 41, 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 114, 101, 115,
250 116, 111, 114, 101, 32, 60, 102, 105, 108, 101, 62, 46, 46, 46, 34, 32, 116, 111, 32,
251 100, 105, 115, 99, 97, 114, 100, 32, 99, 104, 97, 110, 103, 101, 115, 32, 105, 110, 32,
252 119, 111, 114, 107, 105, 110, 103, 32, 100, 105, 114, 101, 99, 116, 111, 114, 121, 41,
253 10, 9, 109, 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99, 47, 98,
254 114, 97, 110, 99, 104, 46, 114, 115, 10, 9, 109, 111, 100, 105, 102, 105, 101, 100, 58,
255 32, 32, 32, 115, 114, 99, 47, 99, 111, 109, 109, 105, 116, 46, 114, 115, 10, 9, 109,
256 111, 100, 105, 102, 105, 101, 100, 58, 32, 32, 32, 115, 114, 99, 47, 114, 117, 110, 95,
257 109, 111, 100, 101, 46, 114, 115, 10, 10, 85, 110, 116, 114, 97, 99, 107, 101, 100, 32,
258 102, 105, 108, 101, 115, 58, 10, 32, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32,
259 97, 100, 100, 32, 60, 102, 105, 108, 101, 62, 46, 46, 46, 34, 32, 116, 111, 32, 105,
260 110, 99, 108, 117, 100, 101, 32, 105, 110, 32, 119, 104, 97, 116, 32, 119, 105, 108,
261 108, 32, 98, 101, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100, 41, 10, 9, 115, 111,
262 109, 101, 95, 102, 105, 108, 101, 95, 49, 50, 51, 46, 116, 120, 116, 10, 9, 115, 111,
263 109, 101, 95, 102, 105, 108, 101, 95, 55, 56, 57, 46, 116, 120, 116, 10, 10, 110, 111,
264 32, 99, 104, 97, 110, 103, 101, 115, 32, 97, 100, 100, 101, 100, 32, 116, 111, 32, 99,
265 111, 109, 109, 105, 116, 32, 40, 117, 115, 101, 32, 34, 103, 105, 116, 32, 97, 100,
266 100, 34, 32, 97, 110, 100, 47, 111, 114, 32, 34, 103, 105, 116, 32, 99, 111, 109, 109,
267 105, 116, 32, 45, 97, 34, 41, 10,
268 ];
269 let output = get_branch_number_from_git_status_output(output);
270 match output {
271 Ok(_) => assert!(false),
272 Err(_) => assert!(true),
273 }
274 }
275}