Files
DevGen/devgen/modules/release_note_generator.py
T
sankalp fd3ce03484 feat(devgen/modules): categorize committypes and improve changelog/release note formattingAdd separate categories for Performance, Refactor, Tests, Style, and Chore; update ordering and emojis; improve remote push detection and fetch strategy; enhance error logging.
- New Features  - Introduced distinct sections for Performance, Refactor, Tests, Style, and Chore in changelog generation.
  - Added dedicated emojis for each new category.
  - Updated section ordering to reflect the new categories.
- Enhancements
  - Enhanced push logic to fetch upstream before push, avoiding non‑fast‑forward rejections.
  - Refactored `is_ahead_of_remote` with a fetch flag to reduce network calls and TOCTOU windows.
  - Improved error logging with full traceback for group processing failures.
- Bug Fixes
  - Fixed emoji mappings for "Style" and "Other Changes".
  - Corrected handling of empty upstream ref to prevent errors.
  - Ensured proper exception handling when remote branch is missing.
2026-06-06 16:27:12 +05:45

73 lines
2.2 KiB
Python

from datetime import datetime
from pathlib import Path
from devgen.modules.changelog_generator import ChangelogGenerator
from devgen.utils import configure_logger
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."""
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:
commits = groups.get(section)
if not commits:
continue
emoji = self.SECTION_EMOJIS.get(section, "")
md.append(f"### {emoji} {section}")
for c in commits:
scope = f"**{c['scope']}**: " if c["scope"] else ""
md.append(f"- {scope}{c['subject']}")
md.append("")
return "\n".join(md)
def run(self, output_file="RELEASE-NOTES.md", version="Unreleased", from_ref=""):
"""Main logic: get commits → parse → generate → write."""
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)
Path(output_file).write_text(md, encoding="utf-8")
print(f" Release notes written to {output_file}")