commit/
lib.rs

1use dialoguer::{Confirm, Editor};
2use std::fmt::{self, Display, Formatter};
3
4#[derive(Copy, Clone)]
5pub struct CommitType {
6    pub text: &'static str,
7    description: &'static str,
8}
9
10impl CommitType {
11    pub fn default_commit_types() -> [CommitType; 8] {
12        [
13            CommitType {
14                text: "feat",
15                description: "A new feature"
16            },
17            CommitType {
18                text: "fix",
19                description: "A bug fix"
20            },
21            CommitType {
22                text: "docs",
23                description: "Documentation only changes"
24            },
25            CommitType {
26                text: "style",
27                description: "Changes that do not affect the meaning of the code (white-space, fomatting, missing semi-colons, etc)"
28            },
29            CommitType {
30                text: "refactor",
31                description: "A code change that neither fixes a bug or adds a feature"
32            },
33            CommitType {
34                text: "perf",
35                description: "A code change that improves performance"
36            },
37            CommitType {
38                text: "test",
39                description: "Added, modified or removed tests"
40            },
41            CommitType {
42                text: "chore",
43                description: "Change to the build process, auxiliary tools, libraries or CI"
44            },
45        ]
46    }
47}
48
49impl Display for CommitType {
50    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
51        write!(f, "{:9}: {}", self.text, self.description)
52    }
53}
54
55pub fn get_optional_commit_body_and_footer() -> Option<String> {
56    let should_open_editor = Confirm::new()
57        .with_prompt("Do you want to write a long description?")
58        .default(false)
59        .show_default(false)
60        .interact()
61        .unwrap();
62    if should_open_editor {
63        return Editor::new().edit("").unwrap();
64    }
65    None
66}
67
68pub fn put_together_first_line(commit_type: CommitType, scope: String, subject: String) -> String {
69    let mut first_line = commit_type.text.to_string();
70    if scope.is_empty() {
71        first_line.push_str(": ");
72    } else {
73        first_line.push_str(&format!("({}): ", scope));
74    }
75    first_line.push_str(&subject.to_lowercase());
76
77    first_line
78}
79
80pub fn put_together_commit_message(
81    first_line: String,
82    optional_body_and_footer: Option<String>,
83) -> String {
84    let mut format_commit_message = first_line;
85    if let Some(text) = optional_body_and_footer {
86        format_commit_message.push_str(&format!("\n\n{}", text));
87    }
88    format_commit_message
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_commit_to_string() {
97        let fix = CommitType {
98            text: "fix",
99            description: "just for test",
100        };
101        assert_eq!(fix.to_string(), "fix      : just for test");
102    }
103
104    #[test]
105    fn test_composite_commit() {
106        let bug = CommitType {
107            text: "bug",
108            description: "a test",
109        };
110        let scope = String::from("view");
111        let subject = String::from("test example");
112        let other: Option<String> = None;
113        let first_line = put_together_first_line(bug, scope, subject);
114        let result = put_together_commit_message(first_line, other);
115        assert_eq!(result, String::from("bug(view): test example"))
116    }
117}