convert-release-notes.py

 1import os
 2import re
 3import requests
 4import sys
 5import textwrap
 6
 7from html import escape
 8
 9def clean_line(line: str, in_code_fence: bool) -> str:
10    line = re.sub(r"\(\[(#\d+)\]\([\w|\d\:|\/|\.|\-|_]*\)\)", lambda match: f"[{match.group(1)}]", line)
11    line = re.sub(r"\[(#\d+)\]\([\w|\d\:|\/|\.|\-|_]*\)", lambda match: f"[{match.group(1)}]", line)
12    if not in_code_fence:
13        line = line.strip()
14
15    return escape(line)
16
17
18def convert_body(body: str) -> str:
19    formatted = ""
20
21    in_code_fence = False
22    in_list = False
23    for line in body.splitlines():
24        line = clean_line(line, in_code_fence)
25        if not line:
26            continue
27        if re.search(r'\[[\w|\d|:|\/|\.|\-|_]*\]\([\w|\d|:|\/|\.|\-|_]*\)', line):
28            continue
29        line = re.sub(r"(?<!\`)`([^`\n]+)`(?!`)", lambda match: f"<code>{match.group(1)}</code>", line)
30
31        contains_code_fence = bool(re.search(r"```", line))
32        is_list = bool(re.search(r"^-\s*", line))
33
34        if in_list and not is_list:
35            formatted += "</ul>\n"
36        if (not in_code_fence and contains_code_fence) or (not in_list and is_list):
37            formatted += "<ul>\n"
38        in_list = is_list
39        in_code_fence = contains_code_fence != in_code_fence
40
41        if is_list:
42            line = re.sub(r"^-\s*", "", line)
43            line = f"    <li>{line}</li>"
44        elif in_code_fence or contains_code_fence:
45            line = f"    <li><code>    {line}</code></li>"
46        else:
47            line = f"<p>{line}</p>"
48        formatted += f"{line}\n"
49
50        if (not in_code_fence and contains_code_fence):
51            formatted += "</ul>\n"
52    if in_code_fence or in_list:
53        formatted += "</ul>\n"
54    return formatted
55
56def get_release_info(tag: str):
57    url = f"https://api.github.com/repos/zed-industries/zed/releases/tags/{tag}"
58    response = requests.get(url)
59    if response.status_code == 200:
60        return response.json()
61    else:
62        print(f"Failed to fetch release info for tag '{tag}'. Status code: {response.status_code}")
63        quit()
64
65
66if __name__ == "__main__":
67    os.chdir(sys.path[0])
68
69    if len(sys.argv) != 3:
70        print("Usage: python convert-release-notes.py <tag> <channel>")
71        sys.exit(1)
72
73    tag = sys.argv[1]
74    channel = sys.argv[2]
75
76    release_info = get_release_info(tag)
77    body = convert_body(release_info["body"])
78    version = tag.removeprefix("v").removesuffix("-pre")
79    date = release_info["published_at"]
80
81    release_info_str = f"<release version=\"{version}\" date=\"{date}\">\n"
82    release_info_str += f"    <description>\n"
83    release_info_str += textwrap.indent(body, " " * 8)
84    release_info_str += f"    </description>\n"
85    release_info_str += f"    <url>https://github.com/zed-industries/zed/releases/tag/{tag}</url>\n"
86    release_info_str += "</release>\n"
87
88    channel_releases_file = f"../../crates/zed/resources/flatpak/release-info/{channel}"
89    with open(channel_releases_file) as f:
90        old_release_info = f.read()
91    with open(channel_releases_file, "w") as f:
92        f.write(textwrap.indent(release_info_str, " " * 8) + old_release_info)
93    print(f"Added release notes from {tag} to '{channel_releases_file}'")