mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	tools: Add tools to manage API feature level changes.
This commit adds two new tools to avoid API feature level rebases: `create-api-changelog`: Generates an empty changelog file for temporarily recording API changes. `merge-api-changelogs`: Merges temporary changelog files and increments the API feature level.
This commit is contained in:
		
							
								
								
									
										32
									
								
								tools/create-api-changelog
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								tools/create-api-changelog
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
import os
 | 
			
		||||
import random
 | 
			
		||||
import subprocess
 | 
			
		||||
import sys
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 | 
			
		||||
    os.chdir(ZULIP_PATH)
 | 
			
		||||
 | 
			
		||||
    dir_path = Path("api_docs/unmerged.d")
 | 
			
		||||
    os.makedirs(dir_path, exist_ok=True)
 | 
			
		||||
 | 
			
		||||
    random_hex_value = f"{random.randint(0, 0xFFFFFF):06x}"
 | 
			
		||||
    file_path = f"{dir_path}/ZF-{random_hex_value}"
 | 
			
		||||
 | 
			
		||||
    with open(file_path, "w") as f:
 | 
			
		||||
        f.write("")
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        subprocess.run(["git", "add", file_path], check=True)
 | 
			
		||||
    except subprocess.CalledProcessError as e:
 | 
			
		||||
        print(e)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
    print(
 | 
			
		||||
        f"""Created an empty API changelog file.
 | 
			
		||||
If you've made changes to the API, document them here:
 | 
			
		||||
{file_path}
 | 
			
		||||
"""
 | 
			
		||||
    )
 | 
			
		||||
							
								
								
									
										137
									
								
								tools/merge-api-changelogs
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										137
									
								
								tools/merge-api-changelogs
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
#!/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-??????")]
 | 
			
		||||
 | 
			
		||||
    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")
 | 
			
		||||
 | 
			
		||||
    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 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}\n")
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    api_docs_path = Path("zerver/openapi/zulip.yaml")
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
                line = line.replace(temporary_feature_level, str(new_feature_level))
 | 
			
		||||
 | 
			
		||||
            if old_line != line:
 | 
			
		||||
                num_replaces += 1
 | 
			
		||||
 | 
			
		||||
            file.write(line)
 | 
			
		||||
 | 
			
		||||
    if num_replaces:
 | 
			
		||||
        print(f"Updated {api_docs_path}; {num_replaces} replaces were made.")
 | 
			
		||||
    else:
 | 
			
		||||
        print(f"No changes were made to {api_docs_path}; no matching file name found.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
		Reference in New Issue
	
	Block a user