mirror of
https://github.com/stablyai/orca.git
synced 2026-10-03 08:02:12 +00:00
feat(docs): publish OSS docs with stable releases
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
name: Docs site
|
||||
|
||||
on:
|
||||
# Stable desktop releases are the production publication boundary. The
|
||||
# release gate below excludes mobile and prerelease tags from this trigger.
|
||||
release:
|
||||
types: [published]
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/site/**'
|
||||
- '.github/workflows/docs.yml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Stable desktop release tag to redeploy (vX.Y.Z)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: docs-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('release-{0}', github.event.release.tag_name || inputs.tag) }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# The Vercel project is rooted at `.`; this package directory is the
|
||||
# complete upload and build context.
|
||||
working-directory: docs/site
|
||||
|
||||
jobs:
|
||||
# This job deliberately has no deployment credentials and runs for fork PRs
|
||||
# as well as same-repository PRs.
|
||||
check:
|
||||
name: Build and test
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout pull request
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.24.0
|
||||
run_install: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: docs/site/pnpm-lock.yaml
|
||||
|
||||
- name: Install site dependencies
|
||||
run: pnpm --ignore-workspace install --frozen-lockfile
|
||||
|
||||
- name: Run package tests
|
||||
run: pnpm --ignore-workspace test
|
||||
|
||||
- name: Lint site
|
||||
run: pnpm --ignore-workspace lint
|
||||
|
||||
- name: Typecheck site
|
||||
run: pnpm --ignore-workspace exec tsc --noEmit --incremental false
|
||||
|
||||
- name: Build site
|
||||
run: pnpm --ignore-workspace build
|
||||
|
||||
release_gate:
|
||||
name: Authorize release
|
||||
if: >-
|
||||
github.repository == 'stablyai/orca' &&
|
||||
(github.event_name == 'release' || github.event_name == 'workflow_dispatch')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
deploy: ${{ steps.validate.outputs.deploy }}
|
||||
steps:
|
||||
- name: Validate stable desktop tag
|
||||
id: validate
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
INPUT_TAG: ${{ inputs.tag }}
|
||||
RELEASE_PRERELEASE: ${{ github.event.release.prerelease }}
|
||||
RELEASE_DRAFT: ${{ github.event.release.draft }}
|
||||
RELEASE_AUTHOR: ${{ github.event.release.author.login }}
|
||||
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
||||
WORKFLOW_REF: ${{ github.ref }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
shell: bash
|
||||
working-directory: .
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag="$INPUT_TAG"
|
||||
[[ "$EVENT_NAME" == "release" ]] && tag="$RELEASE_TAG"
|
||||
|
||||
# Match the stable desktop format used by release-policy.yml. This
|
||||
# intentionally rejects mobile-* and all -rc.* tags.
|
||||
stable_tag=false
|
||||
[[ "$tag" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]] && stable_tag=true
|
||||
|
||||
if [[ "$stable_tag" != "true" ]]; then
|
||||
echo "Release $tag is not a stable desktop release; skipping docs deployment."
|
||||
echo "deploy=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$EVENT_NAME" == "release" ]]; then
|
||||
authorized_ref=true
|
||||
authorized_author=false
|
||||
[[ "$RELEASE_AUTHOR" == "github-actions[bot]" ]] && authorized_author=true
|
||||
release_state_ok=false
|
||||
[[ "$RELEASE_PRERELEASE" == "false" && "$RELEASE_DRAFT" == "false" ]] && release_state_ok=true
|
||||
else
|
||||
authorized_ref=false
|
||||
[[ "$WORKFLOW_REF" == "refs/heads/$DEFAULT_BRANCH" ]] && authorized_ref=true
|
||||
|
||||
release_json="$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$tag")"
|
||||
authorized_author=false
|
||||
[[ "$(jq -r '.author.login' <<<"$release_json")" == "github-actions[bot]" ]] && authorized_author=true
|
||||
release_state_ok=false
|
||||
if [[ "$(jq -r '.tag_name' <<<"$release_json")" == "$tag" &&
|
||||
"$(jq -r '.prerelease' <<<"$release_json")" == "false" &&
|
||||
"$(jq -r '.draft' <<<"$release_json")" == "false" ]]; then
|
||||
release_state_ok=true
|
||||
fi
|
||||
fi
|
||||
|
||||
deploy=false
|
||||
if [[ "$authorized_ref" == "true" && "$authorized_author" == "true" && "$release_state_ok" == "true" ]]; then
|
||||
deploy=true
|
||||
else
|
||||
echo "Release $tag is not an authorized stable desktop release; skipping docs deployment."
|
||||
fi
|
||||
echo "deploy=$deploy" >> "$GITHUB_OUTPUT"
|
||||
|
||||
preview:
|
||||
name: Preview
|
||||
# Only trusted branches can access the Vercel preview environment. Forks
|
||||
# still receive the credential-free check job above.
|
||||
needs: check
|
||||
if: >-
|
||||
github.event_name == 'pull_request' &&
|
||||
needs.check.result == 'success' &&
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
environment:
|
||||
name: docs-preview
|
||||
env:
|
||||
VERCEL_TELEMETRY_DISABLED: '1'
|
||||
steps:
|
||||
- name: Checkout pull request
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.24.0
|
||||
run_install: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: docs/site/pnpm-lock.yaml
|
||||
|
||||
- name: Install site dependencies
|
||||
run: pnpm --ignore-workspace install --frozen-lockfile
|
||||
|
||||
- name: Verify Vercel credentials
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -n "${VERCEL_TOKEN:-}" || { echo '::error::VERCEL_TOKEN is not configured for docs-preview.'; exit 1; }
|
||||
test -n "${VERCEL_ORG_ID:-}" || { echo '::error::VERCEL_ORG_ID is not configured for docs-preview.'; exit 1; }
|
||||
test -n "${VERCEL_PROJECT_ID:-}" || { echo '::error::VERCEL_PROJECT_ID is not configured for docs-preview.'; exit 1; }
|
||||
|
||||
- name: Pull Vercel preview settings
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
run: pnpm --ignore-workspace exec vercel pull --yes --non-interactive --environment=preview
|
||||
|
||||
- name: Build preview
|
||||
run: pnpm --ignore-workspace exec vercel build --non-interactive
|
||||
|
||||
- name: Deploy preview
|
||||
id: deploy
|
||||
shell: bash
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# `--non-interactive` returns a JSON status envelope, not a bare URL.
|
||||
deployment_json="$(pnpm --ignore-workspace exec vercel deploy --prebuilt --yes --non-interactive --format json)"
|
||||
printf '%s\n' "$deployment_json"
|
||||
url="$(jq -er '.deployment.url // .url // empty' <<<"$deployment_json")"
|
||||
[[ "$url" =~ ^https://[^[:space:]]+$ ]]
|
||||
printf '%s\n' "$url"
|
||||
echo "url=$url" >> "$GITHUB_OUTPUT"
|
||||
echo "Preview deployed to $url" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Link preview in pull request
|
||||
uses: actions/github-script@v8
|
||||
env:
|
||||
PREVIEW_URL: ${{ steps.deploy.outputs.url }}
|
||||
with:
|
||||
script: |
|
||||
const marker = '<!-- docs-preview -->'
|
||||
const url = process.env.PREVIEW_URL
|
||||
if (!url) throw new Error('Preview URL was not produced')
|
||||
const body = `${marker}\nDocs preview: [${url}](${url})`
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
per_page: 100
|
||||
})
|
||||
const existing = comments.find((comment) => comment.body?.includes(marker))
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id,
|
||||
body
|
||||
})
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body
|
||||
})
|
||||
}
|
||||
|
||||
production:
|
||||
name: Production
|
||||
if: >-
|
||||
(github.event_name == 'release' || github.event_name == 'workflow_dispatch') &&
|
||||
needs.release_gate.result == 'success' &&
|
||||
needs.release_gate.outputs.deploy == 'true'
|
||||
needs: release_gate
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
environment:
|
||||
name: docs-production
|
||||
url: https://www.onorca.dev/docs
|
||||
env:
|
||||
VERCEL_TELEMETRY_DISABLED: '1'
|
||||
steps:
|
||||
- name: Checkout released tag
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name || inputs.tag }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.24.0
|
||||
run_install: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: docs/site/pnpm-lock.yaml
|
||||
|
||||
- name: Install site dependencies
|
||||
run: pnpm --ignore-workspace install --frozen-lockfile
|
||||
|
||||
- name: Verify Vercel credentials
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -n "${VERCEL_TOKEN:-}" || { echo '::error::VERCEL_TOKEN is not configured for docs-production.'; exit 1; }
|
||||
test -n "${VERCEL_ORG_ID:-}" || { echo '::error::VERCEL_ORG_ID is not configured for docs-production.'; exit 1; }
|
||||
test -n "${VERCEL_PROJECT_ID:-}" || { echo '::error::VERCEL_PROJECT_ID is not configured for docs-production.'; exit 1; }
|
||||
|
||||
- name: Pull Vercel production settings
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
run: pnpm --ignore-workspace exec vercel pull --yes --non-interactive --environment=production
|
||||
|
||||
- name: Run package tests
|
||||
run: pnpm --ignore-workspace test
|
||||
|
||||
- name: Lint site
|
||||
run: pnpm --ignore-workspace lint
|
||||
|
||||
- name: Typecheck site
|
||||
run: pnpm --ignore-workspace exec tsc --noEmit --incremental false
|
||||
|
||||
- name: Build production site
|
||||
run: pnpm --ignore-workspace exec vercel build --prod --non-interactive
|
||||
|
||||
- name: Deploy production site
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
run: pnpm --ignore-workspace exec vercel deploy --prebuilt --prod --yes --non-interactive
|
||||
Reference in New Issue
Block a user