diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2020-05-18 09:43:32 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2020-05-19 19:33:53 -0400 |
commit | f6d5c35f43c4172348da4efaabf83395ce0b7853 (patch) | |
tree | b13f0436e9db6e613f52d5f0b3eddbb65250a4cb /ci/upload_relnotes.py | |
parent | 7f8dd68dd6da360374603f3a352c07713a3b082d (diff) | |
download | python-coveragepy-git-f6d5c35f43c4172348da4efaabf83395ce0b7853.tar.gz |
GitHub release automation
Diffstat (limited to 'ci/upload_relnotes.py')
-rw-r--r-- | ci/upload_relnotes.py | 122 |
1 files changed, 0 insertions, 122 deletions
diff --git a/ci/upload_relnotes.py b/ci/upload_relnotes.py deleted file mode 100644 index 630f4d0a..00000000 --- a/ci/upload_relnotes.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -""" -Upload CHANGES.md to Tidelift as Markdown chunks - -Put your Tidelift API token in a file called tidelift.token alongside this -program, for example: - - user/n3IwOpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxc2ZwE4 - -Run with two arguments: the .md file to parse, and the Tidelift package name: - - python upload_relnotes.py CHANGES.md pypi/coverage - -Every section that has something that looks like a version number in it will -be uploaded as the release notes for that version. - -""" - -import os.path -import re -import sys - -import requests - -class TextChunkBuffer: - """Hold onto text chunks until needed.""" - def __init__(self): - self.buffer = [] - - def append(self, text): - """Add `text` to the buffer.""" - self.buffer.append(text) - - def clear(self): - """Clear the buffer.""" - self.buffer = [] - - def flush(self): - """Produce a ("text", text) tuple if there's anything here.""" - buffered = "".join(self.buffer).strip() - if buffered: - yield ("text", buffered) - self.clear() - - -def parse_md(lines): - """Parse markdown lines, producing (type, text) chunks.""" - buffer = TextChunkBuffer() - - for line in lines: - header_match = re.search(r"^(#+) (.+)$", line) - is_header = bool(header_match) - if is_header: - yield from buffer.flush() - hashes, text = header_match.groups() - yield (f"h{len(hashes)}", text) - else: - buffer.append(line) - - yield from buffer.flush() - - -def sections(parsed_data): - """Convert a stream of parsed tokens into sections with text and notes. - - Yields a stream of: - ('h-level', 'header text', 'text') - - """ - header = None - text = [] - for ttype, ttext in parsed_data: - if ttype.startswith('h'): - if header: - yield (*header, "\n".join(text)) - text = [] - header = (ttype, ttext) - elif ttype == "text": - text.append(ttext) - else: - raise Exception(f"Don't know ttype {ttype!r}") - yield (*header, "\n".join(text)) - - -def relnotes(mdlines): - r"""Yield (version, text) pairs from markdown lines. - - Each tuple is a separate version mentioned in the release notes. - - A version is any section with \d\.\d in the header text. - - """ - for _, htext, text in sections(parse_md(mdlines)): - m_version = re.search(r"\d+\.\d[^ ]*", htext) - if m_version: - version = m_version.group() - yield version, text - -def update_release_note(package, version, text): - """Update the release notes for one version of a package.""" - url = f"https://api.tidelift.com/external-api/lifting/{package}/release-notes/{version}" - token_file = os.path.join(os.path.dirname(__file__), "tidelift.token") - with open(token_file) as ftoken: - token = ftoken.read().strip() - headers = { - "Authorization": f"Bearer: {token}", - } - req_args = dict(url=url, data=text.encode('utf8'), headers=headers) - result = requests.post(**req_args) - if result.status_code == 409: - result = requests.put(**req_args) - print(f"{version}: {result.status_code}") - -def parse_and_upload(md_filename, package): - """Main function: parse markdown and upload to Tidelift.""" - with open(md_filename) as f: - markdown = f.read() - for version, text in relnotes(markdown.splitlines(True)): - update_release_note(package, version, text) - -if __name__ == "__main__": - parse_and_upload(*sys.argv[1:]) # pylint: disable=no-value-for-parameter |