refactor(modules): restructure changelog and release note generation

Refactor to improve readability and separate concerns,
use Section enum and ordered traversal for consistent output.
This commit is contained in:
sankalp committed 2026-06-06 17:10:30 +05:45
1 parent 90ca0c0f59
commit e2ec269f16
6 files changed
+886 -717

No files matched your search

+28 -44
View File
@@ -2,71 +2,55 @@ from datetime import datetime
from pathlib import Path
from devgen.modules.changelog_generator import ChangelogGenerator
from devgen.modules.changelog_sections import Section
from devgen.utils import configure_logger
# Release-note-specific heading styles (use the same emoji, simpler heading).
RELEASE_NOTE_STYLES = {
Section.BREAKING: ("⚠️", "BREAKING CHANGES"),
Section.FEATURES: ("✨", "Features"),
Section.BUG_FIXES: ("🐛", "Bug Fixes"),
Section.PERFORMANCE: ("⚡", "Performance"),
Section.DOCUMENTATION: ("📚", "Documentation"),
Section.REFACTOR: ("♻️", "Refactor"),
Section.TESTS: ("✅", "Tests"),
Section.STYLE: ("💄", "Style"),
Section.CHORE: ("🔧", "Chore"),
Section.OTHER: ("🧹", "Other Changes"),
}
class ReleaseNotesGenerator(ChangelogGenerator):
"""Generate short, clean release notes from git history."""
SECTION_EMOJIS = {
"BREAKING CHANGES": "⚠️",
"Features": "✨",
"Bug Fixes": "🐛",
"Performance": "⚡",
"Documentation": "📚",
"Refactor": "♻️",
"Tests": "✅",
"Chore": "🔧",
"Style": "💄",
"Other Changes": "🧹",
}
def __init__(self, logger=None):
super().__init__(logger or configure_logger("devgen.releasenotes"))
def generate_release_markdown(self, groups, version="Unreleased"):
"""Generate human-friendly release notes."""
"""Render a human-friendly release-notes block."""
date_str = datetime.now().strftime("%Y-%m-%d")
md = [f"## 🚀 Release {version} — {date_str}\n"]
order = [
"BREAKING CHANGES",
"Features",
"Bug Fixes",
"Performance",
"Documentation",
"Refactor",
"Tests",
"Style",
"Chore",
"Other Changes",
]
for section in order:
out = [f"## 🚀 Release {version} — {date_str}\n"]
for section in Section.ordered():
commits = groups.get(section)
if not commits:
continue
emoji = self.SECTION_EMOJIS.get(section, "")
md.append(f"### {emoji} {section}")
emoji, heading = RELEASE_NOTE_STYLES[section]
out.append(f"### {emoji} {heading}")
for c in commits:
scope = f"**{c['scope']}**: " if c["scope"] else ""
md.append(f"- {scope}{c['subject']}")
md.append("")
return "\n".join(md)
scope = f"**{c['scope']}**: " if c.get("scope") else ""
out.append(f"- {scope}{c['subject']}")
out.append("")
return "\n".join(out)
def run(self, output_file="RELEASE-NOTES.md", version="Unreleased", from_ref=""):
"""Main logic: get commits → parse → generate → write."""
"""Fetch → parse → write release notes."""
raw_commits = self.get_commits(from_ref)
if not raw_commits or not raw_commits[0]:
print("❗ No commits found for release notes.")
return
parsed = self.parse_commits(raw_commits)
md = self.generate_release_markdown(parsed, version=version)
groups = self.parse_commits(raw_commits)
md = self.generate_release_markdown(groups, version=version)
Path(output_file).write_text(md, encoding="utf-8")
print(f" Release notes written to {output_file}")