Skip to content

Deploy on GitHub Pages

Render this repository's CI workflow for GitHub Actions, then add the deploy job that publishes the built site to GitHub Pages — ocx-catalog ci renders the build/verify half only; the deploy half is yours to write.

Render the CI workflow

Add a ci block to catalog.config.json:

{
  "ci": { "forge": "github" }
}

Then run:

npx ocx-catalog ci

This writes .github/workflows/catalog-ci.yml. With packageManager defaulted to npm and verifyCi defaulted to true, a first render (no committed pins yet to carry forward) produces:

# generated by ocx-catalog ci v1 — do not edit
#
# Rendered by `ocx-catalog ci` from this repository's own catalog.config.json
# `ci` block. Do not hand-edit this file — change the config instead and
# re-render:
#
#     npx ocx-catalog ci
#
# `ci.verifyCi: false` in catalog.config.json omits the verify-catalog-ci job
# below (`ocx-catalog ci --check`) and stops CI from catching a hand-edit —
# the repository then owns this file by hand instead.
name: catalog-ci

on:
  pull_request:
  push:
    branches: [main]

permissions: {}

jobs:
  build:
    name: build
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4.3.1
        with:
          persist-credentials: false
      - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020  # v7.0.0
        with:
          node-version: "22"
          cache: npm
      - run: npm ci
      - run: npx ocx-catalog build

  verify-catalog-ci:
    name: verify-catalog-ci
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4.3.1
        with:
          persist-credentials: false
      - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020  # v7.0.0
        with:
          node-version: "22"
          cache: npm
      - run: npm ci
      - run: npx ocx-catalog ci --check

build only builds the site — it never uploads or deploys anything. verify-catalog-ci re-renders the workflow in memory and fails the run if this file has drifted from catalog.config.json (see CI rendering); set "verifyCi": false in the ci block to omit it.

Set "packageManager": "bun" and the install/run steps change instead:

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020  # v7.0.0
  with:
    node-version: "22"
    cache: npm
- run: npm ci
- run: npx ocx-catalog build
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6  # v2.2.0
- run: bun install --frozen-lockfile
- run: bun x ocx-catalog build

bun replaces actions/setup-node outright with oven-sh/setup-bun — a bun repo ships no package-lock.json for npm ci to read, so the two managers never run side by side.

Add the deploy job

ocx-catalog ci renders no deploy step at all — add this workflow yourself, alongside the rendered catalog-ci.yml:

name: deploy
on:
  push:
    branches: [main]

permissions: {}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # v7.0.1
        with:
          persist-credentials: false
      - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020  # v7.0.0
        with:
          node-version: "22"
          cache: npm
      - run: npm ci
      - run: npx ocx-catalog build --out dist
      - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9  # v5.0.0
        with:
          path: dist

  deploy:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      pages: write
      id-token: write
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128  # v5.0.0

permissions: {} at the workflow level plus pages: write/id-token: write scoped to the deploy job only, persist-credentials: false on checkout, and the github-pages environment match the least-privilege bar this repository holds its own workflows to.

The default project Pages URL is a subpath

A generated catalog site cannot be served from a URL subpath: the build never emits a VitePress base:, and the theme's data fetches (/data/catalog/catalog.json, /p/<ns>/<pkg>.json, and the OCI image index fetches) are literal root-relative strings. The default URL for a project Pages site — https://<org>.github.io/<repo>/ — is a subpath, so every asset and every one of those fetches 404s once deployed there. This is GitHub's own project-Pages URL topology, not a missing option in this package: deploy to a user or organization root Pages site (a repo named <org>.github.io, served at https://<org>.github.io/) or attach a custom domain at the domain root instead.

The mirrored /p/* tree also ships an inert _headers file — GitHub Pages never reads it. See Hosting and headers for what that means and what to do about it.

Keep the workflow from drifting

verify-catalog-ci catches a hand-edit to the rendered file, not a config-vs-deploy-workflow mismatch — the deploy workflow above is entirely your own and isn't covered by --check. See CI rendering for the drift-check and pin-carry-forward mechanics.