Skip to content

Commit ca2490c

Browse files
committed
refactor: enhance GitMessage validation and signoff handling 🔄
- trim title and content before validation checks - add specific error messages for empty title or content - refactor signoff appending to use final_content variable - add tracing logs for signoff addition and message creation - update Display impl to directly write formatted output Signed-off-by: mingcheng <[email protected]>
1 parent 9530398 commit ca2490c

File tree

1 file changed

+65
-16
lines changed

1 file changed

+65
-16
lines changed

src/message.rs

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,60 +9,109 @@
99
* File Created: 2025-10-16 15:06:58
1010
*
1111
* Modified By: mingcheng <[email protected]>
12-
* Last Modified: 2025-10-16 15:46:26
12+
* Last Modified: 2025-10-16 16:28:06
1313
*/
1414

1515
use crate::repository::Git;
1616
use std::{error::Error, fmt::Display};
1717
use tracing::trace;
1818

19+
/// Represents a structured Git commit message
20+
///
21+
/// A commit message consists of:
22+
/// - `title`: The first line (subject line), typically 50-72 characters
23+
/// - `content`: The body of the commit message with detailed description
1924
pub struct GitMessage {
2025
pub title: String,
2126
pub content: String,
2227
}
2328

2429
impl Display for GitMessage {
2530
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26-
self.to_string().fmt(f)
31+
// Format as: title\n\ncontent
32+
write!(f, "{}\n\n{}", self.title, self.content)
2733
}
2834
}
2935

3036
impl GitMessage {
37+
/// Create a new Git commit message
38+
///
39+
/// # Arguments
40+
/// * `repository` - The Git repository (used to get author info for signoff)
41+
/// * `title` - The commit title/subject line (will be trimmed)
42+
/// * `content` - The commit body/description (will be trimmed)
43+
/// * `signoff` - Whether to append a "Signed-off-by" line
44+
///
45+
/// # Returns
46+
/// * `Ok(GitMessage)` - A valid commit message
47+
/// * `Err` - If title or content is empty after trimming
48+
///
49+
/// # Example
50+
/// ```
51+
/// let msg = GitMessage::new(&repo, "feat: add feature", "Description here", true)?;
52+
/// ```
3153
pub fn new(
3254
repository: &Git,
3355
title: &str,
3456
content: &str,
3557
signoff: bool,
3658
) -> Result<Self, Box<dyn Error>> {
37-
if title.is_empty() || content.is_empty() {
38-
return Err("the commit message is invalid".into());
59+
// Trim inputs first to check actual content
60+
let title_trimmed = title.trim();
61+
let content_trimmed = content.trim();
62+
63+
// Validate both title and content are non-empty
64+
if title_trimmed.is_empty() {
65+
return Err("commit title cannot be empty".into());
66+
}
67+
if content_trimmed.is_empty() {
68+
return Err("commit content cannot be empty".into());
3969
}
4070

41-
let mut content = content.trim().to_string();
42-
// If the --signoff option is enabled, add signoff to the commit message
43-
if signoff {
44-
trace!("signoff option is enabled, will add signoff to the commit message");
71+
let mut final_content = content_trimmed.to_string();
4572

73+
// Append signoff line if requested
74+
if signoff {
75+
trace!("adding Signed-off-by line to commit message");
4676
let author = repository.get_author()?;
47-
// Add signoff to the commit message
48-
let _m = format!("\n\nSigned-off-by: {} <{}>", author.name, author.email);
49-
content.push_str(&_m);
77+
78+
// Ensure proper spacing before signoff
79+
final_content.push_str(&format!(
80+
"\n\nSigned-off-by: {} <{}>",
81+
author.name, author.email
82+
));
5083
}
5184

52-
trace!("the commit message is valid");
53-
trace!("title:\n{}", title.trim());
54-
trace!("content:\n{}", content);
85+
trace!("created commit message with title: {}", title_trimmed);
86+
trace!("content length: {} characters", final_content.len());
87+
5588
Ok(Self {
56-
title: title.trim().to_string(),
57-
content,
89+
title: title_trimmed.to_string(),
90+
content: final_content,
5891
})
5992
}
6093

94+
/// Check if the commit message is empty
95+
///
96+
/// Returns true only if both title and content are empty strings
6197
pub fn is_empty(&self) -> bool {
6298
self.title.is_empty() && self.content.is_empty()
6399
}
64100

101+
/// Convert the message to a formatted string suitable for git commit
102+
///
103+
/// Returns the commit message in the format: `title\n\ncontent`
65104
pub fn to_string(&self) -> String {
66105
format!("{}\n\n{}", self.title, self.content)
67106
}
107+
108+
/// Get the total character count of the commit message
109+
pub fn char_count(&self) -> usize {
110+
self.title.len() + 2 + self.content.len() // +2 for "\n\n"
111+
}
112+
113+
/// Get the number of lines in the commit message
114+
pub fn line_count(&self) -> usize {
115+
1 + self.content.lines().count() // +1 for title, +blank line is implicit
116+
}
68117
}

0 commit comments

Comments
 (0)