Skip to content

Commit db1bc32

Browse files
committed
Fix: CI/CD Pipeline
1 parent cf60fa6 commit db1bc32

1 file changed

Lines changed: 141 additions & 58 deletions

File tree

.github/workflows/main.yml

Lines changed: 141 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,49 +4,42 @@ name: PromptMan CI/CD to Google Cloud Run
44
on:
55
push:
66
branches:
7-
- main # Trigger deployment on pushes to the main branch
7+
- main # Deploy when merging/pushing to main
88

99
env:
10-
# GCP Settings from GitHub Secrets
10+
# GCP Settings from Secrets
1111
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
1212
GCP_REGION: ${{ secrets.GCP_REGION }}
13-
ARTIFACT_REGISTRY_REPO: ${{ secrets.ARTIFACT_REGISTRY_REPO }} # e.g., asia-south1-docker.pkg.dev/your-project-id/promptman-repo
14-
15-
# Image and Service Naming Conventions
13+
ARTIFACT_REGISTRY_REPO: ${{ secrets.ARTIFACT_REGISTRY_REPO }}
14+
# Image and Service Names
1615
BACKEND_IMAGE_NAME: promptman-backend
1716
FRONTEND_IMAGE_NAME: promptman-frontend
1817
BACKEND_SERVICE_NAME: promptman-backend
1918
FRONTEND_SERVICE_NAME: promptman-frontend
20-
21-
# VPC Connector Name (ensure this exists in your GCP project and region)
22-
VPC_CONNECTOR_NAME: promptman-connector
23-
24-
# Use the commit SHA for unique Docker image tags for better traceability
19+
VPC_CONNECTOR_NAME: promptman-connector
20+
# Use commit SHA for unique image tags
2521
IMAGE_TAG: ${{ github.sha }}
2622

2723
jobs:
28-
# =======================================================
29-
# 1. Build & Push Docker Images using Google Cloud Build
30-
# =======================================================
3124
build_and_push_images:
3225
name: Build & Push Images
3326
runs-on: ubuntu-latest
34-
# This job runs only on pushes to the main branch
3527
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
3628

3729
permissions:
38-
contents: 'read' # Required to checkout the repository code
39-
id-token: 'write' # Required for Workload Identity Federation
30+
contents: 'read'
31+
id-token: 'write'
4032

41-
outputs: # Define outputs to pass image URIs to deployment jobs
42-
backend_image_uri: ${{ steps.build_backend.outputs.image_uri }}
43-
frontend_image_uri: ${{ steps.build_frontend.outputs.image_uri }}
33+
outputs:
34+
# Get the image_uri from the step that confirms build success
35+
backend_image_uri: ${{ steps.wait_backend_build.outputs.image_uri }}
36+
frontend_image_uri: ${{ steps.wait_frontend_build.outputs.image_uri }}
4437

4538
steps:
4639
- name: Checkout code
4740
uses: actions/checkout@v4
4841

49-
- name: Authenticate to Google Cloud (via Workload Identity Federation)
42+
- name: Authenticate to Google Cloud
5043
id: auth
5144
uses: google-github-actions/auth@v2
5245
with:
@@ -56,56 +49,141 @@ jobs:
5649
- name: Set up Google Cloud SDK
5750
uses: google-github-actions/setup-gcloud@v2
5851

59-
# Configure Docker helper to authenticate with Artifact Registry (uses gcloud credentials)
6052
- name: Configure Docker for Artifact Registry
6153
run: gcloud auth configure-docker ${{ env.GCP_REGION }}-docker.pkg.dev --quiet
6254

