standard_commit/
format.rs1use crate::parse::ConventionalCommit;
2
3pub fn format(commit: &ConventionalCommit) -> String {
5 let mut msg = String::new();
6
7 msg.push_str(&commit.r#type);
9 if let Some(scope) = &commit.scope {
10 msg.push('(');
11 msg.push_str(scope);
12 msg.push(')');
13 }
14 if commit.is_breaking {
15 msg.push('!');
16 }
17 msg.push_str(": ");
18 msg.push_str(&commit.description);
19
20 if let Some(body) = &commit.body {
22 msg.push_str("\n\n");
23 msg.push_str(body);
24 }
25
26 if !commit.footers.is_empty() {
28 msg.push_str("\n\n");
29 for (i, footer) in commit.footers.iter().enumerate() {
30 if i > 0 {
31 msg.push('\n');
32 }
33 msg.push_str(&footer.token);
34 msg.push_str(": ");
35 msg.push_str(&footer.value);
36 }
37 }
38
39 msg
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use crate::parse::Footer;
46
47 #[test]
48 fn minimal() {
49 let commit = ConventionalCommit {
50 r#type: "feat".into(),
51 scope: None,
52 description: "add login".into(),
53 body: None,
54 footers: vec![],
55 is_breaking: false,
56 };
57 assert_eq!(format(&commit), "feat: add login");
58 }
59
60 #[test]
61 fn with_scope() {
62 let commit = ConventionalCommit {
63 r#type: "fix".into(),
64 scope: Some("auth".into()),
65 description: "handle tokens".into(),
66 body: None,
67 footers: vec![],
68 is_breaking: false,
69 };
70 assert_eq!(format(&commit), "fix(auth): handle tokens");
71 }
72
73 #[test]
74 fn breaking_with_bang() {
75 let commit = ConventionalCommit {
76 r#type: "feat".into(),
77 scope: None,
78 description: "remove legacy API".into(),
79 body: None,
80 footers: vec![],
81 is_breaking: true,
82 };
83 assert_eq!(format(&commit), "feat!: remove legacy API");
84 }
85
86 #[test]
87 fn with_body() {
88 let commit = ConventionalCommit {
89 r#type: "feat".into(),
90 scope: None,
91 description: "add PKCE".into(),
92 body: Some("Full PKCE flow.".into()),
93 footers: vec![],
94 is_breaking: false,
95 };
96 assert_eq!(format(&commit), "feat: add PKCE\n\nFull PKCE flow.");
97 }
98
99 #[test]
100 fn with_footers() {
101 let commit = ConventionalCommit {
102 r#type: "fix".into(),
103 scope: None,
104 description: "fix bug".into(),
105 body: None,
106 footers: vec![
107 Footer {
108 token: "Refs".into(),
109 value: "#42".into(),
110 },
111 Footer {
112 token: "Reviewed-by".into(),
113 value: "Alice".into(),
114 },
115 ],
116 is_breaking: false,
117 };
118 assert_eq!(
119 format(&commit),
120 "fix: fix bug\n\nRefs: #42\nReviewed-by: Alice"
121 );
122 }
123
124 #[test]
125 fn roundtrip() {
126 let msg = "feat(auth): add OAuth2 PKCE flow";
127 let commit = crate::parse::parse(msg).unwrap();
128 assert_eq!(format(&commit), msg);
129 }
130}