Updates for Documentation
This commit is contained in:
200
tools/publish_docs.py
Normal file
200
tools/publish_docs.py
Normal file
@@ -0,0 +1,200 @@
|
||||
# env: python3.10+ (external tooling — NOT Ignition)
|
||||
"""
|
||||
publish_docs.py — sync selected markdown files to WikiJS via GraphQL API.
|
||||
|
||||
Reads WIKIJS_API_KEY and WIKIJS_URL from the environment (or docker/.env via python-dotenv).
|
||||
Run manually or via the git post-push hook installed by scripts/install-hooks.sh.
|
||||
|
||||
Usage:
|
||||
python3 tools/publish_docs.py # sync all files
|
||||
python3 tools/publish_docs.py --dry-run # preview only, no API calls
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# ── Config ────────────────────────────────────────────────────────────────────
|
||||
|
||||
REPO_ROOT = Path(__file__).parent.parent
|
||||
|
||||
# Load secrets from docker/.env (symlink to ~/.config/ignition-dev/secrets.env)
|
||||
load_dotenv(REPO_ROOT / "docker" / ".env")
|
||||
|
||||
WIKIJS_URL = os.environ.get("WIKIJS_URL", "https://wikijs.primecontrols-dev.com")
|
||||
WIKIJS_API_KEY = os.environ["WIKIJS_API_KEY"] # loud failure if missing
|
||||
|
||||
GRAPHQL_ENDPOINT = f"{WIKIJS_URL.rstrip('/')}/graphql"
|
||||
LOCALE = "en"
|
||||
|
||||
# Maps repo-relative file path → WikiJS page path (no leading slash)
|
||||
MANIFEST: dict[str, str] = {
|
||||
"README.md": "en/engineering/AI-Framework/home",
|
||||
"CLAUDE.md": "en/engineering/AI-Framework/CLAUDE",
|
||||
"docker/CLAUDE.md": "en/engineering/AI-Framework/docker",
|
||||
"ignition/CLAUDE.md": "en/engineering/AI-Framework/ignition",
|
||||
"testing/CLAUDE.md": "en/engineering/AI-Framework/testing",
|
||||
"webdev/CLAUDE.md": "en/engineering/AI-Framework/webdev",
|
||||
"ignition/ignition-api.md": "en/engineering/AI-Framework/ignition/ignition-api",
|
||||
"docker/config/traefik/dynamic/README.md": "en/engineering/AI-Framework/docker/traefik",
|
||||
}
|
||||
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
def gql(query: str, variables: dict | None = None) -> dict:
|
||||
resp = requests.post(
|
||||
GRAPHQL_ENDPOINT,
|
||||
json={"query": query, "variables": variables or {}},
|
||||
headers={
|
||||
"Authorization": f"Bearer {WIKIJS_API_KEY}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
timeout=15,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
if "errors" in data:
|
||||
raise RuntimeError(f"GraphQL errors: {data['errors']}")
|
||||
return data
|
||||
|
||||
|
||||
def page_id_for_path(wiki_path: str) -> int | None:
|
||||
"""Return the page ID for an existing WikiJS page, or None if not found."""
|
||||
query = """
|
||||
query ($path: String!, $locale: String!) {
|
||||
pages {
|
||||
singleByPath(path: $path, locale: $locale) {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = gql(query, {"path": wiki_path, "locale": LOCALE})
|
||||
page = data["data"]["pages"]["singleByPath"]
|
||||
return page["id"] if page else None
|
||||
except RuntimeError:
|
||||
return None
|
||||
|
||||
|
||||
def derive_title(local_path: str) -> str:
|
||||
stem = Path(local_path).stem # e.g. "ignition-api"
|
||||
if stem.upper() == "README":
|
||||
# Use parent directory name for README files
|
||||
parent = Path(local_path).parent.name
|
||||
if parent == ".":
|
||||
return "Home"
|
||||
return parent.replace("-", " ").replace("_", " ").title()
|
||||
return stem.replace("-", " ").replace("_", " ").title()
|
||||
|
||||
|
||||
def create_page(wiki_path: str, title: str, content: str) -> None:
|
||||
mutation = """
|
||||
mutation ($path: String!, $title: String!, $content: String!, $locale: String!) {
|
||||
pages {
|
||||
create(
|
||||
path: $path
|
||||
title: $title
|
||||
content: $content
|
||||
locale: $locale
|
||||
editor: "markdown"
|
||||
isPublished: true
|
||||
isPrivate: false
|
||||
tags: []
|
||||
description: ""
|
||||
) {
|
||||
responseResult {
|
||||
succeeded
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
data = gql(mutation, {"path": wiki_path, "title": title, "content": content, "locale": LOCALE})
|
||||
result = data["data"]["pages"]["create"]["responseResult"]
|
||||
if not result["succeeded"]:
|
||||
raise RuntimeError(f"Create failed [{result['errorCode']}]: {result['message']}")
|
||||
|
||||
|
||||
def update_page(page_id: int, title: str, content: str) -> None:
|
||||
mutation = """
|
||||
mutation ($id: Int!, $title: String!, $content: String!) {
|
||||
pages {
|
||||
update(
|
||||
id: $id
|
||||
title: $title
|
||||
content: $content
|
||||
editor: "markdown"
|
||||
isPublished: true
|
||||
isPrivate: false
|
||||
tags: []
|
||||
description: ""
|
||||
) {
|
||||
responseResult {
|
||||
succeeded
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
data = gql(mutation, {"id": page_id, "title": title, "content": content})
|
||||
result = data["data"]["pages"]["update"]["responseResult"]
|
||||
if not result["succeeded"]:
|
||||
raise RuntimeError(f"Update failed [{result['errorCode']}]: {result['message']}")
|
||||
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Sync markdown files to WikiJS")
|
||||
parser.add_argument("--dry-run", action="store_true", help="Preview only, no API calls")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.dry_run:
|
||||
print("Dry run — no changes will be made.\n")
|
||||
|
||||
errors = 0
|
||||
|
||||
for local_rel, wiki_path in MANIFEST.items():
|
||||
local_file = REPO_ROOT / local_rel
|
||||
title = derive_title(local_rel)
|
||||
|
||||
if not local_file.exists():
|
||||
print(f"[SKIP] {local_rel} (file not found)")
|
||||
continue
|
||||
|
||||
if args.dry_run:
|
||||
print(f"[DRY-RUN] {local_rel} → {WIKIJS_URL}/{wiki_path} (title: {title!r})")
|
||||
continue
|
||||
|
||||
content = local_file.read_text(encoding="utf-8")
|
||||
|
||||
try:
|
||||
page_id = page_id_for_path(wiki_path)
|
||||
if page_id is None:
|
||||
create_page(wiki_path, title, content)
|
||||
print(f"[CREATED] {local_rel} → /{wiki_path}")
|
||||
else:
|
||||
update_page(page_id, title, content)
|
||||
print(f"[OK] {local_rel} → /{wiki_path}")
|
||||
except Exception as exc:
|
||||
print(f"[ERROR] {local_rel}: {exc}", file=sys.stderr)
|
||||
errors += 1
|
||||
|
||||
if errors:
|
||||
print(f"\n{errors} file(s) failed.", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user