63-
- name: Build and Push Backend Docker Image (using Cloud Build)
64-
id: build_backend
55+
- name: Submit Backend Build and Get ID
56+
id: submit_backend_build
6557
run: |
66-
IMAGE_URI="${{ env.ARTIFACT_REGISTRY_REPO }}/${{ env.BACKEND_IMAGE_NAME }}:${{ env.IMAGE_TAG }}"
67-
echo "Building Backend Image to: $IMAGE_URI"
68-
gcloud builds submit ./backend \
69-
--tag "$IMAGE_URI" \
58+
TARGET_IMAGE_URI="${{ env.ARTIFACT_REGISTRY_REPO }}/${{ env.BACKEND_IMAGE_NAME }}:${{ env.IMAGE_TAG }}"
59+
echo "Submitting Backend Build for Image: $TARGET_IMAGE_URI"
60+
61+
BUILD_ID_RAW=$(gcloud builds submit ./backend \
62+
--tag "$TARGET_IMAGE_URI" \
7063
--project=${{ env.GCP_PROJECT_ID }} \
71-
--quiet # Suppress verbose output from gcloud
72-
echo "image_uri=$IMAGE_URI" >> $GITHUB_OUTPUT # Set output for subsequent jobs
64+
--quiet \
65+
--format='value(id)')
66+
67+
BUILD_ID=$(echo "$BUILD_ID_RAW" | grep -o -E '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}' | head -n 1)
68+
69+
if [ -z "$BUILD_ID" ]; then
70+
echo "::warning::Could not extract BUILD_ID using UUID pattern from 'gcloud builds submit' output (Backend). Raw output was: [$BUILD_ID_RAW]. Attempting fallback."
71+
BUILD_ID_FALLBACK=$(gcloud builds list --project=${{ env.GCP_PROJECT_ID }} --filter="sourceProvenance.resolvedRepoSource.commitSha='${{ github.sha }}' AND buildTriggerId=''" --sort-by=~createTime --format='value(id)' --limit=1)
72+
if [ -z "$BUILD_ID_FALLBACK" ]; then
73+
echo "::error::Could not determine BUILD_ID even via fallback list command (Backend)."
74+
exit 1
75+
else
76+
BUILD_ID=$(echo "$BUILD_ID_FALLBACK" | xargs)
77+
echo "Using BUILD_ID from fallback (Backend): $BUILD_ID"
78+
fi
79+
fi
80+
81+
if [ -z "$BUILD_ID" ]; then
82+
echo "::error::Failed to obtain a valid BUILD_ID for Backend."
83+
exit 1
84+
fi
7385
74-
- name: Build and Push Frontend Docker Image (using Cloud Build and frontend/cloudbuild.yaml)
75-
id: build_frontend
86+
echo "Extracted Cloud Build ID (Backend): $BUILD_ID"
87+
echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT
88+
# Output the *intended* image URI from this step
89+
echo "target_image_uri=$TARGET_IMAGE_URI" >> $GITHUB_OUTPUT
90+
91+
- name: Wait for Backend Build and Verify
92+
id: wait_backend_build
7693
run: |
77-
IMAGE_URI="${{ env.ARTIFACT_REGISTRY_REPO }}/${{ env.FRONTEND_IMAGE_NAME }}:${{ env.IMAGE_TAG }}"
78-
echo "Building Frontend Image to: $IMAGE_URI"
79-
# Pass substitutions required by frontend/cloudbuild.yaml:
80-
# _REACT_APP_GA_MEASUREMENT_ID comes from GitHub Secrets
81-
# _IMAGE_TAG_NAME is constructed here
82-
gcloud builds submit ./frontend \
94+
BUILD_ID="${{ steps.submit_backend_build.outputs.build_id }}"
95+
TARGET_IMAGE_URI="${{ steps.submit_backend_build.outputs.target_image_uri }}" # Get the intended URI
96+
echo "Waiting for Backend Build ID: $BUILD_ID to complete..."
97+
gcloud builds log --stream "$BUILD_ID" --project=${{ env.GCP_PROJECT_ID }} || echo "Log streaming potentially failed for Backend, checking status..."
98+
99+
FINAL_STATUS=$(gcloud builds describe "$BUILD_ID" --project=${{ env.GCP_PROJECT_ID }} --format='value(status)')
100+
echo "Backend Build final status: $FINAL_STATUS"
101+
if [[ "$FINAL_STATUS" == "SUCCESS" ]]; then
102+
echo "Backend build $BUILD_ID succeeded."
103+
# Only set the output if the build was successful
104+
echo "image_uri=$TARGET_IMAGE_URI" >> $GITHUB_OUTPUT
105+
elif [ "$FINAL_STATUS" == "WORKING" ]; then
106+
echo "::warning::Backend Build $BUILD_ID still in WORKING state after log stream finished. Proceeding cautiously but setting image_uri."
107+
echo "image_uri=$TARGET_IMAGE_URI" >> $GITHUB_OUTPUT # Still set if working, deploy might catch it later
108+
else
109+
echo "::error::Backend build $BUILD_ID failed or has unexpected status $FINAL_STATUS"
110+
exit 1
111+
fi
112+
113+
- name: Submit Frontend Build and Get ID
114+
id: submit_frontend_build
115+
run: |
116+
TARGET_IMAGE_URI="${{ env.ARTIFACT_REGISTRY_REPO }}/${{ env.FRONTEND_IMAGE_NAME }}:${{ env.IMAGE_TAG }}"
117+
echo "Submitting Frontend Build for Image: $TARGET_IMAGE_URI"
118+
119+
BUILD_ID_RAW=$(gcloud builds submit ./frontend \
83120
--config=frontend/cloudbuild.yaml \
84-
--substitutions=_REACT_APP_GA_MEASUREMENT_ID="${{ secrets.PROD_REACT_APP_GA_MEASUREMENT_ID }}",_IMAGE_TAG_NAME="$IMAGE_URI" \
121+
--substitutions=_REACT_APP_GA_MEASUREMENT_ID="${{ secrets.PROD_REACT_APP_GA_MEASUREMENT_ID }}",_IMAGE_TAG_NAME="$TARGET_IMAGE_URI" \
85122
--project=${{ env.GCP_PROJECT_ID }} \
86-
--quiet
87-
echo "image_uri=$IMAGE_URI" >> $GITHUB_OUTPUT # Set output for subsequent jobs
123+
--quiet \
124+
--format='value(id)')
125+
126+
BUILD_ID=$(echo "$BUILD_ID_RAW" | grep -o -E '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}' | head -n 1)
127+
128+
if [ -z "$BUILD_ID" ]; then
129+
echo "::warning::Could not extract BUILD_ID using UUID pattern from 'gcloud builds submit' output (Frontend). Raw output was: [$BUILD_ID_RAW]. Attempting fallback."
130+
BUILD_ID_FALLBACK=$(gcloud builds list --project=${{ env.GCP_PROJECT_ID }} --filter="sourceProvenance.resolvedRepoSource.commitSha='${{ github.sha }}' AND substitutions._IMAGE_TAG_NAME='$TARGET_IMAGE_URI' AND buildTriggerId=''" --sort-by=~createTime --format='value(id)' --limit=1)
131+
if [ -z "$BUILD_ID_FALLBACK" ]; then
132+
echo "::error::Could not determine BUILD_ID even via fallback list command (Frontend)."
133+
exit 1
134+
else
135+
BUILD_ID=$(echo "$BUILD_ID_FALLBACK" | xargs)
136+
echo "Using BUILD_ID from fallback (Frontend): $BUILD_ID"
137+
fi
138+
fi
139+
140+
if [ -z "$BUILD_ID" ]; then
141+
echo "::error::Failed to obtain a valid BUILD_ID for Frontend."
142+
exit 1
143+
fi
144+
145+
echo "Extracted Cloud Build ID (Frontend): $BUILD_ID"
146+
echo "build_id=$BUILD_ID" >> $GITHUB_OUTPUT
147+
echo "target_image_uri=$TARGET_IMAGE_URI" >> $GITHUB_OUTPUT
148+
149+
- name: Wait for Frontend Build and Verify
150+
id: wait_frontend_build
151+
run: |
152+
BUILD_ID="${{ steps.submit_frontend_build.outputs.build_id }}"
153+
TARGET_IMAGE_URI="${{ steps.submit_frontend_build.outputs.target_image_uri }}"
154+
echo "Waiting for Frontend Build ID: $BUILD_ID to complete..."
155+
gcloud builds log --stream "$BUILD_ID" --project=${{ env.GCP_PROJECT_ID }} || echo "Log streaming potentially failed for Frontend, checking status..."
156+
157+
FINAL_STATUS=$(gcloud builds describe "$BUILD_ID" --project=${{ env.GCP_PROJECT_ID }} --format='value(status)')
158+
echo "Frontend Build final status: $FINAL_STATUS"
159+
if [[ "$FINAL_STATUS" == "SUCCESS" ]]; then
160+
echo "Frontend build $BUILD_ID succeeded."
161+
echo "image_uri=$TARGET_IMAGE_URI" >> $GITHUB_OUTPUT
162+
elif [ "$FINAL_STATUS" == "WORKING" ]; then
163+
echo "::warning::Build $BUILD_ID still in WORKING state after log stream finished. Proceeding cautiously but setting image_uri."
164+
echo "image_uri=$TARGET_IMAGE_URI" >> $GITHUB_OUTPUT
165+
else
166+
echo "::error::Frontend build $BUILD_ID failed or has unexpected status $FINAL_STATUS"
167+
exit 1
168+
fi
88169
89-
# ==========================================
90-
# 2. Deploy Backend Service to Cloud Run
91-
# ==========================================
92170
deploy_backend:
93171
name: Deploy Backend Service
94172
runs-on: ubuntu-latest
95-
needs: build_and_push_images # Depends on images being successfully built and pushed
173+
needs: build_and_push_images
96174
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
97175

