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:
6 files changed
+886
-717
No files matched your search
@@ -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}")
|
||||
Reference in new issue
Block a user