Skip to content

Commit abff563

Browse files
authored
Add script to pre-process raw release notes (#1380)
Summary: This commit adds a helper script to pre-process the raw release notes produced by github. This script produces a template with the standard sections and pre-sorts all commits into categories based on github labels and keywords in the commit titles. ``` python scripts/clean_release_notes.py raw_release_notes.txt ``` Test Plan: Manual testing on v0.7.0 release notes
1 parent 4f8021f commit abff563

File tree

1 file changed

+225
-0
lines changed

1 file changed

+225
-0
lines changed

scripts/clean_release_notes.py

+225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
4+
# This source code is licensed under the license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# =============================================================
8+
# This script automatically cleans up the raw release notes
9+
# generated by github by doing an initial pass to sort the
10+
# commits. The output still requires manual reviewing.
11+
#
12+
# This script uses PyGithub. If you don't have it yet, please
13+
# install it using:
14+
#
15+
# pip install PyGithub
16+
#
17+
# We expect the following format for the input release notes:
18+
#
19+
# ## What's Changed
20+
# * commit1_title by @userX in https://github.com/pytorch/ao/pull/123
21+
# * commit2_title by @userY in https://github.com/pytorch/ao/pull/234
22+
# * commit3_title by @userZ in https://github.com/pytorch/ao/pull/345
23+
#
24+
# ## New Contributors
25+
# * @userX made their first contribution in https://github.com/pytorch/ao/pull/123
26+
# * @userY made their first contribution in https://github.com/pytorch/ao/pull/234
27+
#
28+
# Example output:
29+
#
30+
# ## Highlights
31+
#
32+
# We are excited to announce the X.Y.Z release of torchao! This release adds support for A, B, C, D!
33+
#
34+
# ### Highlight Feature 1
35+
#
36+
# ### Highlight Feature 2
37+
#
38+
# ## BC-Breaking
39+
#
40+
# ## Deprecation
41+
#
42+
# ## New Features
43+
# * commit1_title (https://github.com/pytorch/ao/pull/123)
44+
#
45+
# ## Improvement
46+
# * commit2_title (https://github.com/pytorch/ao/pull/234)
47+
#
48+
# ## Bug Fixes
49+
# * commit3_title (https://github.com/pytorch/ao/pull/345)
50+
#
51+
# ## Performance
52+
#
53+
# ## Documentation
54+
#
55+
# ## Developers
56+
#
57+
# ## New Contributors
58+
# * @userX made their first contribution in https://github.com/pytorch/ao/pull/123
59+
# * @userY made their first contribution in https://github.com/pytorch/ao/pull/234
60+
#
61+
# =============================================================
62+
63+
64+
import os
65+
import re
66+
import sys
67+
from typing import Dict, List, Optional
68+
69+
try:
70+
from github import Github
71+
except ImportError as err:
72+
raise ValueError("PyGithub not installed, please run 'pip install PyGithub'") from err
73+
74+
if len(sys.argv) != 2:
75+
print("Usage: python clean_release_notes.py [raw_release_notes.txt]")
76+
sys.exit(1)
77+
78+
input_file = sys.argv[1]
79+
output_file = input_file + ".out"
80+
VERBOSE = os.getenv("VERBOSE", "true").lower() == "true"
81+
GITHUB_LABEL_TO_CATEGORY = {
82+
"topic: bc-breaking": "BC Breaking",
83+
"topic: deprecation": "Deprecation",
84+
"topic: new feature": "New Features",
85+
"topic: improvement": "Improvement",
86+
"topic: bug fix": "Bug Fixes",
87+
"topic: performance": "Performance",
88+
"topic: documentation": "Documentation",
89+
"topic: for developer": "Developers",
90+
}
91+
92+
93+
def clean_release_notes():
94+
"""
95+
Main entry point for this script.
96+
97+
This function pre-processes the raw release notes and produces a template
98+
with all the standard sections and pre-sorts the commits into different
99+
categories based on github labels and commit title keywords.
100+
"""
101+
102+
# Write the header section
103+
with open(output_file, "w") as out_f:
104+
out_f.write("## Highlights\n\n")
105+
out_f.write("We are excited to announce the X.Y.Z release of torchao! This release adds support for A, B, C, D!\n\n")
106+
out_f.write("### Highlight Feature 1\n\n")
107+
out_f.write("### Highlight Feature 2\n\n")
108+
109+
# Sort commits into different categories and write them to output file
110+
# For lines after the commits, just copy them to the output file as is
111+
commit_lines = []
112+
commit_start = False
113+
commits_by_category = {
114+
"BC Breaking": [],
115+
"Deprecations": [],
116+
"New Features": [],
117+
"Improvement": [],
118+
"Bug Fixes": [],
119+
"Performance": [],
120+
"Documentation": [],
121+
"Developers": [],
122+
}
123+
with open(input_file, "r") as in_f, open(output_file, "a") as out_f:
124+
for line in in_f.readlines():
125+
if line.startswith("## What's Changed"):
126+
commit_start = True
127+
elif commit_start and line.startswith("*"):
128+
commit_lines.append(line)
129+
elif commit_start:
130+
# End of commits, fetch PR labels based on commits collected so far
131+
commit_start = False
132+
pr_number_to_label = fetch_pr_labels(commit_lines)
133+
# Assign each commit to a category
134+
for commit_line in commit_lines:
135+
category = get_commit_category(commit_line, pr_number_to_label)
136+
if category is not None:
137+
commits_by_category[category].append(commit_line)
138+
# Write all commits to the output file by category
139+
for category, commits in commits_by_category.items():
140+
out_f.write("## %s\n\n" % category)
141+
for commit_line in commits:
142+
out_f.write(format_commit(commit_line))
143+
out_f.write("\n")
144+
else:
145+
# Not a commit, just copy to the output file
146+
out_f.write(line)
147+
print("Wrote to %s." % output_file)
148+
149+
150+
def parse_pr_number(commit_line: str) -> int:
151+
"""
152+
Helper function to parse PR number from commit line.
153+
"""
154+
return int(re.match(".*pytorch/ao/pull/(.*)", commit_line).groups()[0])
155+
156+
157+
def fetch_pr_labels(commit_lines: List[str]) -> Dict[int, str]:
158+
"""
159+
Fetch the relevant github labels starting with "topic: " from all PRs.
160+
If such a label exists for a given PR, store the first one.
161+
"""
162+
pr_number_to_label = {}
163+
all_pr_numbers = [parse_pr_number(line) for line in commit_lines]
164+
smallest_pr_number = min(all_pr_numbers)
165+
repo = Github().get_repo("pytorch/ao")
166+
167+
# This call fetches 30 PRs at a time in descending order of when the PR was created
168+
pulls = repo.get_pulls(state="closed")
169+
for pr in pulls:
170+
if pr.number < smallest_pr_number:
171+
break
172+
labels = [l.name for l in pr.labels if l.name.startswith("topic: ")]
173+
if len(labels) > 0:
174+
if VERBOSE:
175+
print("Found label for PR %s: '%s'" % (pr.number, labels[0]))
176+
pr_number_to_label[pr.number] = labels[0]
177+
return pr_number_to_label
178+
179+
180+
def get_commit_category(commit_line: str, pr_number_to_label: Dict[int, str]) -> Optional[str]:
181+
"""
182+
Assign the commit to a category based on:
183+
(1) The github label if it exists
184+
(2) Keywords in the PR title
185+
186+
If the commit is not meant to be user facing, remove None.
187+
Otherwise, return "Improvement" by default.
188+
"""
189+
pr_number = parse_pr_number(commit_line)
190+
if pr_number in pr_number_to_label:
191+
label = pr_number_to_label[pr_number]
192+
if label == "topic: not user facing":
193+
return None
194+
if label in GITHUB_LABEL_TO_CATEGORY:
195+
return GITHUB_LABEL_TO_CATEGORY[label]
196+
elif any(x in commit_line.lower() for x in ["revert", "version.txt"]):
197+
return None
198+
elif any(x in commit_line.lower() for x in ["doc", "readme", "tutorial", "typo", "example", "spelling"]):
199+
return "Documentation"
200+
elif any(x in commit_line.lower() for x in ["test", "lint", " ci", "nightl"]):
201+
return "Developers"
202+
elif " fix" in commit_line.lower():
203+
return "Bug Fixes"
204+
elif " add" in commit_line.lower():
205+
return "New Features"
206+
else:
207+
return "Improvement"
208+
209+
210+
def format_commit(commit_line: str) -> str:
211+
"""
212+
Format the commit line as follows:
213+
Before: * commit title by @userX in https://github.com/pytorch/ao/pull/123
214+
After: * Commit title (https://github.com/pytorch/ao/pull/123)
215+
"""
216+
# Remove author, put PR link in parentheses
217+
commit_line = re.sub(" by @.* in (.*)", " (\g<1>)", commit_line)
218+
# Capitalize first letter
219+
commit_line = commit_line.lstrip("* ")
220+
commit_line = "* " + commit_line[0].upper() + commit_line[1:]
221+
return commit_line
222+
223+
224+
if __name__ == "__main__":
225+
clean_release_notes()

0 commit comments

Comments
 (0)