98176
permissions:
99177
contents: 'read'
100178
id-token: 'write'
101179

102-
outputs: # Output the deployed backend URL and host for the frontend deployment
180+
outputs:
103181
backend_url: ${{ steps.deploy_backend_service.outputs.url }}
104182
backend_host: ${{ steps.deploy_backend_service.outputs.host }}
105183

106184
steps:
107185
- name: Checkout code
108-
uses: actions/checkout@v4 # Though not strictly needed for deploy-from-image, good for consistency
186+
uses: actions/checkout@v4
109187

110188
- name: Authenticate to Google Cloud
111189
id: auth
@@ -118,11 +196,16 @@ jobs:
118196
uses: google-github-actions/setup-gcloud@v2
119197

120198
- name: Deploy Backend to Cloud Run
121-
id: deploy_backend_service # Step ID for referencing outputs
199+
id: deploy_backend_service
122200
run: |
123-
echo "Deploying Backend Image: ${{ needs.build_and_push_images.outputs.backend_image_uri }}"
201+
IMAGE_URI="${{ needs.build_and_push_images.outputs.backend_image_uri }}" # Correctly references output
202+
echo "Deploying Backend Image: $IMAGE_URI"
203+
if [ -z "$IMAGE_URI" ]; then
204+
echo "::error::Backend Image URI is empty. Build might have failed to output."
205+
exit 1
206+
fi
124207
gcloud run deploy ${{ env.BACKEND_SERVICE_NAME }} \
125-
--image "${{ needs.build_and_push_images.outputs.backend_image_uri }}" \
208+
--image "$IMAGE_URI" \
126209
--platform managed \
127210
--region ${{ env.GCP_REGION }} \
128211
--port 8000 \
@@ -136,22 +219,17 @@ jobs:
136219
--project=${{ env.GCP_PROJECT_ID }} \
137220
--quiet
138221
139-
# Get the URL of the deployed service to pass to the frontend deployment
140222
SERVICE_URL=$(gcloud run services describe ${{ env.BACKEND_SERVICE_NAME }} --platform managed --region ${{ env.GCP_REGION }} --format='value(status.url)' --project=${{ env.GCP_PROJECT_ID }})
141-
SERVICE_HOST=$(echo $SERVICE_URL | sed -e 's|^[^/]*//||' -e 's|/.*$||') # Extracts hostname
223+
SERVICE_HOST=$(echo $SERVICE_URL | sed -e 's|^[^/]*//||' -e 's|/.*$||')
142224
echo "Backend Service URL: $SERVICE_URL"
143225
echo "Backend Service Host: $SERVICE_HOST"
144-
# Set outputs for the next job
145226
echo "url=$SERVICE_URL" >> $GITHUB_OUTPUT
146227
echo "host=$SERVICE_HOST" >> $GITHUB_OUTPUT
147228
148-
# ==========================================
149-
# 3. Deploy Frontend Service to Cloud Run
150-
# ==========================================
151229
deploy_frontend:
152230
name: Deploy Frontend Service
153231
runs-on: ubuntu-latest
154-
needs: deploy_backend # Depends on backend deployment to get its URL
232+
needs: [build_and_push_images, deploy_backend] # Depends on both image build and backend deployment
155233
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
156234

