From 1e9fd7d5ede337da30fcbfba49952d1612a666ec Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 7 Jul 2025 15:41:01 +0300 Subject: [PATCH] Add scripts/gen-changelog.py --- scripts/gen-changelog.py | 106 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100755 scripts/gen-changelog.py diff --git a/scripts/gen-changelog.py b/scripts/gen-changelog.py new file mode 100755 index 000000000..6e39297a8 --- /dev/null +++ b/scripts/gen-changelog.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +import subprocess +import re +import sys +from collections import defaultdict + +def get_git_merges(prev_version): + """Get merge commits since the previous version tag.""" + try: + command = f"git log {prev_version}..HEAD | grep 'Merge '" + result = subprocess.run(command, shell=True, check=True, text=True, capture_output=True) + + merge_lines = [] + for line in result.stdout.strip().split('\n'): + if not line.strip() or "Merge:" in line: + continue + + # Extract the commit message and author + match = re.search(r"Merge '([^']+)' from ([^(]+)", line) + if match: + message = match.group(1).strip() + author = match.group(2).strip() + merge_lines.append((message, author)) + + return merge_lines + except subprocess.CalledProcessError as e: + print(f"Error: Failed to get git merge logs: {e}") + return [] + +def categorize_commits(merge_lines): + """Categorize commits into Added, Updated, Fixed.""" + categories = defaultdict(list) + + for message, author in merge_lines: + # Format the line for our output + formatted_line = f"* {message} ({author})" + + # Categorize based on keywords in the commit message + message_lower = message.lower() + if re.search(r'add|new|implement|support|initial|introduce', message_lower): + categories['Added'].append(formatted_line) + elif re.search(r'fix|bug|issue|error|crash|resolve|typo', message_lower): + categories['Fixed'].append(formatted_line) + else: + categories['Updated'].append(formatted_line) + + return categories + +def format_changelog(categories): + """Format the categorized commits into a changelog.""" + changelog = "## Unreleased\n" + + for category in ['Added', 'Updated', 'Fixed']: + changelog += f"### {category}\n" + + if not categories[category]: + changelog += "\n" + continue + + for commit_message in categories[category]: + changelog += f"{commit_message}\n" + + changelog += "\n" + + return changelog + +def main(): + if len(sys.argv) != 2: + print("Usage: python changelog_generator.py ") + print("Example: python changelog_generator.py v0.0.17") + sys.exit(1) + + prev_version = sys.argv[1] + + # Get merge commits since previous version + merge_lines = get_git_merges(prev_version) + + if not merge_lines: + print(f"No merge commits found since {prev_version}") + return + + # Categorize commits + categories = categorize_commits(merge_lines) + + # Format changelog + changelog = format_changelog(categories) + + # Output changelog + print(changelog) + + # Optionally write to file + write_to_file = input("Write to CHANGELOG.md? (y/n): ") + if write_to_file.lower() == 'y': + try: + with open("CHANGELOG.md", "r") as f: + content = f.read() + with open("CHANGELOG.md", "w") as f: + f.write(changelog + content) + print("Changelog written to CHANGELOG.md") + except FileNotFoundError: + with open("CHANGELOG.md", "w") as f: + f.write(changelog) + print("Created new CHANGELOG.md file") + +if __name__ == "__main__": + main()