Skip to content

Commit ae1d24d

Browse files
committed
workflow file add
1 parent 63a79c9 commit ae1d24d

1 file changed

Lines changed: 239 additions & 0 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
name: Deploy to Google Cloud
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
env:
10+
PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
11+
GAR_LOCATION: us-central1
12+
REPOSITORY: taskmanager
13+
SERVICE_BACKEND: taskmanager-backend
14+
SERVICE_FRONTEND: taskmanager-frontend
15+
REGION: us-central1
16+
17+
jobs:
18+
test:
19+
name: Test Application
20+
runs-on: ubuntu-latest
21+
22+
services:
23+
postgres:
24+
image: postgres:15
25+
env:
26+
POSTGRES_PASSWORD: postgres
27+
POSTGRES_DB: taskmanager_test
28+
options: >-
29+
--health-cmd pg_isready
30+
--health-interval 10s
31+
--health-timeout 5s
32+
--health-retries 5
33+
ports:
34+
- 5432:5432
35+
36+
steps:
37+
- name: Checkout code
38+
uses: actions/checkout@v4
39+
40+
- name: Setup Node.js
41+
uses: actions/setup-node@v4
42+
with:
43+
node-version: '18'
44+
cache: 'npm'
45+
cache-dependency-path: |
46+
backend/package-lock.json
47+
frontend/package-lock.json
48+
49+
- name: Install backend dependencies
50+
working-directory: ./backend
51+
run: npm ci
52+
53+
- name: Install frontend dependencies
54+
working-directory: ./frontend
55+
run: npm ci
56+
57+
- name: Generate Prisma client
58+
working-directory: ./backend
59+
run: npx prisma generate
60+
61+
- name: Run Prisma migrations
62+
working-directory: ./backend
63+
run: npx prisma migrate deploy
64+
env:
65+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/taskmanager_test?schema=public
66+
67+
- name: Build backend
68+
working-directory: ./backend
69+
run: npm run build
70+
71+
- name: Build frontend
72+
working-directory: ./frontend
73+
run: npm run build
74+
75+
deploy:
76+
name: Deploy to Google Cloud
77+
needs: test
78+
runs-on: ubuntu-latest
79+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
80+
81+
steps:
82+
- name: Checkout code
83+
uses: actions/checkout@v4
84+
85+
- name: Google Auth
86+
id: auth
87+
uses: google-github-actions/auth@v2
88+
with:
89+
credentials_json: '${{ secrets.GCP_SA_KEY }}'
90+
91+
- name: Set up Cloud SDK
92+
uses: google-github-actions/setup-gcloud@v2
93+
94+
- name: Configure Docker to use gcloud as credential helper
95+
run: gcloud auth configure-docker $GAR_LOCATION-docker.pkg.dev
96+
97+
- name: Create Artifact Registry repository
98+
run: |
99+
gcloud artifacts repositories create $REPOSITORY \
100+
--repository-format=docker \
101+
--location=$GAR_LOCATION \
102+
--description="Task Manager application images" \
103+
--project=$PROJECT_ID || true
104+
105+
- name: Build and push backend image
106+
run: |
107+
cd backend
108+
docker build -t $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_BACKEND:$GITHUB_SHA .
109+
docker push $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_BACKEND:$GITHUB_SHA
110+
111+
- name: Build and push frontend image
112+
run: |
113+
cd frontend
114+
docker build -t $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_FRONTEND:$GITHUB_SHA .
115+
docker push $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_FRONTEND:$GITHUB_SHA
116+
117+
- name: Create Cloud SQL instance
118+
run: |
119+
gcloud sql instances create taskmanager-db \
120+
--database-version=POSTGRES_15 \
121+
--tier=db-f1-micro \
122+
--region=$REGION \
123+
--storage-type=SSD \
124+
--storage-size=10GB \
125+
--project=$PROJECT_ID || true
126+
127+
- name: Create database
128+
run: |
129+
gcloud sql databases create taskmanager \
130+
--instance=taskmanager-db \
131+
--project=$PROJECT_ID || true
132+
133+
- name: Create database user
134+
run: |
135+
gcloud sql users create taskmanager-user \
136+
--instance=taskmanager-db \
137+
--password=${{ secrets.DB_PASSWORD }} \
138+
--project=$PROJECT_ID || true
139+
140+
- name: Create Cloud Storage bucket
141+
run: |
142+
gsutil mb -p $PROJECT_ID -c STANDARD -l $REGION gs://$PROJECT_ID-taskmanager-files || true
143+
144+
- name: Deploy backend to Cloud Run
145+
run: |
146+
gcloud run deploy $SERVICE_BACKEND \
147+
--image $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_BACKEND:$GITHUB_SHA \
148+
--platform managed \
149+
--region $REGION \
150+
--allow-unauthenticated \
151+
--memory 512Mi \
152+
--cpu 1 \
153+
--min-instances 0 \
154+
--max-instances 10 \
155+
--set-env-vars="DATABASE_URL=${{ secrets.DATABASE_URL }}" \
156+
--set-env-vars="JWT_SECRET=${{ secrets.JWT_SECRET }}" \
157+
--set-env-vars="JWT_EXPIRES_IN=7d" \
158+
--set-env-vars="NODE_ENV=production" \
159+
--set-env-vars="GOOGLE_CLOUD_PROJECT_ID=$PROJECT_ID" \
160+
--set-env-vars="GOOGLE_CLOUD_STORAGE_BUCKET=$PROJECT_ID-taskmanager-files" \
161+
--set-env-vars="FRONTEND_URL=https://$SERVICE_FRONTEND-${{ steps.auth.outputs.credentials_file_path | hashFiles }}-$REGION.run.app" \
162+
--project=$PROJECT_ID
163+
164+
- name: Get backend service URL
165+
id: backend-url
166+
run: |
167+
BACKEND_URL=$(gcloud run services describe $SERVICE_BACKEND --platform managed --region $REGION --format 'value(status.url)' --project=$PROJECT_ID)
168+
echo "url=$BACKEND_URL" >> $GITHUB_OUTPUT
169+
170+
- name: Deploy frontend to Cloud Run
171+
run: |
172+
# Create a temporary Dockerfile for frontend with backend URL
173+
cd frontend
174+
cat > Dockerfile.production << EOF
175+
FROM nginx:alpine
176+
COPY dist /usr/share/nginx/html
177+
COPY nginx.conf /etc/nginx/nginx.conf
178+
179+
# Add environment variable substitution
180+
RUN apk add --no-cache gettext
181+
COPY entrypoint.sh /entrypoint.sh
182+
RUN chmod +x /entrypoint.sh
183+
184+
EXPOSE 80
185+
ENTRYPOINT ["/entrypoint.sh"]
186+
CMD ["nginx", "-g", "daemon off;"]
187+
EOF
188+
189+
# Create entrypoint script for runtime environment variable substitution
190+
cat > entrypoint.sh << 'EOF'
191+
#!/bin/sh
192+
# Replace API_URL placeholder in built files
193+
find /usr/share/nginx/html -name "*.js" -exec sed -i "s|__API_URL__|${API_URL}|g" {} \;
194+
exec "$@"
195+
EOF
196+
197+
# Build with production Dockerfile
198+
docker build -f Dockerfile.production -t $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_FRONTEND:$GITHUB_SHA .
199+
docker push $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_FRONTEND:$GITHUB_SHA
200+
201+
gcloud run deploy $SERVICE_FRONTEND \
202+
--image $GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$SERVICE_FRONTEND:$GITHUB_SHA \
203+
--platform managed \
204+
--region $REGION \
205+
--allow-unauthenticated \
206+
--memory 256Mi \
207+
--cpu 1 \
208+
--min-instances 0 \
209+
--max-instances 5 \
210+
--set-env-vars="API_URL=${{ steps.backend-url.outputs.url }}" \
211+
--project=$PROJECT_ID
212+
213+
- name: Run database migrations
214+
run: |
215+
# Get Cloud SQL connection name
216+
CONNECTION_NAME=$(gcloud sql instances describe taskmanager-db --format="value(connectionName)" --project=$PROJECT_ID)
217+
218+
# Run migrations using Cloud SQL Proxy
219+
docker run --rm \
220+
-v "${{ github.workspace }}/backend:/workspace" \
221+
-w /workspace \
222+
--network host \
223+
node:18-alpine sh -c "
224+
npm install &&
225+
npx prisma generate &&
226+
npx prisma migrate deploy
227+
"
228+
env:
229+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
230+
231+
- name: Output deployment URLs
232+
run: |
233+
BACKEND_URL=$(gcloud run services describe $SERVICE_BACKEND --platform managed --region $REGION --format 'value(status.url)' --project=$PROJECT_ID)
234+
FRONTEND_URL=$(gcloud run services describe $SERVICE_FRONTEND --platform managed --region $REGION --format 'value(status.url)' --project=$PROJECT_ID)
235+
236+
echo "🚀 Deployment completed successfully!"
237+
echo "Backend URL: $BACKEND_URL"
238+
echo "Frontend URL: $FRONTEND_URL"
239+
echo "📧 Please update CORS settings in backend if needed."

0 commit comments

Comments
 (0)