mirror of https://github.com/zulip/zulip.git
156 lines
3.9 KiB
Python
Executable File
156 lines
3.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# check for the venv
|
|
from lib import sanity_check
|
|
|
|
sanity_check.check_venv(__file__)
|
|
|
|
import html
|
|
import os
|
|
import pprint
|
|
from collections import defaultdict
|
|
from typing import Any, Dict, List, Set
|
|
|
|
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 encode_info(info: Any) -> str:
|
|
try:
|
|
result = ""
|
|
try:
|
|
info = orjson.loads(info)
|
|
result = "(stringified)\n"
|
|
except orjson.JSONDecodeError:
|
|
pass
|
|
result += html.escape(pprint.pformat(info, indent=4))
|
|
return "<pre>" + result + "</pre>"
|
|
except Exception:
|
|
pass
|
|
try:
|
|
return html.escape(str(info))
|
|
except Exception:
|
|
pass
|
|
return "NOT ENCODABLE"
|
|
|
|
|
|
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()
|