generate-gh-release-notes.py (2109B)
1 # mypy: disallow-untyped-defs 2 """ 3 Script used to generate a Markdown file containing only the changelog entries of a specific pytest release, which 4 is then published as a GitHub Release during deploy (see workflows/deploy.yml). 5 6 The script requires ``pandoc`` to be previously installed in the system -- we need to convert from RST (the format of 7 our CHANGELOG) into Markdown (which is required by GitHub Releases). 8 9 Requires Python3.6+. 10 """ 11 12 from pathlib import Path 13 import re 14 import sys 15 from typing import Sequence 16 17 import pypandoc 18 19 20 def extract_changelog_entries_for(version: str) -> str: 21 p = Path(__file__).parent.parent / "doc/en/changelog.rst" 22 changelog_lines = p.read_text(encoding="UTF-8").splitlines() 23 24 title_regex = re.compile(r"pytest (\d\.\d+\.\d+\w*) \(\d{4}-\d{2}-\d{2}\)") 25 consuming_version = False 26 version_lines = [] 27 for line in changelog_lines: 28 m = title_regex.match(line) 29 if m: 30 # Found the version we want: start to consume lines until we find the next version title. 31 if m.group(1) == version: 32 consuming_version = True 33 # Found a new version title while parsing the version we want: break out. 34 elif consuming_version: 35 break 36 if consuming_version: 37 version_lines.append(line) 38 39 return "\n".join(version_lines) 40 41 42 def convert_rst_to_md(text: str) -> str: 43 result = pypandoc.convert_text( 44 text, "md", format="rst", extra_args=["--wrap=preserve"] 45 ) 46 assert isinstance(result, str), repr(result) 47 return result 48 49 50 def main(argv: Sequence[str]) -> int: 51 if len(argv) != 3: 52 print("Usage: generate-gh-release-notes VERSION FILE") 53 return 2 54 55 version, filename = argv[1:3] 56 print(f"Generating GitHub release notes for version {version}") 57 rst_body = extract_changelog_entries_for(version) 58 md_body = convert_rst_to_md(rst_body) 59 Path(filename).write_text(md_body, encoding="UTF-8") 60 print() 61 print(f"Done: {filename}") 62 print() 63 return 0 64 65 66 if __name__ == "__main__": 67 sys.exit(main(sys.argv))