Skip to content

Next 16

Next 16 #129

Workflow file for this run

name: Preview
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
concurrency:
group: preview-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
issues: write
jobs:
preview:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Abort for draft PRs
if: github.event.pull_request.draft == true
run: |
echo "Draft PRs do not get previews. Skipping preview deployment."
exit 0
- name: Resolve workers.dev subdomain
id: workers_dev
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CLOUDFLARE_ACCOUNT_ID:-}" ] || [ -z "${CLOUDFLARE_API_TOKEN:-}" ]; then
echo "Missing Cloudflare credentials; cannot resolve workers.dev subdomain." >&2
exit 1
fi
response=$(curl -sSL \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
"https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/workers/subdomain")
success=$(echo "$response" | jq -r '.success // false')
if [ "$success" != "true" ]; then
echo "workers.dev subdomain lookup failed" >&2
exit 1
fi
subdomain=$(echo "$response" | jq -r '.result.subdomain // empty')
if [ -z "$subdomain" ]; then
echo "workers.dev subdomain missing in response" >&2
exit 1
fi
echo "subdomain=$subdomain" >> "$GITHUB_OUTPUT"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # https://github.com/actions/checkout/releases/tag/v6.0.2
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
persist-credentials: false
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # https://github.com/pnpm/action-setup/releases/tag/v4.2.0
with:
version: 10
run_install: false
- name: Install Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # https://github.com/actions/setup-node/releases/tag/v6.2.0
with:
node-version: 24
cache: "pnpm"
- name: Cache Next.js
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # https://github.com/actions/cache/releases/tag/v5.0.3
with:
path: ${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/pnpm-lock.yaml') }}-
- name: Cache Compiled MDX
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # https://github.com/actions/cache/releases/tag/v5.0.3
with:
path: ${{ github.workspace }}/.compiled-mdx
key: ${{ runner.os }}-compiled-mdx-${{ hashFiles('src/app/content/**/*.mdx', 'src/lib/shiki/*.json') }}
restore-keys: |
${{ runner.os }}-compiled-mdx-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Lint
run: pnpm lint
- name: Check formatting
run: pnpm exec oxfmt --check .
- name: Precompile MDX
run: pnpm precompile-mdx
- name: Tune AWS CLI transfers
run: |
aws configure set default.s3.max_concurrent_requests 100
aws configure set default.s3.max_queue_size 1000
aws configure set default.s3.multipart_threshold 100MB
aws configure set default.s3.multipart_chunksize 100MB
- name: Derive preview identifiers
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
WORKERS_DEV_SUBDOMAIN: ${{ steps.workers_dev.outputs.subdomain }}
run: |
PR_NUMBER="${PR_NUMBER}"
echo "WORKER_NAME=blueshift-preview-pr-${PR_NUMBER}" >> "$GITHUB_ENV"
echo "CONTENT_PREFIX=compiled-mdx-preview/pr-${PR_NUMBER}" >> "$GITHUB_ENV"
if [ -n "${WORKERS_DEV_SUBDOMAIN:-}" ]; then
echo "PREVIEW_URL=https://blueshift-preview-pr-${PR_NUMBER}.${WORKERS_DEV_SUBDOMAIN}.workers.dev" >> "$GITHUB_ENV"
fi
- name: Seed preview content from production
env:
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
ENDPOINT: https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com
PROD_CONTENT_PREFIX: compiled-mdx
run: |
MANIFEST_NAME=".upload-manifest.json"
SOURCE_PREFIX="s3://${{ secrets.R2_BUCKET }}/$PROD_CONTENT_PREFIX"
DEST_PREFIX="s3://${{ secrets.R2_BUCKET }}/$CONTENT_PREFIX"
aws s3 sync "$SOURCE_PREFIX" "$DEST_PREFIX" \
--endpoint-url "$ENDPOINT" \
--quiet \
--size-only \
--exclude "$MANIFEST_NAME" \
--delete
- name: Upload Compiled MDX to R2 (preview)
env:
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
ENDPOINT: https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com
COMPILED_DIR: .compiled-mdx
PROD_CONTENT_PREFIX: compiled-mdx
run: |
S3_PREFIX="s3://${{ secrets.R2_BUCKET }}/$CONTENT_PREFIX"
PROD_S3_PREFIX="s3://${{ secrets.R2_BUCKET }}/$PROD_CONTENT_PREFIX"
MANIFEST_NAME=".upload-manifest.json"
MANIFEST_FILE="$COMPILED_DIR/$MANIFEST_NAME"
REMOTE_MANIFEST_FILE="$RUNNER_TEMP/$MANIFEST_NAME"
node ./scripts/mdx-upload-manifest.mjs write "$COMPILED_DIR" "$MANIFEST_FILE"
if ! aws s3 cp "$S3_PREFIX/$MANIFEST_NAME" "$REMOTE_MANIFEST_FILE" \
--endpoint-url "$ENDPOINT" \
--no-progress >/dev/null 2>&1; then
aws s3 cp "$PROD_S3_PREFIX/$MANIFEST_NAME" "$REMOTE_MANIFEST_FILE" \
--endpoint-url "$ENDPOINT" \
--no-progress >/dev/null 2>&1 || printf '{}\n' > "$REMOTE_MANIFEST_FILE"
fi
aws s3 sync "$COMPILED_DIR/" "$S3_PREFIX" \
--endpoint-url "$ENDPOINT" \
--quiet \
--size-only \
--delete \
--content-type "application/json"
# Compare against the existing preview manifest first; fall back to production only to bootstrap a new preview.
changed_files=$(node ./scripts/mdx-upload-manifest.mjs diff "$MANIFEST_FILE" "$REMOTE_MANIFEST_FILE")
if [ -n "$changed_files" ]; then
printf '%s\n' "$changed_files" | while IFS= read -r json_path; do
[ -n "$json_path" ] || continue
aws s3 cp "$COMPILED_DIR/$json_path" "$S3_PREFIX/$json_path" \
--endpoint-url "$ENDPOINT" \
--quiet \
--content-type "application/json"
done
fi
aws s3 cp "$MANIFEST_FILE" "$S3_PREFIX/$MANIFEST_NAME" \
--endpoint-url "$ENDPOINT" \
--quiet \
--content-type "application/json"
- name: Build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_CHALLENGE_SECRET: ${{ secrets.NEXT_PUBLIC_CHALLENGE_SECRET }}
NEXT_PUBLIC_CHALLENGE_RPC_ENDPOINT: ${{ secrets.NEXT_PUBLIC_CHALLENGE_RPC_ENDPOINT }}
NEXT_PUBLIC_MAINNET_RPC_ENDPOINT: ${{ secrets.NEXT_PUBLIC_MAINNET_RPC_ENDPOINT }}
NEXT_PUBLIC_DEVNET_RPC_ENDPOINT: ${{ secrets.NEXT_PUBLIC_DEVNET_RPC_ENDPOINT }}
run: pnpm exec opennextjs-cloudflare build
- name: Deploy Preview (workers.dev)
uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # https://github.com/cloudflare/wrangler-action/releases/tag/v3.14.1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: >
deploy --env preview
--name ${{ env.WORKER_NAME }}
--var CONTENT_PREFIX:${{ env.CONTENT_PREFIX }}
- name: Comment preview URL
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
PREVIEW_URL: ${{ env.PREVIEW_URL }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
if [ -z "${PREVIEW_URL:-}" ]; then
echo "No preview URL available. Skipping comment."
exit 0
fi
marker='<!-- preview-link -->'
body=$(printf '%s\n✅ Preview deployed: %s' "$marker" "$PREVIEW_URL")
payload=$(jq -n --arg body "$body" '{body: $body}')
comments_url="https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments"
comments=$(curl -sSL \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
"$comments_url")
comment_id=$(echo "$comments" | jq -r --arg marker "$marker" 'map(select(.body | contains($marker))) | .[0].id // empty')
if [ -n "$comment_id" ]; then
curl -sSL -X PATCH \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d "$payload" \
"https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/comments/${comment_id}" > /dev/null
exit 0
fi
curl -sSL -X POST \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d "$payload" \
"$comments_url" > /dev/null