Wire cli/docs.py build/serve/generate commands to run extraction scripts and Docusaurus. Add extract_cli.py (27 CLI docs from typer help), extract_openapi.py (8 REST API docs from FastAPI schema), extract_citations.py (14 pipeline pages with bib references), extract_dag.py (pipeline + table lineage Mermaid diagrams). Closes #26, #27, #28, #29, #30.
102 lines
2.7 KiB
Python
102 lines
2.7 KiB
Python
"""Extract CLI usage docs from typer commands.
|
|
|
|
Walks the CLI app tree, invokes ``--help`` for each command, and
|
|
writes Markdown files into ``docs/docs/cli/``.
|
|
|
|
Usage::
|
|
|
|
uv run python docs/scripts/extract_cli.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
# Ensure src/ is on the path
|
|
sys.path.insert(0, str(Path("src").resolve()))
|
|
|
|
from cli import app # noqa: E402
|
|
|
|
runner = CliRunner()
|
|
|
|
OUT_DIR = Path("docs/docs/cli")
|
|
|
|
|
|
def _get_commands(group_name: str = "") -> list[tuple[str, list[str]]]:
|
|
"""Walk the typer app tree and return (name, cmd_path) pairs."""
|
|
commands: list[tuple[str, list[str]]] = []
|
|
|
|
# Top-level help
|
|
commands.append(("stack", []))
|
|
|
|
# Registered sub-commands / groups
|
|
for info in app.registered_commands:
|
|
name = info.name or info.callback.__name__
|
|
commands.append((name, [name]))
|
|
|
|
for group in app.registered_groups:
|
|
grp_name = group.name or ""
|
|
if not grp_name:
|
|
continue
|
|
commands.append((grp_name, [grp_name]))
|
|
|
|
# Walk sub-commands within the group
|
|
grp_app = group.typer_instance
|
|
if grp_app:
|
|
for sub_info in grp_app.registered_commands:
|
|
sub_name = sub_info.name or sub_info.callback.__name__
|
|
commands.append(
|
|
(f"{grp_name}-{sub_name}", [grp_name, sub_name])
|
|
)
|
|
for sub_group in grp_app.registered_groups:
|
|
sg_name = sub_group.name or ""
|
|
if sg_name:
|
|
commands.append(
|
|
(f"{grp_name}-{sg_name}", [grp_name, sg_name])
|
|
)
|
|
|
|
return commands
|
|
|
|
|
|
def main() -> None:
|
|
if OUT_DIR.exists():
|
|
import shutil
|
|
|
|
shutil.rmtree(OUT_DIR)
|
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Category metadata for sidebar
|
|
cat_json = OUT_DIR / "_category_.json"
|
|
cat_json.write_text('{"label": "CLI Reference", "position": 10}\n')
|
|
|
|
commands = _get_commands()
|
|
count = 0
|
|
|
|
for slug, cmd_path in commands:
|
|
result = runner.invoke(app, [*cmd_path, "--help"])
|
|
if result.exit_code != 0:
|
|
continue
|
|
|
|
help_text = result.output.strip()
|
|
title = f"stack {' '.join(cmd_path)}" if cmd_path else "stack"
|
|
|
|
lines = [
|
|
f"---\ntitle: {title}\nsidebar_position: {count + 1}\n---\n",
|
|
f"# `{title}`\n",
|
|
f"```\n{help_text}\n```\n",
|
|
]
|
|
|
|
out_path = OUT_DIR / f"{slug}.md"
|
|
out_path.write_text("\n".join(lines))
|
|
count += 1
|
|
print(f" {title} -> {out_path}")
|
|
|
|
print(f"\nDone: {count} CLI docs written to {OUT_DIR}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|