From a4690b364c06cceeaaf5eddb1b60480be71da546 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 18 Sep 2026 17:04:56 +0000 Subject: [PATCH] =?UTF-8?q?ci:=20=E6=B7=BB=E5=8A=A0=E5=AE=98=E7=BD=91=20Cl?= =?UTF-8?q?oudflare=20=E7=94=9F=E4=BA=A7=E9=83=A8=E7=BD=B2=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过 GitHub Environment production 的 secrets/vars 部署 Worker 与安装脚本,避免把 token 写进仓库。 Co-authored-by: Henry Zhang --- .github/workflows/deploy-website.yml | 85 ++++++++++++++++++++++++++++ apps/website/README.md | 14 +++-- 2 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/deploy-website.yml diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml new file mode 100644 index 00000000..029bfdf2 --- /dev/null +++ b/.github/workflows/deploy-website.yml @@ -0,0 +1,85 @@ +name: Deploy website + +on: + push: + branches: [main] + paths: + - "apps/website/**" + - "install.sh" + - "install.ps1" + - ".github/workflows/deploy-website.yml" + workflow_dispatch: + +permissions: + contents: read + +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + environment: production + permissions: + contents: read + defaults: + run: + working-directory: apps/website + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 11.21.0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: apps/website/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Deploy to Cloudflare + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} + run: | + set -euo pipefail + if [ -z "${CLOUDFLARE_API_TOKEN}" ]; then + echo "::error::Missing secret CLOUDFLARE_API_TOKEN on Environment production" + exit 1 + fi + if [ -z "${CLOUDFLARE_ACCOUNT_ID}" ]; then + echo "::error::Missing variable CLOUDFLARE_ACCOUNT_ID on Environment production" + exit 1 + fi + if ! pnpm run deploy; then + echo "::error::wrangler deploy failed; Worker and static assets were not published" + exit 1 + fi + + # wrangler 4.x takes {bucket}/{key}; --bucket is not a valid flag on r2 object put. + # Quote content-type so the charset parameter is not split by the shell. + - name: Upload install scripts to R2 + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} + run: | + set -euo pipefail + if ! npx wrangler r2 object put amber-dist/install.sh \ + --file=../../install.sh \ + --remote \ + --content-type "text/plain; charset=utf-8"; then + echo "::error::Failed to upload install.sh to R2 bucket amber-dist" + exit 1 + fi + if ! npx wrangler r2 object put amber-dist/install.ps1 \ + --file=../../install.ps1 \ + --remote \ + --content-type "text/plain; charset=utf-8"; then + echo "::error::Failed to upload install.ps1 to R2 bucket amber-dist" + exit 1 + fi diff --git a/apps/website/README.md b/apps/website/README.md index c732db24..1cd7ae5a 100644 --- a/apps/website/README.md +++ b/apps/website/README.md @@ -19,7 +19,13 @@ The production bundle is written to `dist/`. The `prebuild` step copies repo-roo ## Cloudflare Deploy -`get.amberjs.com` is a custom domain on the same Worker as `amberjs.com` (`apps/website/wrangler.toml`). There is no GitHub Actions deploy job; publishing is a local Wrangler deploy (needs a Cloudflare account with access to this Worker): +`get.amberjs.com` is a custom domain on the same Worker as `amberjs.com` (`apps/website/wrangler.toml`). + +Production deploys run through GitHub Actions on the **`production`** Environment (secret `CLOUDFLARE_API_TOKEN`, variable `CLOUDFLARE_ACCOUNT_ID`). The workflow publishes on push to `main` when `apps/website/**`, `install.sh`, `install.ps1`, or the workflow file change. Tokens are not stored in the YAML. + +To publish manually: **Actions → Deploy website → Run workflow**. + +Local Wrangler is still available for dry-run and development (needs a Cloudflare account with access to this Worker): ```bash pnpm run deploy:dry-run @@ -28,9 +34,9 @@ pnpm run deploy `wrangler.toml` serves `dist/` as static assets and uses `single-page-application` fallback so direct links such as `/docs/installation` work on Cloudflare. -`src/worker.ts` serves `/install.sh` and `/install.ps1` from the R2 bucket `amber-dist` **when that object exists**, otherwise from the Worker static assets. Live `get.amberjs.com/install.sh` currently matches the asset-hosted copy (`content-type: application/x-sh`, `max-age=0`), so a Wrangler deploy updates the installer. If R2 later has `install.sh` / `install.ps1`, it shadows the deploy — also upload: +`src/worker.ts` serves `/install.sh` and `/install.ps1` from the R2 bucket `amber-dist` **when that object exists**, otherwise from the Worker static assets. If R2 has `install.sh` / `install.ps1`, it shadows the Worker assets. The production workflow also uploads both scripts to `amber-dist` after deploy so `get.amberjs.com` stays in sync. Local equivalent (wrangler 4.x uses `{bucket}/{key}`): ```bash -npx wrangler r2 object put install.sh --file=../../install.sh --bucket=amber-dist --remote --content-type text/plain -npx wrangler r2 object put install.ps1 --file=../../install.ps1 --bucket=amber-dist --remote --content-type text/plain +npx wrangler r2 object put amber-dist/install.sh --file=../../install.sh --remote --content-type "text/plain; charset=utf-8" +npx wrangler r2 object put amber-dist/install.ps1 --file=../../install.ps1 --remote --content-type "text/plain; charset=utf-8" ```