forked from airctic/icevision
-
Notifications
You must be signed in to change notification settings - Fork 1
/
update_changelog.py
217 lines (185 loc) · 7.41 KB
/
update_changelog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
import argparse
from io import StringIO
import json
# install Github via `pip install PyGithub`
from github import Github
def get_closed_pull_requests():
icevision_repo = g.get_repo("airctic/icevision")
pull_requests = icevision_repo.get_pulls(state="closed")
return pull_requests
def filter_pull_requests(
pull_requests,
start_pull_request_id=None,
end_pull_request_id=1,
end_is_off_by_one=False,
):
"Returns all pull requests that have the same pull request id as the given limits or are inbetween."
collected_pull_requests = []
page_counter = 0
if start_pull_request_id is None:
collect_flag = True
else:
collect_flag = False
stop_flag = False
while True:
try:
# pull requests will are sorted by newest
pull_request_page = pull_requests.get_page(page_counter)
# stop when a empty page appears as only empty pages follow onwards
if len(pull_request_page) == 0:
break
for pull_request in pull_requests:
if start_pull_request_id == pull_request.number:
collect_flag = True
if collect_flag:
collected_pull_requests.append(pull_request)
if end_pull_request_id == pull_request.number:
stop_flag = True
# if the end is off by one due to using the end of the version before the last element of the
# collected pull requests needs to be removed0
if end_is_off_by_one:
collected_pull_requests = collected_pull_requests[:-1]
break
page_counter += 1
if stop_flag:
break
except:
break
return collected_pull_requests
def extract_contribution_data_from_pull_requests(pull_requests):
data = {}
for pull_request in pull_requests:
if not pull_request.user.login in data.keys():
data[pull_request.user.login] = [
{
"title": pull_request.title,
"id": pull_request.number,
"url": pull_request.comments_url,
}
]
else:
data[pull_request.user.login].append(
{
"title": pull_request.title,
"id": pull_request.number,
"url": pull_request.comments_url,
}
)
return data
0
def clean_comment_url(url):
clean_url = url.replace("//api.github", "//github")
clean_url = clean_url.replace("/repos/", "/")
clean_url = clean_url.replace("/comments", "")
return clean_url
def create_markdown_from_pull_request_data(data, version_name=None):
version_name = "VERSION" if version_name is None else version_name
markdown = f"""[comment]: # (Version_start)
## {version_name}\nThe following PRs have been merged since the last version.\n\n"""
# add contributers with their contributions sorted by most contributions
sorted_data = sorted(data.items(), key=lambda x: len(x[1]), reverse=True)
for author, pull_requests in sorted_data:
markdown += author + "\n"
for pull_request in pull_requests:
markdown += f" - [{pull_request['title']}]({clean_comment_url(pull_request['url'])}) (#{pull_request['id']})\n"
markdown += "\n"
# add thank you notice
markdown += (
"**Thank you to all contributers: "
+ ", ".join([f"@{entry[0]}" for entry in sorted_data])
+ "**"
+ "\n\n[comment]: # (Version_end)\n\n"
)
return markdown
def load_loged_data():
try:
data = json.load(open("logs.json", "r"))
except:
data = {}
return data
def log_update(log_data, version_string, pull_requests_data):
log_data[version_string] = pull_requests_data
log_data["latest_release"] = pull_requests_data
json.dump(log_data, open("logs.json", "w"))
def get_latest_pull_request_id(log_data):
pull_request_ids = []
for contributer_pull_requests in log_data["latest_release"].values():
pull_request_ids += [
pull_request["id"] for pull_request in contributer_pull_requests
]
return max(pull_request_ids)
def load_changelogs():
change_log = open("CHANGELOG.md", "r").read()
with open("CHANGELOG_backup.md", "w") as f:
f.write(change_log)
changelogs_head, changelog_body = change_log.split(
"[comment]: # (Add changes below)"
)
return changelogs_head, changelog_body
def update_changelog_file(markdown_update_text):
changelogs_head, changelog_body = load_changelogs()
new_changelog_file = """"""
new_changelog_file = changelogs_head
new_changelog_file += "[comment]: # (Add changes below)\n\n"
new_changelog_file += markdown_update_text
new_changelog_file += changelog_body
with open("CHANGELOG.md", "w") as f:
f.write(new_changelog_file)
parser = argparse.ArgumentParser(
description="""Automatically update the CHANGELOG.md file. The script can create an update between two given PRs, were all RPs including the start and end PR are listed for the new version. Or only one can be provided.
If only the start PR is provided all PRs after wards will be used. When only the end PR is provided the PR after the one that is the end PR of the last version will be used as the start PR. If both are not given both methods described before will be combined to
get the start and end PRs."""
)
parser.add_argument(
"github_token", metavar="T", type=str, help="Access token for github."
)
parser.add_argument(
"version", metavar="V", type=str, help="String for the name of the next version"
)
parser.add_argument(
"--start_pr",
default=None,
type=int,
help="Id of the pr to start the collection of PRs looking backward in time. This should be a bigger than the value of --end_pr.",
)
parser.add_argument(
"--end_pr",
default=None,
type=int,
help="Id of the pr to end the collection of PRslooking backward in time. This sould be smaller than the value of --start_pr",
)
if __name__ == "__main__":
args = parser.parse_args()
# load changelog data
print("Loading changelog data.")
changelog_data = load_loged_data()
end_pull_request_id_is_off_by_one = False
if args.start_pr is None:
start_pull_request_id = get_latest_pull_request_id(changelog_data)
end_pull_request_id_is_off_by_one = True
else:
start_pull_request_id = args.start_pr
print(f"Starting from PR: {start_pull_request_id}")
# generate markdown for new release
print(f"Generating markdown for new version: {args.version}")
g = Github(args.github_token)
pull_requests = get_closed_pull_requests()
selected_pull_requests = filter_pull_requests(
pull_requests,
end_pull_request_id=start_pull_request_id,
start_pull_request_id=args.end_pr,
end_is_off_by_one=end_pull_request_id_is_off_by_one,
)
pull_requests_data = extract_contribution_data_from_pull_requests(
selected_pull_requests
)
markdown_update = create_markdown_from_pull_request_data(
pull_requests_data, args.version
)
# apply updates
print("Updating logs and markdown.")
log_update(changelog_data, args.version, pull_requests_data)
update_changelog_file(
create_markdown_from_pull_request_data(pull_requests_data, args.version)
)
print("Done!")