#!/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()