diff --git a/automation/source-repo-templates/README.md b/automation/source-repo-templates/README.md index 3186317a..0f9a6f25 100644 --- a/automation/source-repo-templates/README.md +++ b/automation/source-repo-templates/README.md @@ -71,6 +71,22 @@ it ships its own rustdoc pipeline today. | `resq-software/viz` | C#/web | DefaultDocumentation | _TODO_ | | `resq-software/crates` | Rust | already has docs | n/a | +## Syncing changes + +Templates here are the canonical version. After editing, push the +update to each source repo with the helper script: + +```sh +automation/sync-templates.sh # all 3 +automation/sync-templates.sh --dry-run # preview diffs +automation/sync-templates.sh python # one language only +automation/sync-templates.sh --auto-merge # open PRs with --auto +``` + +The script clones each target repo shallowly, copies the matching +`api-docs..yml`, opens a sync PR on `sync/api-docs-template`, +and reports up-to-date when the workflow already matches. + ## Adding a new template 1. Drop the workflow YAML in this folder named `api-docs..yml`. diff --git a/automation/source-repo-templates/api-docs.dotnet.yml b/automation/source-repo-templates/api-docs.dotnet.yml index b3dd0746..4ff18d4c 100644 --- a/automation/source-repo-templates/api-docs.dotnet.yml +++ b/automation/source-repo-templates/api-docs.dotnet.yml @@ -451,7 +451,7 @@ jobs: # Mintlify only routes pages registered in docs.json. The # _pages.json artifact lists every generated Markdown path; # rewrite the matching language sub-group under the - # 'Generated API Reference' group so all pages are + # 'Generated Package References' group so all pages are # discoverable, in-content cross-links resolve, and direct # URLs work. working-directory: docs-checkout @@ -509,7 +509,7 @@ jobs: en = next(l for l in docs["navigation"]["languages"] if l["language"] == "en") sdks_tab = next(t for t in en["tabs"] if t["tab"] == "SDKs") - gen_group = next(g for g in sdks_tab["groups"] if g["group"] == "Generated API Reference") + gen_group = next(g for g in sdks_tab["groups"] if g["group"] == "Generated Package References") for sub in gen_group["pages"]: if isinstance(sub, dict) and sub.get("group") == LANG_LABEL: sub["pages"] = new_pages diff --git a/automation/source-repo-templates/api-docs.python.yml b/automation/source-repo-templates/api-docs.python.yml index 0100b60b..d2f1ee98 100644 --- a/automation/source-repo-templates/api-docs.python.yml +++ b/automation/source-repo-templates/api-docs.python.yml @@ -489,7 +489,7 @@ jobs: # Mintlify only routes pages registered in docs.json. The # _pages.json artifact lists every generated Markdown path; # rewrite the matching language sub-group under the - # 'Generated API Reference' group so all pages are + # 'Generated Package References' group so all pages are # discoverable, in-content cross-links resolve, and direct # URLs work. working-directory: docs-checkout @@ -547,7 +547,7 @@ jobs: en = next(l for l in docs["navigation"]["languages"] if l["language"] == "en") sdks_tab = next(t for t in en["tabs"] if t["tab"] == "SDKs") - gen_group = next(g for g in sdks_tab["groups"] if g["group"] == "Generated API Reference") + gen_group = next(g for g in sdks_tab["groups"] if g["group"] == "Generated Package References") for sub in gen_group["pages"]: if isinstance(sub, dict) and sub.get("group") == LANG_LABEL: sub["pages"] = new_pages diff --git a/automation/source-repo-templates/api-docs.typescript.yml b/automation/source-repo-templates/api-docs.typescript.yml index dd301b1c..4ab91770 100644 --- a/automation/source-repo-templates/api-docs.typescript.yml +++ b/automation/source-repo-templates/api-docs.typescript.yml @@ -261,7 +261,7 @@ jobs: # Mintlify only routes pages registered in docs.json. The # _pages.json artifact lists every generated Markdown path; # rewrite the matching language sub-group under the - # 'Generated API Reference' group so all pages are + # 'Generated Package References' group so all pages are # discoverable, in-content cross-links resolve, and direct # URLs work. working-directory: docs-checkout @@ -319,7 +319,7 @@ jobs: en = next(l for l in docs["navigation"]["languages"] if l["language"] == "en") sdks_tab = next(t for t in en["tabs"] if t["tab"] == "SDKs") - gen_group = next(g for g in sdks_tab["groups"] if g["group"] == "Generated API Reference") + gen_group = next(g for g in sdks_tab["groups"] if g["group"] == "Generated Package References") for sub in gen_group["pages"]: if isinstance(sub, dict) and sub.get("group") == LANG_LABEL: sub["pages"] = new_pages diff --git a/automation/sync-templates.sh b/automation/sync-templates.sh new file mode 100755 index 00000000..737ede64 --- /dev/null +++ b/automation/sync-templates.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +# Sync canonical SDK auto-doc workflows from this repo's +# `automation/source-repo-templates/` into each SDK source repo's +# `.github/workflows/api-docs.yml`. Opens a sync PR per repo when a +# diff exists; reports up-to-date when not. +# +# Mapping is hard-coded (one entry per language) because there are +# only three SDKs and each has its own repo + default-branch quirk. +# +# Requirements: +# - gh CLI authenticated with repo:write on each target repo +# - git, mktemp +# +# Usage: +# automation/sync-templates.sh # sync all 3 +# automation/sync-templates.sh dotnet # sync just dotnet +# automation/sync-templates.sh dotnet python # sync subset +# +# Flags: +# --dry-run show diffs but don't open PRs +# --auto-merge open PRs with --auto so they merge after CI +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TEMPLATE_DIR="${REPO_ROOT}/automation/source-repo-templates" + +# language|template_filename|target_repo|default_branch +TARGETS=( + "typescript|api-docs.typescript.yml|resq-software/npm|master" + "python|api-docs.python.yml|resq-software/pypi|main" + "dotnet|api-docs.dotnet.yml|resq-software/dotnet-sdk|main" +) + +DRY_RUN=0 +AUTO_MERGE=0 +SELECTED_LANGS=() +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=1 ;; + --auto-merge) AUTO_MERGE=1 ;; + -*) echo "unknown flag: $arg" >&2; exit 2 ;; + *) SELECTED_LANGS+=("$arg") ;; + esac +done + +selected() { + if [ ${#SELECTED_LANGS[@]} -eq 0 ]; then + return 0 + fi + for s in "${SELECTED_LANGS[@]}"; do + [ "$s" = "$1" ] && return 0 + done + return 1 +} + +sync_one() { + local lang="$1" template_file="$2" target_repo="$3" default_branch="$4" + + if ! selected "$lang"; then + return 0 + fi + + local template_path="${TEMPLATE_DIR}/${template_file}" + if [ ! -f "$template_path" ]; then + echo "[$lang] missing template: $template_path" >&2 + return 1 + fi + + echo "==> [$lang] checking $target_repo" + local work + work="$(mktemp -d)" + trap 'rm -rf "$work"' RETURN + + local clone_dir="${work}/clone" + if ! gh repo clone "$target_repo" "$clone_dir" -- \ + --depth=1 --branch="$default_branch" --quiet 2>/dev/null; then + echo "[$lang] clone failed for $target_repo" >&2 + return 1 + fi + + local target_workflow="${clone_dir}/.github/workflows/api-docs.yml" + mkdir -p "$(dirname "$target_workflow")" + cp "$template_path" "$target_workflow" + + if git -C "$clone_dir" diff --quiet -- .github/workflows/api-docs.yml; then + echo "[$lang] up-to-date" + return 0 + fi + + echo "[$lang] diff:" + git -C "$clone_dir" --no-pager diff --stat -- .github/workflows/api-docs.yml + + if [ "$DRY_RUN" -eq 1 ]; then + echo "[$lang] dry-run, skipping PR" + return 0 + fi + + local branch="sync/api-docs-template" + local commit_msg + commit_msg="$(cat <&1 | tail -1)" + echo "[$lang] $pr_url" + + if [ "$AUTO_MERGE" -eq 1 ]; then + gh pr merge "$pr_url" --repo "$target_repo" --squash --auto --delete-branch || true + echo "[$lang] auto-merge enabled" + fi +} + +failed=0 +for entry in "${TARGETS[@]}"; do + IFS='|' read -r lang template repo branch <<<"$entry" + if ! sync_one "$lang" "$template" "$repo" "$branch"; then + failed=$((failed + 1)) + fi +done + +if [ "$failed" -gt 0 ]; then + echo "==> $failed sync target(s) failed" >&2 + exit 1 +fi + +echo "==> done" diff --git a/docs.json b/docs.json index 96919124..f5ef8598 100644 --- a/docs.json +++ b/docs.json @@ -65,7 +65,7 @@ ] }, { - "group": "Generated API Reference", + "group": "Generated Package References", "pages": [ { "group": "TypeScript", diff --git a/scripts/splice-sdk-nav.py b/scripts/splice-sdk-nav.py index 13dc0b2c..6ec5703a 100644 --- a/scripts/splice-sdk-nav.py +++ b/scripts/splice-sdk-nav.py @@ -1,4 +1,4 @@ -"""Splice each SDK's _pages.json into docs.json's `Generated API Reference` +"""Splice each SDK's _pages.json into docs.json's `Generated Package References` sub-group for that language. Builds a hierarchical groups structure from page IDs of the form @@ -161,12 +161,12 @@ def main() -> int: readme_id = f"{prefix}/README" new_subgroups.append(build_lang_group(label, prefix, pages_path, readme_id)) - # Find Generated API Reference under en > SDKs > groups + # Find Generated Package References under en > SDKs > groups en = next(l for l in docs["navigation"]["languages"] if l["language"] == "en") sdks_tab = next(t for t in en["tabs"] if t["tab"] == "SDKs") gen_group = next( g for g in sdks_tab["groups"] - if g["group"] == "Generated API Reference" + if g["group"] == "Generated Package References" ) gen_group["pages"] = new_subgroups