Skip to content

Commit 021fa1c

Browse files
committed
create release_note_generator
1 parent bcb257e commit 021fa1c

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

scripts/release_notes_generator.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""Script to generate release notes."""
2+
3+
import argparse
4+
import os
5+
from collections import defaultdict
6+
7+
import requests
8+
9+
LABEL_TO_HEADER = {
10+
'feature request': 'New Features',
11+
'bug': 'Bugs Fixed',
12+
'internal': 'Internal',
13+
'maintenance': 'Maintenance',
14+
'customer success': 'Customer Success',
15+
'documentation': 'Documentation',
16+
'misc': 'Miscellaneous',
17+
}
18+
ISSUE_LABELS = [
19+
'documentation',
20+
'maintenance',
21+
'internal',
22+
'bug',
23+
'feature request',
24+
'customer success',
25+
]
26+
NEW_LINE = '\n'
27+
GITHUB_URL = 'https://api.github.com/repos/sdv-dev/sdmetrics'
28+
GITHUB_TOKEN = os.getenv('GH_ACCESS_TOKEN')
29+
30+
31+
def _get_milestone_number(milestone_title):
32+
url = f'{GITHUB_URL}/milestones'
33+
headers = {'Authorization': f'Bearer {GITHUB_TOKEN}'}
34+
query_params = {'milestone': milestone_title, 'state': 'all', 'per_page': 100}
35+
response = requests.get(url, headers=headers, params=query_params)
36+
body = response.json()
37+
if response.status_code != 200:
38+
raise Exception(str(body))
39+
milestones = body
40+
for milestone in milestones:
41+
if milestone.get('title') == milestone_title:
42+
return milestone.get('number')
43+
raise ValueError(f'Milestone {milestone_title} not found in past 100 milestones.')
44+
45+
46+
def _get_issues_by_milestone(milestone):
47+
headers = {'Authorization': f'Bearer {GITHUB_TOKEN}'}
48+
# get milestone number
49+
milestone_number = _get_milestone_number(milestone)
50+
url = f'{GITHUB_URL}/issues'
51+
page = 1
52+
query_params = {'milestone': milestone_number, 'state': 'all'}
53+
issues = []
54+
while True:
55+
query_params['page'] = page
56+
response = requests.get(url, headers=headers, params=query_params)
57+
body = response.json()
58+
if response.status_code != 200:
59+
raise Exception(str(body))
60+
issues_on_page = body
61+
if not issues_on_page:
62+
break
63+
issues.extend(issues_on_page)
64+
page += 1
65+
return issues
66+
67+
68+
def _get_issues_by_category(release_issues):
69+
category_to_issues = defaultdict(list)
70+
for issue in release_issues:
71+
issue_title = issue['title']
72+
issue_number = issue['number']
73+
issue_url = issue['html_url']
74+
line = f'* {issue_title} - Issue [#{issue_number}]({issue_url})'
75+
assignee = issue.get('assignee')
76+
if assignee:
77+
login = assignee['login']
78+
line += f' by @{login}'
79+
# Check if any known label is marked on the issue
80+
labels = [label['name'] for label in issue['labels']]
81+
found_category = False
82+
for category in ISSUE_LABELS:
83+
if category in labels:
84+
category_to_issues[category].append(line)
85+
found_category = True
86+
break
87+
if not found_category:
88+
category_to_issues['misc'].append(line)
89+
return category_to_issues
90+
91+
92+
def _create_release_notes(issues_by_category, version, date):
93+
title = f'## v{version} - {date}'
94+
release_notes = f'{title}{NEW_LINE}{NEW_LINE}'
95+
for category in ISSUE_LABELS + ['misc']:
96+
issues = issues_by_category.get(category)
97+
if issues:
98+
section_text = (
99+
f'### {LABEL_TO_HEADER[category]}{NEW_LINE}{NEW_LINE}'
100+
f'{NEW_LINE.join(issues)}{NEW_LINE}{NEW_LINE}'
101+
)
102+
release_notes += section_text
103+
return release_notes
104+
105+
106+
def update_release_notes(release_notes):
107+
"""Add the release notes for the new release to the ``HISTORY.md``."""
108+
file_path = 'HISTORY.md'
109+
with open(file_path, 'r') as history_file:
110+
history = history_file.read()
111+
token = '# HISTORY\n\n'
112+
split_index = history.find(token) + len(token) + 1
113+
header = history[:split_index]
114+
new_notes = f'{header}{release_notes}{history[split_index:]}'
115+
with open(file_path, 'w') as new_history_file:
116+
new_history_file.write(new_notes)
117+
118+
119+
if __name__ == '__main__':
120+
parser = argparse.ArgumentParser()
121+
parser.add_argument('-v', '--version', type=str, help='Release version number (ie. v1.0.1)')
122+
parser.add_argument('-d', '--date', type=str, help='Date of release in format YYYY-MM-DD')
123+
args = parser.parse_args()
124+
release_number = args.version
125+
release_issues = _get_issues_by_milestone(release_number)
126+
issues_by_category = _get_issues_by_category(release_issues)
127+
release_notes = _create_release_notes(issues_by_category, release_number, args.date)
128+
update_release_notes(release_notes)

0 commit comments

Comments
 (0)