use anyhow::Result;
use chrono::Utc;
use fs_err as fs;
use std::collections::HashSet;
use std::path::PathBuf;
pub fn maybe_update(
cfg: &crate::config::Config,
tag: &str,
notes: &str,
disabled: bool,
) -> Result<()> {
if disabled {
return Ok(());
}
let path = cfg
.changelog_path
.clone()
.unwrap_or_else(|| "CHANGELOG.md".into());
let mut out = String::new();
let date = Utc::now().format("%Y-%m-%d").to_string();
out.push_str(&format!("## {} {}\n\n", tag, date));
let mut usernames = HashSet::new();
for line in notes.lines() {
if line.trim_start().starts_with("- ") {
if let Some(name_part) =
line.trim_start_matches("- ").split('<').nth(1)
{
let username =
name_part.split('@').next().unwrap_or("").trim();
if !username.is_empty() {
usernames.insert(username.to_string());
}
}
}
}
let plural = usernames.len() > 1;
let header = if plural { "Authors" } else { "Author" };
let mut formatted_notes = String::new();
let mut lines = notes.lines().peekable();
while let Some(line) = lines.next() {
if line.trim().starts_with("### Authors")
|| line.trim().starts_with("### Author")
{
formatted_notes.push_str(&format!("### {}\n", header));
for l in lines.by_ref() {
if l.trim().is_empty() {
formatted_notes.push('\n');
break;
}
let mut username = "unknown";
if let Some(email_part) = l.split('<').nth(1) {
username = email_part
.split('@')
.next()
.unwrap_or("unknown")
.trim();
}
if let Some((_, count_part)) = l.rsplit_once('(') {
let count = count_part
.trim_end_matches(')')
.split_whitespace()
.next()
.unwrap_or("0")
.parse::<u32>()
.unwrap_or(0);
let word =
if count == 1 { "commit" } else { "commits" };
formatted_notes.push_str(&format!(
"- {} ({} {})\n",
username, count, word
));
} else {
formatted_notes
.push_str(&format!("- {}\n", username));
}
}
} else {
formatted_notes.push_str(line);
formatted_notes.push('\n');
}
}
out.push_str(&formatted_notes);
out.push('\n');
let p = PathBuf::from(&path);
let existing = if p.exists() {
fs::read_to_string(&p).unwrap_or_default()
} else {
String::new()
};
let mut final_doc = String::new();
if let Some(h) = &cfg.changelog_header {
if !existing.starts_with(h) {
final_doc.push_str(h);
final_doc.push('\n');
final_doc.push('\n');
}
}
final_doc.push_str(&out);
final_doc.push_str(&existing);
fs::write(&p, final_doc)?;
eprintln!("[ok] updated changelog at {}", p.display());
Ok(())
}