name: Sync OpenAPI to site # Keeps the public API reference on the omnigent website in sync with # the spec generated here. When openapi.json changes on main, copy it # into omnigent-site/public/openapi.json and open (or update) a PR there. # # Like doc-sync, this stages onto the per-minor docs branch `X.Y-docs` # (derived from omnigent/version.py) rather than site `main`: the spec on # main describes the NEXT unreleased version, so the API reference is held # back until release, when publish-changelog merges `X.Y-docs → main`. # # Cross-repo writes can't use the workflow's own GITHUB_TOKEN (it's # scoped to this repo), so we mint a short-lived token from the # omnigent-ci GitHub App — the same App used by oss-regen-on-comment.yml # — scoped to omnigent-site. The App must be installed on omnigent-site # with contents + pull-requests write. on: push: branches: [main] paths: [openapi.json] # Manual trigger for backfills / re-syncs after editing this workflow. workflow_dispatch: # One sync at a time; a newer spec supersedes an in-flight run. concurrency: group: sync-openapi-to-site cancel-in-progress: true permissions: contents: read jobs: sync: name: Open sync PR on omnigent-site runs-on: ubuntu-latest # Skip cleanly on forks / installs where the App isn't configured, # rather than failing the token step with a confusing error. if: ${{ vars.OMNIGENT_BOT_APP_ID != '' }} env: SYNC_BRANCH: auto/openapi-sync TARGET_REPO: ${{ github.repository_owner }}/omnigent-site steps: - name: Checkout omnigent (spec source) uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: path: omnigent # Derive the per-minor docs staging branch from the runtime version # (0.5.0.dev0 → "0.5-docs"), matching doc-sync so both stage together. - name: Resolve docs branch id: docsbranch run: | set -euo pipefail minor="$(python3 - <<'PYEOF' import pathlib, re text = pathlib.Path("omnigent/omnigent/version.py").read_text() m = re.search(r'VERSION\s*=\s*["\']([0-9]+)\.([0-9]+)', text) if not m: raise SystemExit("could not parse X.Y from omnigent/omnigent/version.py") print(f"{m.group(1)}.{m.group(2)}") PYEOF )" echo "branch=${minor}-docs" >> "$GITHUB_OUTPUT" echo "::notice::OpenAPI ref stages on branch ${minor}-docs" - name: Mint App token for omnigent-site id: app-token uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: app-id: ${{ vars.OMNIGENT_BOT_APP_ID }} private-key: ${{ secrets.OMNIGENT_BOT_APP_KEY }} owner: ${{ github.repository_owner }} repositories: omnigent-site - name: Checkout omnigent-site (sync target) uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: repository: ${{ env.TARGET_REPO }} token: ${{ steps.app-token.outputs.token }} path: site # Base the sync on the docs branch, not main. Create it off the default # branch's tip if this is the cycle's first stage (idempotent — a concurrent # doc-sync run may have created it already). - name: Switch site checkout to docs branch working-directory: site env: GH_TOKEN: ${{ steps.app-token.outputs.token }} DOCS_BRANCH: ${{ steps.docsbranch.outputs.branch }} run: | set -euo pipefail git config user.name "omnigent-ci[bot]" git config user.email "294685417+omnigent-ci[bot]@users.noreply.github.com" if git ls-remote --exit-code --heads origin "$DOCS_BRANCH" >/dev/null 2>&1; then git fetch origin "$DOCS_BRANCH" git switch -C "$DOCS_BRANCH" FETCH_HEAD else git switch -C "$DOCS_BRANCH" git push origin "$DOCS_BRANCH" \ || echo "::notice::${DOCS_BRANCH} already created by a concurrent run — reusing it." fi - name: Copy spec into the site run: cp omnigent/openapi.json site/public/openapi.json # Commit + push to a fixed branch and open a PR if one isn't # already open. If a PR exists, the force-push updates it in place # — so repeated spec changes collapse into a single rolling PR. - name: Open or update sync PR working-directory: site env: GH_TOKEN: ${{ steps.app-token.outputs.token }} DOCS_BRANCH: ${{ steps.docsbranch.outputs.branch }} run: | if [ -z "$(git status --porcelain -- public/openapi.json)" ]; then echo "openapi.json already in sync — nothing to do." exit 0 fi # user.name/email already set by the branch-switch step. git switch -C "$SYNC_BRANCH" git add public/openapi.json git commit -m "chore(api): sync openapi.json from omnigent@${GITHUB_SHA:0:7}" git push --force origin "$SYNC_BRANCH" # auto/openapi-sync is a rolling branch reused across cycles, but its PR # base tracks the current docs branch — so retarget an already-open PR if # the cycle rolled over (e.g. 0.5-docs → 0.6-docs after a release). existing="$(gh pr list --head "$SYNC_BRANCH" --state open --json number --jq '.[0].number // empty')" if [ -n "$existing" ]; then gh pr edit "$existing" --base "$DOCS_BRANCH" >/dev/null 2>&1 || true echo "PR #$existing already open for $SYNC_BRANCH (base $DOCS_BRANCH) — the force-push updated it." exit 0 fi # Build the body with printf so YAML block indentation never # leaks leading spaces into the Markdown. short="${GITHUB_SHA:0:7}" body="$(printf 'Automated sync of `public/openapi.json` from [omnigent@`%s`](https://github.com/%s/commit/%s).\n\nStaged on `%s` (the per-minor docs branch); publishes the updated API reference at `/reference` when that branch merges to main at release.' "$short" "$GITHUB_REPOSITORY" "$GITHUB_SHA" "$DOCS_BRANCH")" gh pr create \ --base "$DOCS_BRANCH" \ --head "$SYNC_BRANCH" \ --title "chore(api): sync OpenAPI reference from omnigent" \ --body "$body"