mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	These changes are all independent of each other; I just didn’t feel like making dozens of commits for them. Signed-off-by: Anders Kaseorg <anders@zulip.com>
		
			
				
	
	
		
			139 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python3
 | 
						|
 | 
						|
import html
 | 
						|
import os
 | 
						|
import sys
 | 
						|
from collections import defaultdict
 | 
						|
from typing import Any, Dict, List, Set
 | 
						|
 | 
						|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
 | 
						|
 | 
						|
# check for the venv
 | 
						|
from tools.lib import sanity_check
 | 
						|
 | 
						|
sanity_check.check_venv(__file__)
 | 
						|
 | 
						|
import orjson
 | 
						|
 | 
						|
Call = Dict[str, Any]
 | 
						|
 | 
						|
 | 
						|
def clean_up_pattern(s: str) -> str:
 | 
						|
    paren_level = 0
 | 
						|
    in_braces = False
 | 
						|
    result = ""
 | 
						|
    prior_char = None
 | 
						|
    for c in s:
 | 
						|
        if c == "(":
 | 
						|
            paren_level += 1
 | 
						|
        if c == "<" and prior_char == "P":
 | 
						|
            in_braces = True
 | 
						|
        if in_braces or (paren_level == 0):
 | 
						|
            if c != "?":
 | 
						|
                result += c
 | 
						|
        if c == ")":
 | 
						|
            paren_level -= 1
 | 
						|
        if c == ">":
 | 
						|
            in_braces = False
 | 
						|
        prior_char = c
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def fix_test_name(s: str) -> str:
 | 
						|
    return s.replace("zerver.tests.", "")
 | 
						|
 | 
						|
 | 
						|
def create_single_page(pattern: str, out_dir: str, href: str, calls: List[Call]) -> None:
 | 
						|
    fn = out_dir + "/" + href
 | 
						|
    with open(fn, "w") as f:
 | 
						|
        f.write(
 | 
						|
            """
 | 
						|
            <style>
 | 
						|
            .test {
 | 
						|
                margin: 20px;
 | 
						|
            }
 | 
						|
            </style>
 | 
						|
            """
 | 
						|
        )
 | 
						|
        f.write(f"<h3>{html.escape(pattern)}</h3>\n")
 | 
						|
        calls.sort(key=lambda call: call["status_code"])
 | 
						|
        for call in calls:
 | 
						|
            f.write("<hr>")
 | 
						|
            f.write("\n{}".format(fix_test_name(call["test_name"])))
 | 
						|
            f.write('<div class="test">')
 | 
						|
            f.write(call["url"])
 | 
						|
            f.write("<br>\n")
 | 
						|
            f.write(call["method"] + "<br>\n")
 | 
						|
            f.write("status code: {}<br>\n".format(call["status_code"]))
 | 
						|
            f.write("<br>")
 | 
						|
            f.write("</div>")
 | 
						|
 | 
						|
 | 
						|
def create_user_docs() -> None:
 | 
						|
    fn = "var/url_coverage.txt"  # TODO: make path more robust, maybe use json suffix
 | 
						|
 | 
						|
    out_dir = "var/api_docs"
 | 
						|
    try:
 | 
						|
        os.mkdir(out_dir)
 | 
						|
    except OSError:
 | 
						|
        pass
 | 
						|
 | 
						|
    main_page = out_dir + "/index.html"
 | 
						|
 | 
						|
    with open(main_page, "w") as f:
 | 
						|
        f.write(
 | 
						|
            """
 | 
						|
            <style>
 | 
						|
            li {
 | 
						|
                list-style-type: none;
 | 
						|
            }
 | 
						|
 | 
						|
            a {
 | 
						|
                text-decoration: none;
 | 
						|
            }
 | 
						|
            </style>
 | 
						|
            """
 | 
						|
        )
 | 
						|
 | 
						|
        with open(fn, "rb") as coverage:
 | 
						|
            calls = [orjson.loads(line) for line in coverage]
 | 
						|
 | 
						|
        pattern_dict: Dict[str, List[Call]] = defaultdict(list)
 | 
						|
        for call in calls:
 | 
						|
            if "pattern" in call:
 | 
						|
                pattern = clean_up_pattern(call["pattern"])
 | 
						|
                if pattern:
 | 
						|
                    pattern_dict[pattern].append(call)
 | 
						|
 | 
						|
        patterns = set(pattern_dict.keys())
 | 
						|
 | 
						|
        tups = [
 | 
						|
            ("api/v1/external", "webhooks"),
 | 
						|
            ("api/v1", "api"),
 | 
						|
            ("json", "legacy"),
 | 
						|
        ]
 | 
						|
 | 
						|
        groups: Dict[str, Set[str]] = {}
 | 
						|
        for prefix, name in tups:
 | 
						|
            groups[name] = {p for p in patterns if p.startswith(prefix)}
 | 
						|
            patterns -= groups[name]
 | 
						|
 | 
						|
        groups["other"] = patterns
 | 
						|
 | 
						|
        for name in ["api", "legacy", "webhooks", "other"]:
 | 
						|
            f.write(name + " endpoints:\n\n")
 | 
						|
            f.write("<ul>\n")
 | 
						|
            for pattern in sorted(groups[name]):
 | 
						|
                href = pattern.replace("/", "-") + ".html"
 | 
						|
                link = f'<a href="{href}">{html.escape(pattern)}</a>'
 | 
						|
                f.write("<li>" + link + "</li>\n")
 | 
						|
                create_single_page(pattern, out_dir, href, pattern_dict[pattern])
 | 
						|
            f.write("</ul>")
 | 
						|
            f.write("\n")
 | 
						|
 | 
						|
    print(f"open {main_page}")
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    create_user_docs()
 |