feat:(first commit)created repository and complete 0.1.0
This commit is contained in:
198
src/utils/formatter.rs
Normal file
198
src/utils/formatter.rs
Normal file
@@ -0,0 +1,198 @@
|
||||
use chrono::{DateTime, Local, Utc};
|
||||
use regex::Regex;
|
||||
|
||||
/// Format commit message with conventional commit format
|
||||
pub fn format_conventional_commit(
|
||||
commit_type: &str,
|
||||
scope: Option<&str>,
|
||||
description: &str,
|
||||
body: Option<&str>,
|
||||
footer: Option<&str>,
|
||||
breaking: bool,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
// Type and scope
|
||||
message.push_str(commit_type);
|
||||
if let Some(s) = scope {
|
||||
message.push_str(&format!("({})", s));
|
||||
}
|
||||
if breaking {
|
||||
message.push('!');
|
||||
}
|
||||
message.push_str(&format!(": {}", description));
|
||||
|
||||
// Body
|
||||
if let Some(b) = body {
|
||||
message.push_str(&format!("\n\n{}", b));
|
||||
}
|
||||
|
||||
// Footer
|
||||
if let Some(f) = footer {
|
||||
message.push_str(&format!("\n\n{}", f));
|
||||
}
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
/// Format commit with @commitlint format
|
||||
pub fn format_commitlint_commit(
|
||||
commit_type: &str,
|
||||
scope: Option<&str>,
|
||||
subject: &str,
|
||||
body: Option<&str>,
|
||||
footer: Option<&str>,
|
||||
references: Option<&[&str]>,
|
||||
) -> String {
|
||||
let mut message = String::new();
|
||||
|
||||
// Header
|
||||
message.push_str(commit_type);
|
||||
if let Some(s) = scope {
|
||||
message.push_str(&format!("({})", s));
|
||||
}
|
||||
message.push_str(&format!(": {}", subject));
|
||||
|
||||
// References
|
||||
if let Some(refs) = references {
|
||||
for reference in refs {
|
||||
message.push_str(&format!(" #{}", reference));
|
||||
}
|
||||
}
|
||||
|
||||
// Body
|
||||
if let Some(b) = body {
|
||||
message.push_str(&format!("\n\n{}", b));
|
||||
}
|
||||
|
||||
// Footer
|
||||
if let Some(f) = footer {
|
||||
message.push_str(&format!("\n\n{}", f));
|
||||
}
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
/// Format date for commit message
|
||||
pub fn format_commit_date(date: &DateTime<Local>) -> String {
|
||||
date.format("%Y-%m-%d %H:%M:%S").to_string()
|
||||
}
|
||||
|
||||
/// Format date for changelog
|
||||
pub fn format_changelog_date(date: &DateTime<Utc>) -> String {
|
||||
date.format("%Y-%m-%d").to_string()
|
||||
}
|
||||
|
||||
/// Format tag name with version
|
||||
pub fn format_tag_name(version: &str, prefix: Option<&str>) -> String {
|
||||
match prefix {
|
||||
Some(p) => format!("{}{}", p, version),
|
||||
None => version.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrap text at specified width
|
||||
pub fn wrap_text(text: &str, width: usize) -> String {
|
||||
textwrap::fill(text, width)
|
||||
}
|
||||
|
||||
/// Truncate text with ellipsis
|
||||
pub fn truncate(text: &str, max_len: usize) -> String {
|
||||
if text.len() <= max_len {
|
||||
text.to_string()
|
||||
} else {
|
||||
format!("{}...", &text[..max_len.saturating_sub(3)])
|
||||
}
|
||||
}
|
||||
|
||||
/// Clean commit message (remove comments, extra whitespace)
|
||||
pub fn clean_message(message: &str) -> String {
|
||||
let comment_regex = Regex::new(r"^#.*$").unwrap();
|
||||
|
||||
message
|
||||
.lines()
|
||||
.filter(|line| !comment_regex.is_match(line.trim()))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Format list as markdown bullet points
|
||||
pub fn format_markdown_list(items: &[String]) -> String {
|
||||
items
|
||||
.iter()
|
||||
.map(|item| format!("- {}", item))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
/// Format changelog section
|
||||
pub fn format_changelog_section(
|
||||
version: &str,
|
||||
date: &str,
|
||||
changes: &[(String, Vec<String>)],
|
||||
) -> String {
|
||||
let mut section = format!("## [{}] - {}\n\n", version, date);
|
||||
|
||||
for (category, items) in changes {
|
||||
if !items.is_empty() {
|
||||
section.push_str(&format!("### {}\n\n", category));
|
||||
for item in items {
|
||||
section.push_str(&format!("- {}\n", item));
|
||||
}
|
||||
section.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
section
|
||||
}
|
||||
|
||||
/// Format git config key
|
||||
pub fn format_git_config_key(section: &str, subsection: Option<&str>, key: &str) -> String {
|
||||
match subsection {
|
||||
Some(sub) => format!("{}.{}.{}", section, sub, key),
|
||||
None => format!("{}.{}", section, key),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_format_conventional_commit() {
|
||||
let msg = format_conventional_commit(
|
||||
"feat",
|
||||
Some("auth"),
|
||||
"add login functionality",
|
||||
Some("This adds OAuth2 login support."),
|
||||
Some("Closes #123"),
|
||||
false,
|
||||
);
|
||||
|
||||
assert!(msg.contains("feat(auth): add login functionality"));
|
||||
assert!(msg.contains("This adds OAuth2 login support."));
|
||||
assert!(msg.contains("Closes #123"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_conventional_commit_breaking() {
|
||||
let msg = format_conventional_commit(
|
||||
"feat",
|
||||
None,
|
||||
"change API response format",
|
||||
None,
|
||||
Some("BREAKING CHANGE: response format changed"),
|
||||
true,
|
||||
);
|
||||
|
||||
assert!(msg.starts_with("feat!: change API response format"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate() {
|
||||
assert_eq!(truncate("hello", 10), "hello");
|
||||
assert_eq!(truncate("hello world", 8), "hello...");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user