#!/usr/bin/env python3 import glob import os import re import subprocess import sys from pathlib import Path def get_changelog_files_list() -> list[str]: dir_path = Path("api_docs/unmerged.d") if os.path.exists(dir_path): return [os.path.basename(path) for path in glob.glob(f"{dir_path}/ZF-??????.md")] return [] def get_unmerged_changelogs() -> str: changelogs = "" dir_path = Path("api_docs/unmerged.d") changelog_files_list = get_changelog_files_list() if changelog_files_list: print(f"Unmerged changelog files: {changelog_files_list}") else: print("No unmerged changelog files found.") for file_name in changelog_files_list: file_path = Path(f"{dir_path}/{file_name}") with open(file_path) as f: changelogs += f.read().strip("\n") + "\n" return changelogs def increment_and_get_feature_level() -> int: new_feature_level = None version_file_path = Path("version.py") with open(version_file_path) as file: lines = file.readlines() new_feature_level = None with open(version_file_path, "w") as file: for line in lines: if line.startswith("API_FEATURE_LEVEL = "): match = re.search(r"\d+", line) if match: new_feature_level = int(match.group()) + 1 file.write(f"API_FEATURE_LEVEL = {new_feature_level}\n") continue file.write(line) assert new_feature_level is not None print(f"Updated API feature level: {new_feature_level - 1} -> {new_feature_level}") return new_feature_level def get_current_major_version() -> str | None: changelog_path = Path("api_docs/changelog.md") with open(changelog_path) as file: for line in file: match = re.search(r"## Changes in Zulip (\d+\.\d+)", line) if match: return match.group(1) return None def merge_changelogs(changelogs: str, new_feature_level: int) -> None: changelogs_merged = False changelog_path = Path("api_docs/changelog.md") with open(changelog_path) as file: lines = file.readlines() changelogs_merged = False with open(changelog_path, "w") as file: for line in lines: file.write(line) if changelogs_merged: continue if re.fullmatch(r"## Changes in Zulip \d+\.\d+\n", line): changelogs_merged = True file.write(f"\n**Feature level {new_feature_level}**\n") file.write(f"\n{changelogs}") print(f"Changelogs merged to {changelog_path}.") def update_feature_level_in_api_docs(new_feature_level: int) -> None: changelog_files_list = get_changelog_files_list() num_replaces = 0 current_version = get_current_major_version() # Get all the markdown files in api_docs folder along with zulip.yaml. api_docs_folder = Path("api_docs") api_docs_paths = list(api_docs_folder.glob("*.md")) api_docs_paths.append(Path("zerver/openapi/zulip.yaml")) for api_docs_path in api_docs_paths: with open(api_docs_path) as file: lines = file.readlines() num_replaces = 0 with open(api_docs_path, "w") as file: for line in lines: old_line = line for file_name in changelog_files_list: temporary_feature_level = file_name[: -len(".md")] pattern = rf"Zulip \d+\.\d+ \(feature level {temporary_feature_level}\)" replacement = f"Zulip {current_version} (feature level {new_feature_level})" line = re.sub(pattern, replacement, line) if old_line != line: num_replaces += 1 file.write(line) if num_replaces: print(f"Updated {api_docs_path}; {num_replaces} replaces were made.") def remove_unmerged_changelog_files() -> None: changelog_files_list = get_changelog_files_list() for file_name in changelog_files_list: os.remove(Path(f"api_docs/unmerged.d/{file_name}")) if changelog_files_list: print("Removed all the unmerged changelog files.") if __name__ == "__main__": ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) os.chdir(ZULIP_PATH) changelogs = get_unmerged_changelogs() if changelogs: new_feature_level = increment_and_get_feature_level() merge_changelogs(changelogs, new_feature_level) update_feature_level_in_api_docs(new_feature_level) remove_unmerged_changelog_files() commit_message = f"api: Increment API feature level to {new_feature_level}." try: subprocess.run(["git", "add", "-u"], check=True) subprocess.run(["git", "commit", "-m", commit_message], check=True) except subprocess.CalledProcessError as e: print(e) sys.exit(1)