Skip to content

Commit e6bd510

Browse files
committed
A script to upload release notes to Tidelift
1 parent 1083b33 commit e6bd510

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ include .editorconfig
2929
include .readthedocs.yml
3030

3131
recursive-include ci *.*
32-
exclude ci/appveyor.token
32+
exclude ci/*.token
3333

3434
recursive-include coverage/fullcoverage *.py
3535
recursive-include coverage/ctracer *.c *.h

ci/upload_relnotes.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Upload CHANGES.rst to Tidelift as Markdown chunks
4+
"""
5+
6+
import re
7+
import subprocess
8+
9+
import requests
10+
11+
class Buffer:
12+
def __init__(self):
13+
self.buffer = []
14+
15+
def append(self, text):
16+
self.buffer.append(text)
17+
18+
def clear(self):
19+
self.buffer = []
20+
21+
def flush(self):
22+
buffered = "".join(self.buffer).strip()
23+
if buffered:
24+
yield ("text", buffered)
25+
self.clear()
26+
27+
28+
def parse_md(lines):
29+
buffer = Buffer()
30+
31+
for line in lines:
32+
header_match = re.search(r"^(#+) (.+)$", line)
33+
is_header = bool(header_match)
34+
if is_header:
35+
yield from buffer.flush()
36+
hashes, text = header_match.groups()
37+
yield (f"h{len(hashes)}", text)
38+
else:
39+
buffer.append(line)
40+
yield from buffer.flush()
41+
42+
43+
def sections(parsed_data):
44+
"""Convert a stream of parsed tokens into sections with text and notes.
45+
46+
Yields a stream of:
47+
('h-level', 'header text', 'text')
48+
49+
"""
50+
header = None
51+
text = []
52+
for ttype, ttext in parsed_data:
53+
if ttype.startswith('h'):
54+
if header:
55+
yield (*header, "\n".join(text))
56+
text = []
57+
notes = []
58+
header = (ttype, ttext)
59+
elif ttype == "text":
60+
text.append(ttext)
61+
else:
62+
raise Exception(f"Don't know ttype {ttype!r}")
63+
yield (*header, "\n".join(text))
64+
65+
66+
def relnotes(mdlines):
67+
for hlevel, htext, text in sections(parse_md(mdlines)):
68+
if hlevel == 'h2' and htext.startswith('Version '):
69+
version = htext.split()[1]
70+
yield version, text
71+
72+
def convert_rst_file_to_markdown(rst_filename):
73+
markdown = subprocess.check_output(["pandoc", "-frst", "-tmarkdown_strict", "--atx-headers", rst_filename])
74+
return markdown.decode("utf8")
75+
76+
def update_release_note(package, version, text):
77+
url = f"https://api.tidelift.com/external-api/lifting/{package}/release-notes/{version}"
78+
with open("ci/tidelift.token") as ftoken:
79+
token = ftoken.read().strip()
80+
headers = {
81+
"Authorization": f"Bearer: {token}",
82+
}
83+
req_args = dict(url=url, data=text.encode('utf8'), headers=headers)
84+
result = requests.post(**req_args)
85+
if result.status_code == 409:
86+
result = requests.put(**req_args)
87+
print(f"{version}: {result.status_code}")
88+
89+
def main():
90+
markdown = convert_rst_file_to_markdown("CHANGES.rst")
91+
for version, text in relnotes(markdown.splitlines(True)):
92+
update_release_note("pypi/coverage", version, text)
93+
94+
if __name__ == "__main__":
95+
main()

howto.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@
8181
- wait for the new tag build to finish successfully.
8282
- visit https://readthedocs.org/dashboard/coverage/versions/
8383
- change the default version to the new version
84+
- Update Tidelift:
85+
- python ci/upload_relnotes.py
8486
- Visit the fixed issues on GitHub and mention the version it was fixed in.
8587
- Announce on [email protected] .
8688
- Announce on TIP.

0 commit comments

Comments
 (0)