Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy Docs
permissions:
contents: read

on:
push:
branches: [main]
workflow_dispatch:

# Preserve deployment order so the newest push finishes last.
concurrency:
group: deploy-docs
cancel-in-progress: false

jobs:
deploy:
timeout-minutes: 10
runs-on: ubuntu-latest
environment: docs

steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # PageActions reads `git log %at` for each page's "Updated" date
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "24"
cache: "npm"
cache-dependency-path: |
package-lock.json
packages/docs/package-lock.json
examples/worker-react/client/package-lock.json

- name: Install dependencies
run: |
npm ci
npm ci --prefix packages/docs
npm ci --prefix examples/worker-react/client

- name: Build docs
run: npm run build:docs

- name: Deploy to Cloudflare
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: npx wrangler deploy -c packages/docs/wrangler.jsonc
123 changes: 123 additions & 0 deletions .github/workflows/preview-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: Preview Docs
permissions:
contents: read

on:
pull_request:
types: [opened, synchronize, reopened, closed]

concurrency:
group: preview-docs-${{ github.event.pull_request.number }}
cancel-in-progress: true

env:
# Astro bakes this origin into canonical URLs, OG URLs, robots.txt, and the sitemap.
PREVIEW_NAME: ${{ github.event.pull_request.number }}
PREVIEW_URL: https://${{ github.event.pull_request.number }}.pr.capnweb.com

jobs:
preview:
permissions:
contents: read
pull-requests: write
# Never expose the deploy token to forked pull requests.
if: ${{ github.event.action != 'closed' && github.event.pull_request.head.repo.id == github.event.repository.id }}
timeout-minutes: 15
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # PageActions reads `git log %at` for each page's "Updated" date
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "24"
cache: "npm"
cache-dependency-path: |
package-lock.json
packages/docs/package-lock.json
examples/worker-react/client/package-lock.json

- name: Install dependencies
run: |
npm ci
npm ci --prefix packages/docs
npm ci --prefix examples/worker-react/client

- name: Build docs
env:
DOCS_SITE_URL: ${{ env.PREVIEW_URL }}
run: npm run build:docs

- name: Keep the Preview out of search results
# Keep public Preview URLs out of search results without affecting production.
run: |
printf '\n/*\n X-Robots-Tag: noindex\n' >> packages/docs/dist/_headers

- name: Deploy Preview
id: deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
WRANGLER_OUTPUT_FILE_PATH: ${{ runner.temp }}/wrangler-output.json
run: |
npx wrangler preview -c packages/docs/wrangler.jsonc --name "$PREVIEW_NAME"
jq -er --arg expected "$PREVIEW_URL" '
select(.type == "preview"
and (.preview_urls[0] | rtrimstr("/")) == ($expected | rtrimstr("/"))
and .deployment_urls[0])
| "url=\(.preview_urls[0])\ndeployment=\(.deployment_urls[0])"
' "$WRANGLER_OUTPUT_FILE_PATH" >> "$GITHUB_OUTPUT"

- name: Comment the Preview URL
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
URL: ${{ steps.deploy.outputs.url }}
DEPLOYMENT: ${{ steps.deploy.outputs.deployment }}
SHA: ${{ github.event.pull_request.head.sha }}
# Keep one bot comment current across pushes.
run: |
marker='<!-- capnweb-docs-preview -->'
body=$(printf '%s\n### Docs preview\n\n| | |\n| --- | --- |\n| **Preview** | %s |\n| **This commit** | %s |\n\nUpdates on every push. Deleted when this pull request closes. Not indexed by search engines.\n\n<sub>`%s`</sub>\n' \
"$marker" "$URL" "$DEPLOYMENT" "$SHA")
id=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" --paginate \
--jq "[.[] | select(.user.type == \"Bot\" and (.body | startswith(\"$marker\")))] | first | .id // empty")
if [ -n "$id" ]; then
gh api -X PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${id}" -f body="$body" --silent
else
gh api -X POST "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" -f body="$body" --silent
fi

cleanup:
# Delete the public Preview when its pull request closes.
if: ${{ github.event.action == 'closed' && github.event.pull_request.head.repo.id == github.event.repository.id }}
timeout-minutes: 10
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "24"
cache: "npm"
cache-dependency-path: package-lock.json

- name: Install wrangler
run: npm ci

- name: Delete the Preview
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# A Preview may not exist if its deployment never ran.
run: |
status=0
output=$(npx wrangler preview delete -c packages/docs/wrangler.jsonc --name "$PREVIEW_NAME" --skip-confirmation 2>&1) || status=$?
printf '%s\n' "$output"
[[ "$status" -eq 0 || "$output" == *"code: 10025"* ]]
43 changes: 43 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,49 @@ jobs:
- name: Lint Markdown
run: npm run lint:md

# The docs site is deployed from main by deploy-docs.yml, so without this the
# first place its build ever runs is the deploy. Fail it on the pull request
# instead.
build-docs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7
with:
# Same full history the deploy uses. Each page's "Updated" date comes from
# `git log -1 --format=%at <file>`, and in a shallow clone that resolves to
# the one commit that was fetched -- so every page would claim to have been
# updated at the same moment, and this job would be checking a build that is
# not the one main deploys.
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "24"
cache: "npm"
# packages/docs is excluded from the workspaces and the React example's
# client is its own install, so both have lockfiles the root one does not
# cover.
cache-dependency-path: |
package-lock.json
packages/docs/package-lock.json
examples/worker-react/client/package-lock.json

# The docs build bundles each example's real source, so the React example's
# client needs its own node_modules for esbuild to resolve react out of.
- name: Install dependencies
run: |
npm ci
npm ci --prefix packages/docs
npm ci --prefix examples/worker-react/client

- name: Build docs
run: npm run build:docs

- name: Check docs
run: npm --prefix packages/docs run check

test:
runs-on: ubuntu-latest
container:
Expand Down
Loading
Loading