Move health endpoint to /api/health (Cloud Run reserves /healthz) #3
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 Cloud Run | |
| # Builds the single-container app (SPA + API + WebSocket) and deploys it to | |
| # Cloud Run, wired to Cloud SQL (Postgres+pgvector), Memorystore (Redis, via a | |
| # Serverless VPC connector), and a GCS bucket for generated images. | |
| # One-time GCP/GitHub setup is in DEPLOY.md. | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| env: | |
| SERVICE: ai-dm | |
| REGION: europe-west2 # London (infra + Gemini DM + Imagen) | |
| # The image-consistency model (gemini-2.5-flash-image) isn't served in | |
| # europe-west2, so reference-conditioned calls go to europe-west1. | |
| EDIT_LOCATION: europe-west1 | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - run: npm ci | |
| - run: npm run build --workspace @ai-dm/engine # other packages resolve @ai-dm/engine via its dist | |
| - run: npm run typecheck | |
| - run: npm test | |
| deploy: | |
| needs: test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write # required for Workload Identity Federation | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - id: auth | |
| uses: google-github-actions/auth@v2 | |
| with: | |
| workload_identity_provider: ${{ secrets.WIF_PROVIDER }} | |
| service_account: ${{ secrets.DEPLOY_SERVICE_ACCOUNT }} | |
| - uses: google-github-actions/setup-gcloud@v2 | |
| # Build the image and push to Artifact Registry (repo provisioned by | |
| # Terraform — see infra/), then deploy it to Cloud Run. | |
| - name: Build & push image | |
| run: | | |
| gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet | |
| echo "IMAGE=${REGION}-docker.pkg.dev/${{ secrets.GCP_PROJECT }}/aidm/ai-dm:${GITHUB_SHA}" >> "$GITHUB_ENV" | |
| - run: docker build -t "$IMAGE" . | |
| - run: docker push "$IMAGE" | |
| # Env vars use the ^##^ delimiter so URLs with special characters pass | |
| # through cleanly. min/max-instances=1: the live session is still in-process | |
| # memory, so we run a single instance for now (Redis is wired and ready for | |
| # the multi-instance follow-up). --timeout=3600 keeps WebSockets long-lived. | |
| - name: Deploy | |
| run: | | |
| gcloud run deploy "$SERVICE" \ | |
| --image "$IMAGE" \ | |
| --project "${{ secrets.GCP_PROJECT }}" \ | |
| --region "$REGION" \ | |
| --platform managed \ | |
| --allow-unauthenticated \ | |
| --min-instances=1 --max-instances=1 \ | |
| --timeout=3600 --memory=1Gi --cpu=1 \ | |
| --execution-environment=gen2 \ | |
| --service-account "${{ secrets.RUNTIME_SERVICE_ACCOUNT }}" \ | |
| --add-cloudsql-instances "${{ secrets.CLOUDSQL_INSTANCE }}" \ | |
| --vpc-connector "${{ secrets.VPC_CONNECTOR }}" \ | |
| --vpc-egress private-ranges-only \ | |
| --add-volume=name=images,type=cloud-storage,bucket=${{ secrets.IMAGE_BUCKET }} \ | |
| --add-volume-mount=volume=images,mount-path=/images \ | |
| --set-env-vars="^##^DM_PROVIDER=gemini##IMAGE_PROVIDER=gemini##GEMINI_MODEL=gemini-2.5-flash##GCP_PROJECT=${{ secrets.GCP_PROJECT }}##GCP_LOCATION=$REGION##GEMINI_EDIT_LOCATION=$EDIT_LOCATION##IMAGE_DIR=/images##DATABASE_URL=${{ secrets.DATABASE_URL }}##REDIS_URL=${{ secrets.REDIS_URL }}" | |
| - name: Show URL | |
| run: gcloud run services describe "$SERVICE" --project "${{ secrets.GCP_PROJECT }}" --region "$REGION" --format='value(status.url)' |