Skip to content

chore: release new version 🚀 #43

chore: release new version 🚀

chore: release new version 🚀 #43

name: Deploy Website Preview
# Per-PR preview of the marketing site at https://ema.tnsor.network/preview/<n>/
# (the production router worker proxies /preview/<n> to this PR's worker,
# nostream-web-pr-<n>, served from its workers.dev URL). The preview is deleted
# when the PR closes (merged or not).
#
# Requires the `website-preview` GitHub environment to exist with
# CLOUDFLARE_API_TOKEN (Workers Scripts edit) and CLOUDFLARE_ACCOUNT_ID —
# one-time setup. While the environment or its secrets are absent, this
# workflow skips with a notice instead of failing the PR.
on:
pull_request:
types:
- opened
- synchronize
- reopened
- closed
paths:
- "website/site/**"
- "website/hero-animation/**"
- ".github/workflows/deploy-website-preview.yml"
concurrency:
group: website-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
preview:
runs-on: ubuntu-latest
# Deploy credentials live in this GitHub environment: CLOUDFLARE_API_TOKEN
# secret (Workers Scripts scope) and CLOUDFLARE_ACCOUNT_ID variable.
environment: website-preview
# Guard the environment reference so a missing setup skips rather than fails:
# the job targets the environment only when it exists.
steps:
- name: Check preview environment is configured
id: guard
env:
GH_TOKEN: ${{ github.token }}
run: |
set -eu
# Existence is the only check the runner's token can make: listing
# environment secrets needs permissions github.token does not carry,
# and probing them here once made every run skip with "lacks
# CLOUDFLARE_API_TOKEN" even after the secrets were set.
if gh api repos/${{ github.repository }}/environments/website-preview >/dev/null 2>&1; then
echo "skip=false" >> "$GITHUB_OUTPUT"
else
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "::notice::website-preview environment does not exist yet — PR preview skipped. Create it with CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID to enable previews."
fi
- name: Checkout (for cleanup metadata)
if: steps.guard.outputs.skip == 'false'
uses: actions/checkout@v3
- uses: pnpm/action-setup@v4
if: steps.guard.outputs.skip == 'false' && github.event.action != 'closed'
- uses: actions/setup-node@v3
if: steps.guard.outputs.skip == 'false' && github.event.action != 'closed'
with:
node-version-file: .nvmrc
cache: pnpm
- name: Install workspace dependencies
if: steps.guard.outputs.skip == 'false' && github.event.action != 'closed'
run: pnpm install --frozen-lockfile
- name: Build the site under the preview base
if: steps.guard.outputs.skip == 'false' && github.event.action != 'closed'
working-directory: website/site
env:
SITE_URL: https://ema.tnsor.network
SITE_BASE: /preview/${{ github.event.pull_request.number }}/
run: |
pnpm run build
node scripts/apply-base.mjs
# The assets manifest is keyed by file path: the worker serves dist/
# at the root of its URL, but the preview is requested under
# /preview/<n>/... — so the built tree must also EXIST at that path
# or every asset request falls through to the SPA-fallback
# index.html (text/html for .css/.mp4 requests — the broken preview).
# Copy the build into dist/preview/<n>/ (excluding the copy itself).
n="${{ github.event.pull_request.number }}"
mkdir -p "dist/preview/$n"
find dist -mindepth 1 -maxdepth 1 ! -name preview -exec cp -r {} "dist/preview/$n/" \;
- name: Mark the preview comment as rendering
if: steps.guard.outputs.skip == 'false' && github.event.action != 'closed'
env:
GH_TOKEN: ${{ github.token }}
URL: https://ema.tnsor.network/preview/${{ github.event.pull_request.number }}/
WORKER_URL: https://nostream-web-pr-${{ github.event.pull_request.number }}.cameri.workers.dev/preview/${{ github.event.pull_request.number }}/
MARKER: <!-- site-preview-comment -->
run: |
# Flip the single preview comment to a "rendering" state before the
# deploy starts, so the link always exists but signals staleness.
COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments?per_page=100" \
--jq '.[] | select(.body | startswith(env.MARKER)) | .id' | tail -1)
BODY="${MARKER}
⏳ Preview is rendering for the latest push — ${WORKER_URL} will serve the new build in about a minute."
if [ -n "$COMMENT_ID" ]; then
gh api -X PATCH "repos/${{ github.repository }}/issues/comments/$COMMENT_ID" -f body="$BODY" >/dev/null
echo "marked comment $COMMENT_ID as rendering"
else
gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$BODY" >/dev/null
echo "created new preview comment (rendering)"
fi
- name: Deploy the preview worker
if: steps.guard.outputs.skip == 'false' && github.event.action != 'closed'
working-directory: website/site
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
run: |
npx wrangler deploy \
--config wrangler.preview.jsonc \
--name nostream-web-pr-${{ github.event.pull_request.number }}
- name: Link the preview on the PR
if: steps.guard.outputs.skip == 'false' && github.event.action != 'closed'
env:
GH_TOKEN: ${{ github.token }}
URL: https://ema.tnsor.network/preview/${{ github.event.pull_request.number }}/
WORKER_URL: https://nostream-web-pr-${{ github.event.pull_request.number }}.cameri.workers.dev/preview/${{ github.event.pull_request.number }}/
MARKER: <!-- site-preview-comment -->
run: |
# One comment per PR, updated in place on every push: find the
# existing one by marker, edit it, or create it if absent. The
# direct workers.dev URL works as soon as this deploy lands; the
# ema.tnsor.network form starts working once the router ships
# (it deploys with this PR's merge).
COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments?per_page=100" \
--jq '.[] | select(.body | startswith(env.MARKER)) | .id' | tail -1)
BODY="${MARKER}
🔍 Site preview for this PR (includes all changes on this branch): ${WORKER_URL}
The ${URL} form serves the same build once this PR merges — the production router that proxies /preview/* ships with it.
Updates with every push to this PR; deleted when the PR closes."
if [ -n "$COMMENT_ID" ]; then
gh api -X PATCH "repos/${{ github.repository }}/issues/comments/$COMMENT_ID" -f body="$BODY" >/dev/null
echo "updated comment $COMMENT_ID"
else
gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$BODY" >/dev/null
echo "created new preview comment"
fi
- name: Delete the preview worker
if: steps.guard.outputs.skip == 'false' && github.event.action == 'closed'
working-directory: website/site
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
run: |
# --force skips the "would this break dependents" probe, which calls
# KV namespaces listing the deploy token's scope (Workers Scripts
# only) cannot read — the probe errors with auth 10000 AFTER the
# delete has already succeeded. Preview workers are assets-only
# (no bindings), so the check is pure overhead. A missing worker
# still errors and is caught below.
npx wrangler delete --config wrangler.preview.jsonc --force \
--name nostream-web-pr-${{ github.event.pull_request.number }} \
|| echo "preview worker already absent"
- name: Note the cleanup on the PR
if: steps.guard.outputs.skip == 'false' && github.event.action == 'closed'
env:
GH_TOKEN: ${{ github.token }}
MARKER: <!-- site-preview-comment -->
run: |
# Update the SAME single preview comment instead of adding one.
COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments?per_page=100" \
--jq '.[] | select(.body | startswith(env.MARKER)) | .id' | tail -1)
BODY="${MARKER}
🧹 Site preview for this PR was deleted (PR closed)."
if [ -n "$COMMENT_ID" ]; then
gh api -X PATCH "repos/${{ github.repository }}/issues/comments/$COMMENT_ID" -f body="$BODY" >/dev/null
else
gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$BODY" >/dev/null || true
fi