You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
proxysql/scripts/release-tools/fetch_prs_legacy.py

182 lines
6.0 KiB

#!/usr/bin/env python3
import subprocess
import json
import re
import sys
def run(cmd_list):
return subprocess.check_output(cmd_list, text=True).strip()
# Get merge commits since v3.0.3
merge_log = run(["git", "log", "v3.0.3..v3.0", "--merges", "--pretty=format:%H %s"])
lines = merge_log.split('\n')
pr_numbers = []
for line in lines:
if 'Merge pull request' in line:
match = re.search(r'#(\d+)', line)
if match:
pr_numbers.append(match.group(1))
print(f'Found {len(pr_numbers)} PRs')
# Fetch PR details using gh
prs = []
for num in pr_numbers:
try:
data = run(["gh", "pr", "view", str(num), "--json", "title,body,number,url,labels"])
pr = json.loads(data)
prs.append(pr)
except subprocess.CalledProcessError as e:
print(f'Failed to fetch PR {num}: {e}')
continue
# Categorize based on labels and title
categories = {
'Bug Fixes': [],
'New Features': [],
'Improvements': [],
'Documentation': [],
'Testing': [],
'Build/Packaging': [],
'Refactoring': [],
'Security': [],
'Monitoring': [],
'PostgreSQL': [],
'MySQL': [],
'Other': [],
}
def categorize(pr):
title = pr['title'].lower()
labels = [l['name'].lower() for l in pr.get('labels', [])]
# label hints
for label in labels:
if 'bug' in label:
return 'Bug Fixes'
if 'feature' in label:
return 'New Features'
if 'documentation' in label:
return 'Documentation'
if 'test' in label:
return 'Testing'
if 'security' in label:
return 'Security'
if 'refactor' in label:
return 'Refactoring'
if 'improvement' in label:
return 'Improvements'
# title keywords
if any(word in title for word in ['fix', 'bug', 'issue', 'crash', 'vulnerability', 'error']):
return 'Bug Fixes'
if any(word in title for word in ['add', 'new', 'support', 'implement', 'feature', 'introduce', 'enable']):
return 'New Features'
if any(word in title for word in ['improve', 'optimize', 'enhance', 'performance', 'better']):
return 'Improvements'
if any(word in title for word in ['doc', 'documentation', 'doxygen']):
return 'Documentation'
if any(word in title for word in ['test', 'tap', 'regression']):
return 'Testing'
if any(word in title for word in ['build', 'package', 'opensuse', 'docker']):
return 'Build/Packaging'
if any(word in title for word in ['refactor', 'cleanup', 'restructure']):
return 'Refactoring'
if any(word in title for word in ['security', 'injection', 'vulnerability']):
return 'Security'
if any(word in title for word in ['monitor', 'metric', 'log']):
return 'Monitoring'
if any(word in title for word in ['postgresql', 'pgsql', 'pg']):
return 'PostgreSQL'
if any(word in title for word in ['mysql']):
return 'MySQL'
return 'Other'
for pr in prs:
cat = categorize(pr)
categories[cat].append(pr)
# Generate markdown
output = []
output.append('# ProxySQL 3.0.4 Detailed Changelog\n')
output.append('\n')
output.append('This changelog lists all pull requests merged since ProxySQL 3.0.3.\n')
output.append('\n')
for cat in sorted(categories.keys()):
entries = categories[cat]
if not entries:
continue
output.append(f'## {cat}\n')
for pr in entries:
output.append(f'- **PR #{pr["number"]}**: [{pr["title"]}]({pr["url"]})\n')
if pr.get('body'):
# take first non-empty line as summary
lines = pr['body'].split('\n')
summary = ''
for line in lines:
if line.strip():
summary = line.strip()
break
if summary:
output.append(f' - {summary}\n')
output.append('\n')
with open('CHANGELOG-3.0.4-detailed.md', 'w') as f:
f.writelines(output)
print('Generated CHANGELOG-3.0.4-detailed.md')
# Also generate a concise version for release notes
release_notes = []
release_notes.append('# ProxySQL 3.0.4 Release Notes\n')
release_notes.append('\n')
release_notes.append('ProxySQL 3.0.4 includes numerous bug fixes, improvements, and new features.\n')
release_notes.append('\n')
# New Features section
new_features = categories['New Features'] + categories['PostgreSQL'] + categories['MySQL']
if new_features:
release_notes.append('## New Features\n')
for pr in new_features:
release_notes.append(f'- {pr["title"]} [#{pr["number"]}]({pr["url"]})\n')
release_notes.append('\n')
# Bug Fixes
bug_fixes = categories['Bug Fixes'] + categories['Security']
if bug_fixes:
release_notes.append('## Bug Fixes\n')
for pr in bug_fixes:
release_notes.append(f'- {pr["title"]} [#{pr["number"]}]({pr["url"]})\n')
release_notes.append('\n')
# Improvements
improvements = categories['Improvements'] + categories['Refactoring'] + categories['Monitoring']
if improvements:
release_notes.append('## Improvements\n')
for pr in improvements:
release_notes.append(f'- {pr["title"]} [#{pr["number"]}]({pr["url"]})\n')
release_notes.append('\n')
# Documentation
if categories['Documentation']:
release_notes.append('## Documentation\n')
for pr in categories['Documentation']:
release_notes.append(f'- {pr["title"]} [#{pr["number"]}]({pr["url"]})\n')
release_notes.append('\n')
# Testing
if categories['Testing']:
release_notes.append('## Testing\n')
for pr in categories['Testing']:
release_notes.append(f'- {pr["title"]} [#{pr["number"]}]({pr["url"]})\n')
release_notes.append('\n')
# Build/Packaging
if categories['Build/Packaging']:
release_notes.append('## Build/Packaging\n')
for pr in categories['Build/Packaging']:
release_notes.append(f'- {pr["title"]} [#{pr["number"]}]({pr["url"]})\n')
release_notes.append('\n')
with open('RELEASE_NOTES-3.0.4.md', 'w') as f:
f.writelines(release_notes)
print('Generated RELEASE_NOTES-3.0.4.md')