157235
permissions:
@@ -176,17 +254,22 @@ jobs:
176254
run: |
177255
BACKEND_URL="${{ needs.deploy_backend.outputs.backend_url }}"
178256
BACKEND_HOST="${{ needs.deploy_backend.outputs.backend_host }}"
257+
IMAGE_URI="${{ needs.build_and_push_images.outputs.frontend_image_uri }}" # Correctly references output
179258
180259
if [ -z "$BACKEND_URL" ] || [ -z "$BACKEND_HOST" ]; then
181260
echo "::error::Backend URL or Host not received from previous job. Check deploy_backend job outputs."
182261
exit 1
183262
fi
263+
if [ -z "$IMAGE_URI" ]; then
264+
echo "::error::Frontend Image URI is empty. Build might have failed to output."
265+
exit 1
266+
fi
184267
185-
echo "Deploying Frontend Image: ${{ needs.build_and_push_images.outputs.frontend_image_uri }}"
268+
echo "Deploying Frontend Image: $IMAGE_URI"
186269
echo "Configuring Nginx with Backend URL: $BACKEND_URL and Host: $BACKEND_HOST"
187270
188271
gcloud run deploy ${{ env.FRONTEND_SERVICE_NAME }} \
189-
--image "${{ needs.build_and_push_images.outputs.frontend_image_uri }}" \
272+
--image "$IMAGE_URI" \
190273
--platform managed \
191274
--region ${{ env.GCP_REGION }} \
192275
--port 80 \

0 commit comments

Comments
 (0)