Deploy to Cloudflare #50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to Cloudflare | |
| on: | |
| push: | |
| branches: | |
| - multi-tenant | |
| paths-ignore: | |
| - 'README.md' | |
| - 'LICENSE' | |
| - '.gitignore' | |
| - 'docs/**' | |
| - '*.md' | |
| schedule: | |
| # 每 3 天检查一次更新并部署 | |
| - cron: '0 0 */3 * *' | |
| workflow_dispatch: | |
| inputs: | |
| force_deploy: | |
| description: '强制部署(忽略版本检查)' | |
| required: false | |
| type: boolean | |
| default: false | |
| deploy_frontend: | |
| description: '是否部署前端(auto=仅版本变化时,deploy=强制部署,skip=跳过)' | |
| required: false | |
| type: choice | |
| default: auto | |
| options: | |
| - auto | |
| - deploy | |
| - skip | |
| env: | |
| SUBSTORE_REPO: sub-store-org/Sub-Store | |
| FRONTEND_REPO: sub-store-org/Sub-Store-Front-End | |
| jobs: | |
| check-updates: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| deploy_backend: ${{ steps.check.outputs.deploy_backend }} | |
| deploy_frontend_needed: ${{ steps.check.outputs.deploy_frontend_needed }} | |
| backend_version: ${{ steps.check.outputs.backend_version }} | |
| frontend_version: ${{ steps.check.outputs.frontend_version }} | |
| deploy_frontend: ${{ steps.frontend-check.outputs.deploy_frontend }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup jq | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y jq | |
| - name: Restore Last Version Cache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: | | |
| .last-backend-version | |
| .last-frontend-version | |
| key: version-cache-${{ github.ref_name }}-${{ github.run_id }} | |
| restore-keys: | | |
| version-cache-${{ github.ref_name }}- | |
| - name: Check for New Releases | |
| id: check | |
| run: | | |
| # 获取最新版本 | |
| BACKEND_VERSION=$(curl -m 10 -s https://api.github.com/repos/${{ env.SUBSTORE_REPO }}/releases/latest | jq -r '.tag_name' || echo "fetch-failed") | |
| FRONTEND_VERSION=$(curl -m 10 -s https://api.github.com/repos/${{ env.FRONTEND_REPO }}/releases/latest | jq -r '.tag_name' || echo "fetch-failed") | |
| if [[ "$BACKEND_VERSION" == "fetch-failed" || "$FRONTEND_VERSION" == "fetch-failed" ]]; then | |
| echo "::error::获取上游 releases 版本失败(可能是网络/限流),停止部署" | |
| exit 1 | |
| fi | |
| echo "backend_version=$BACKEND_VERSION" >> $GITHUB_OUTPUT | |
| echo "frontend_version=$FRONTEND_VERSION" >> $GITHUB_OUTPUT | |
| # 获取上次部署的版本 | |
| LAST_BACKEND=$(cat .last-backend-version 2>/dev/null || echo "none") | |
| LAST_FRONTEND=$(cat .last-frontend-version 2>/dev/null || echo "none") | |
| echo "Current backend: $BACKEND_VERSION (last: $LAST_BACKEND)" | |
| echo "Current frontend: $FRONTEND_VERSION (last: $LAST_FRONTEND)" | |
| # 使用动态令牌避免 if 条件/日志被意外处理(不要用纯 true/false) | |
| DEPLOY_TOKEN="ACTION_START_${{ github.run_id }}" | |
| # 后端:push / force / 版本变化 都触发 | |
| if [[ "${{ github.event.inputs.force_deploy }}" == "true" ]] || \ | |
| [[ "${{ github.event_name }}" == "push" ]] || \ | |
| [[ "$BACKEND_VERSION" != "$LAST_BACKEND" ]]; then | |
| echo "deploy_backend=$DEPLOY_TOKEN" >> $GITHUB_OUTPUT | |
| echo "Backend deploy: YES" | |
| else | |
| echo "deploy_backend=ACTION_HOLD" >> $GITHUB_OUTPUT | |
| echo "Backend deploy: NO" | |
| fi | |
| # 前端:支持 workflow_dispatch 手动控制(auto/deploy/skip) | |
| MODE="${{ github.event.inputs.deploy_frontend }}" | |
| if [[ -z "$MODE" ]]; then MODE="auto"; fi | |
| if [[ "$MODE" == "deploy" ]]; then | |
| echo "deploy_frontend_needed=$DEPLOY_TOKEN" >> $GITHUB_OUTPUT | |
| echo "Frontend deploy: YES (manual deploy)" | |
| elif [[ "$MODE" == "skip" ]]; then | |
| echo "deploy_frontend_needed=ACTION_HOLD" >> $GITHUB_OUTPUT | |
| echo "Frontend deploy: NO (manual skip)" | |
| elif [[ "$FRONTEND_VERSION" != "$LAST_FRONTEND" ]]; then | |
| echo "deploy_frontend_needed=$DEPLOY_TOKEN" >> $GITHUB_OUTPUT | |
| echo "Frontend deploy: YES (version changed)" | |
| else | |
| echo "deploy_frontend_needed=ACTION_HOLD" >> $GITHUB_OUTPUT | |
| echo "Frontend deploy: NO" | |
| fi | |
| - name: Check If Frontend Deploy Is Enabled | |
| id: frontend-check | |
| env: | |
| DEPLOY_FRONTEND_SECRET: ${{ secrets.DEPLOY_SUB_STORE_FRONTEND }} | |
| run: | | |
| if [ -n "$DEPLOY_FRONTEND_SECRET" ]; then | |
| echo "deploy_frontend=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "deploy_frontend=false" >> $GITHUB_OUTPUT | |
| fi | |
| deploy-backend: | |
| needs: check-updates | |
| if: contains(needs.check-updates.outputs.deploy_backend, 'ACTION_START') | |
| runs-on: ubuntu-latest | |
| name: Deploy Backend | |
| steps: | |
| - name: Validate JWT_SECRET | |
| run: | | |
| if [ -z "${{ secrets.JWT_SECRET }}" ]; then | |
| echo "::error::JWT_SECRET 未设置!" | |
| exit 1 | |
| fi | |
| - name: Checkout Workers Adapter Code | |
| uses: actions/checkout@v4 | |
| - name: Download Sub-Store Source Code | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| VERSION=${{ needs.check-updates.outputs.backend_version }} | |
| echo "Downloading Sub-Store source $VERSION..." | |
| # 使用仓库内脚本拉取后端源码(支持 GITHUB_TOKEN 降低限流概率) | |
| SUBSTORE_REPO='${{ env.SUBSTORE_REPO }}' \ | |
| SUBSTORE_VERSION="$VERSION" \ | |
| bash scripts/fetch-substore.sh | |
| # 复制整个项目到构建目录(包含 sub-store/backend) | |
| mkdir -p build | |
| rsync -av --exclude='.git' --exclude='build' --exclude='node_modules' . build/ | |
| - name: Configure wrangler.toml | |
| run: | | |
| cd build | |
| cp wrangler.toml.example wrangler.toml | |
| JWT_SECRET='${{ secrets.JWT_SECRET }}' | |
| ESCAPED_JWT_SECRET=$(printf '%s' "$JWT_SECRET" | sed -e 's/[\\/&]/\\\\&/g') | |
| sed -i "s|__JWT_SECRET__|$ESCAPED_JWT_SECRET|g" wrangler.toml | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: latest | |
| - name: Install backend dependencies | |
| working-directory: build/sub-store/backend | |
| run: pnpm install | |
| - name: Install dependencies | |
| working-directory: build | |
| run: bun install | |
| - name: Build with Vite | |
| working-directory: build | |
| run: bun run build | |
| - name: Deploy to Cloudflare Workers | |
| working-directory: build | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} | |
| run: | | |
| bun run deploy:action | |
| echo "Deploy completed" | |
| deploy-frontend: | |
| needs: check-updates | |
| if: contains(needs.check-updates.outputs.deploy_frontend_needed, 'ACTION_START') && needs.check-updates.outputs.deploy_frontend == 'true' | |
| runs-on: ubuntu-latest | |
| name: Deploy Frontend | |
| steps: | |
| - name: Download Sub-Store Frontend dist | |
| run: | | |
| VERSION=${{ needs.check-updates.outputs.frontend_version }} | |
| echo "Downloading Sub-Store Frontend $VERSION..." | |
| # 直接下载 release 中的 dist.zip(已构建好) | |
| curl -L "https://github.com/${{ env.FRONTEND_REPO }}/releases/download/${VERSION}/dist.zip" -o dist.zip | |
| unzip dist.zip -d frontend-dist | |
| - name: Deploy to Cloudflare Pages | |
| uses: cloudflare/wrangler-action@v3 | |
| with: | |
| apiToken: ${{ secrets.CF_API_TOKEN }} | |
| accountId: ${{ secrets.CF_ACCOUNT_ID }} | |
| command: pages deploy frontend-dist/dist --project-name=sub-store-frontend | |
| update-version-cache: | |
| needs: [check-updates, deploy-backend, deploy-frontend] | |
| if: always() && (needs.deploy-backend.result == 'success' || needs.deploy-frontend.result == 'success') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Restore Last Version Cache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: | | |
| .last-backend-version | |
| .last-frontend-version | |
| key: version-cache-${{ github.ref_name }}-${{ github.run_id }} | |
| restore-keys: | | |
| version-cache-${{ github.ref_name }}- | |
| - name: Update version files | |
| run: | | |
| # 只在对应组件部署成功后,才推进它的“上次部署版本” | |
| if [[ "${{ needs.deploy-backend.result }}" == "success" ]]; then | |
| echo "${{ needs.check-updates.outputs.backend_version }}" > .last-backend-version | |
| else | |
| test -f .last-backend-version || echo "none" > .last-backend-version | |
| fi | |
| if [[ "${{ needs.deploy-frontend.result }}" == "success" ]]; then | |
| echo "${{ needs.check-updates.outputs.frontend_version }}" > .last-frontend-version | |
| else | |
| test -f .last-frontend-version || echo "none" > .last-frontend-version | |
| fi | |
| - name: Save version cache | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: | | |
| .last-backend-version | |
| .last-frontend-version | |
| key: version-cache-${{ github.ref_name }}-${{ github.run_id }} | |
| summary: | |
| needs: [check-updates, deploy-backend, deploy-frontend] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Deploy Summary | |
| run: | | |
| echo "## 部署摘要报告" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**触发方式**: \`${{ github.event_name }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| 组件 | 版本 | 状态 |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------|------|------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| 后端 | \`${{ needs.check-updates.outputs.backend_version }}\` | \`${{ needs.deploy-backend.result }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| 前端 | \`${{ needs.check-updates.outputs.frontend_version }}\` | \`${{ needs.deploy-frontend.result }}\` |" >> $GITHUB_STEP_SUMMARY |