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()
|