name: CI on: push: branches: - main pull_request: jobs: python-quality: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: | python -m pip install --upgrade pip pip install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements.lock -r requirements-dev.lock - name: Ruff run: python -m ruff check . - name: Pytest run: python -m pytest frontend-quality: runs-on: ubuntu-latest defaults: run: working-directory: frontend steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" cache-dependency-path: frontend/package-lock.json - name: Install dependencies run: npm ci - name: Business state tests run: npm run test:business build-and-push: needs: [python-quality, frontend-quality] if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest strategy: matrix: image: - name: backend context: . file: Dockerfile tag: ghcr.io/yangyuan-zhen/polyweather-backend - name: frontend context: ./frontend file: ./frontend/Dockerfile tag: ghcr.io/yangyuan-zhen/polyweather-frontend permissions: contents: read packages: write steps: - name: Checkout uses: actions/checkout@v4 - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push image env: IMAGE_NAME: ${{ matrix.image.name }} IMAGE_CONTEXT: ${{ matrix.image.context }} IMAGE_FILE: ${{ matrix.image.file }} IMAGE_TAG: ${{ matrix.image.tag }} NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }} NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }} NEXT_PUBLIC_SITE_URL: ${{ secrets.NEXT_PUBLIC_SITE_URL || 'https://polyweather.top' }} NEXT_PUBLIC_POLYWEATHER_API_BASE_URL: ${{ secrets.NEXT_PUBLIC_POLYWEATHER_API_BASE_URL || '' }} NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID || '' }} NEXT_PUBLIC_WALLETCONNECT_POLYGON_RPC_URL: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_POLYGON_RPC_URL || 'https://polygon-bor-rpc.publicnode.com' }} NEXT_PUBLIC_PAYMENT_ALLOWED_HOSTS: ${{ secrets.NEXT_PUBLIC_PAYMENT_ALLOWED_HOSTS || 'polyweather.top,www.polyweather.top' }} NEXT_PUBLIC_TURNSTILE_SITE_KEY: ${{ secrets.NEXT_PUBLIC_TURNSTILE_SITE_KEY || '' }} run: | set -euo pipefail tags=(-t "${IMAGE_TAG}:latest" -t "${IMAGE_TAG}:${GITHUB_SHA}") build_args=() if [ "${IMAGE_NAME}" = "frontend" ]; then build_args=( --build-arg "NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL}" --build-arg "NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY}" --build-arg "NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL}" --build-arg "NEXT_PUBLIC_POLYWEATHER_API_BASE_URL=${NEXT_PUBLIC_POLYWEATHER_API_BASE_URL}" --build-arg "NEXT_PUBLIC_POLYWEATHER_LOCAL_FULL_ACCESS=false" --build-arg "NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=${NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID}" --build-arg "NEXT_PUBLIC_WALLETCONNECT_POLYGON_RPC_URL=${NEXT_PUBLIC_WALLETCONNECT_POLYGON_RPC_URL}" --build-arg "NEXT_PUBLIC_PAYMENT_ALLOWED_HOSTS=${NEXT_PUBLIC_PAYMENT_ALLOWED_HOSTS}" --build-arg "NEXT_PUBLIC_TURNSTILE_SITE_KEY=${NEXT_PUBLIC_TURNSTILE_SITE_KEY}" ) fi docker build -f "${IMAGE_FILE}" "${tags[@]}" "${build_args[@]}" "${IMAGE_CONTEXT}" docker push "${IMAGE_TAG}:latest" docker push "${IMAGE_TAG}:${GITHUB_SHA}" cloudflare-cache-rules: needs: [python-quality] if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Apply Cloudflare cache rules env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} run: | if [ -z "${CLOUDFLARE_API_TOKEN}" ]; then echo "CLOUDFLARE_API_TOKEN is not configured; skipping Cache Rules sync" exit 0 fi if [ -z "${CLOUDFLARE_ZONE_ID}" ]; then echo "CLOUDFLARE_ZONE_ID is not configured; skipping Cache Rules sync" exit 0 fi python scripts/configure_cloudflare_free.py --apply deploy: needs: [build-and-push] if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest concurrency: group: polyweather-production-deploy cancel-in-progress: false steps: - name: Checkout uses: actions/checkout@v4 - name: Deploy to VPS env: GHCR_PAT: ${{ secrets.GHCR_PAT }} run: | mkdir -p ~/.ssh echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa scp -o StrictHostKeyChecking=accept-new deploy.sh ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }}:/tmp/deploy.sh printf '%s\n' "$GHCR_PAT" | ssh -o StrictHostKeyChecking=accept-new ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} " bash /tmp/deploy.sh '${{ github.sha }}' "