-
Notifications
You must be signed in to change notification settings - Fork 6
341 lines (300 loc) · 13.7 KB
/
Copy pathapi-deploy-developer.yml
File metadata and controls
341 lines (300 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# Deploys a developer Feeds API (Cloud Run) and Operations API (Cloud Function) to the DEV project.
#
# Completely isolated — no Terraform, no shared infrastructure changes.
# Only two new named resources are created/updated (both scoped to your suffix):
# - Cloud Run: developer-feed-api-<name_suffix>
# - Cloud Function: operations-api-developer-<name_suffix>
#
# Both use the same dev secrets/databases as the shared dev environment (read-safe).
#
# Prerequisites: none — reuses all existing dev environment vars and secrets:
# Secrets (already set for api-dev.yml): DEV_GCP_MOBILITY_FEEDS_SA_KEY, OP_SERVICE_ACCOUNT_TOKEN
# Variables (already set for api-dev.yml): DEV_MOBILITY_FEEDS_PROJECT_ID,
# DEV_MOBILITY_FEEDS_DEPLOYER_SERVICE_ACCOUNT, MOBILITY_FEEDS_REGION
#
# Usage: Actions → "Deploy Developer Feeds API" → Run workflow → fill in name_suffix
name: Deploy Developer Feeds API
on:
# PR for testing
push:
branches:
- 'user_feature_flag'
workflow_dispatch:
inputs:
name_suffix:
description: >
Developer identifier suffix. Creates:
Cloud Run: mobility-feed-api-developer-<suffix>
Cloud Function: operations-api-developer-<suffix>
Use your name or branch (e.g. "david", "feat-1723").
required: true
default: 'x'
deploy_feeds_api:
description: 'Deploy Feeds API (Cloud Run)'
required: false
default: 'true'
deploy_operations_api:
description: 'Deploy Operations API (Cloud Function)'
required: false
default: 'true'
env:
python_version: '3.11'
java_version: '11'
REGION: ${{ vars.MOBILITY_FEEDS_REGION }}
PROJECT_ID: ${{ vars.DEV_MOBILITY_FEEDS_PROJECT_ID }}
ARTIFACT_REPO: feeds-dev
# Dev VPC connector lives in the QA project (matches Terraform logic in infra/main.tf)
VPC_CONNECTOR: vpc-connector-qa
VPC_CONNECTOR_PROJECT: mobility-feeds-qa
jobs:
# ── Shared setup: generate code stubs needed by both deploy jobs ──────────
generate-and-build:
runs-on: ubuntu-latest
permissions: write-all
needs: []
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Extract commit hash and version from git
run: ./scripts/extract-hash-and-version.sh
- name: Set up JDK ${{ env.java_version }}
uses: actions/setup-java@v4
with:
java-version: ${{ env.java_version }}
distribution: 'temurin'
- uses: actions/setup-python@v5
with:
python-version: ${{ env.python_version }}
- name: Start PostgreSQL (needed for db-gen)
run: docker compose --env-file ./config/.env.local up -d --wait postgres postgres-test
- name: Install Liquibase
env:
LIQUIBASE_VERSION: 4.33.0
run: |
curl -sSL https://github.com/liquibase/liquibase/releases/download/v${LIQUIBASE_VERSION}/liquibase-${LIQUIBASE_VERSION}.tar.gz -o liquibase.tar.gz
mkdir liquibase-dist && tar -xzf liquibase.tar.gz -C liquibase-dist
sudo mv liquibase-dist /usr/local/liquibase
sudo ln -sf /usr/local/liquibase/liquibase /usr/local/bin/liquibase
- name: Run Liquibase migrations
working-directory: ${{ github.workspace }}/liquibase
run: |
export LIQUIBASE_COMMAND_USERNAME=postgres
export LIQUIBASE_COMMAND_PASSWORD=postgres
export LIQUIBASE_COMMAND_URL=jdbc:postgresql://localhost:54320/MobilityDatabaseTest
export LIQUIBASE_COMMAND_CHANGELOG_FILE=changelog.xml
liquibase update
export LIQUIBASE_COMMAND_URL=jdbc:postgresql://localhost:54320/MobilityDatabaseUsersTest
export LIQUIBASE_COMMAND_CHANGELOG_FILE=changelog_user.xml
liquibase update
- name: Generate API stubs and DB models
run: |
scripts/setup-openapi-generator.sh
scripts/api-gen.sh
scripts/api-user-service-gen.sh
scripts/api-operations-gen.sh
export USE_TEST_DB=true
scripts/db-gen.sh
scripts/db-gen-user.sh
- name: Build operations API function zip
if: ${{ github.event.inputs.deploy_operations_api != 'false' }}
run: scripts/function-python-build.sh --function_name operations_api
- name: Upload generated feeds_gen
uses: actions/upload-artifact@v4
with:
name: feeds_gen
path: api/src/feeds_gen/
- name: Upload generated database_gen
uses: actions/upload-artifact@v4
with:
name: database_gen
path: api/src/shared/database_gen/
- name: Upload generated users_database_gen
uses: actions/upload-artifact@v4
with:
name: users_database_gen
path: api/src/shared/users_database_gen/
- name: Upload generated user_service_gen
uses: actions/upload-artifact@v4
with:
name: user_service_gen
path: api/src/user_service_gen/
- name: Upload operations API build
if: ${{ github.event.inputs.deploy_operations_api != 'false' }}
uses: actions/upload-artifact@v4
with:
name: operations_api_build
path: functions-python/operations_api/.dist/
include-hidden-files: true
# ── Feeds API: build Docker image and deploy to developer Cloud Run ─────────
deploy-feeds-api:
if: ${{ github.event.inputs.deploy_feeds_api != 'false' }}
runs-on: ubuntu-latest
permissions: write-all
needs: [generate-and-build]
outputs:
service_name: ${{ steps.names.outputs.service_name }}
service_url: ${{ steps.get_url.outputs.url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set service name and image tag
id: names
run: |
echo "service_name=mobility-feed-api-developer${{ github.event.inputs.name_suffix || 'x' }}" >> "$GITHUB_OUTPUT"
echo "image_tag=developer-$(date +%s)-${GITHUB_SHA::8}" >> "$GITHUB_OUTPUT"
- name: Download generated artifacts
uses: actions/download-artifact@v4
with:
name: feeds_gen
path: api/src/feeds_gen/
- uses: actions/download-artifact@v4
with:
name: database_gen
path: api/src/shared/database_gen/
- uses: actions/download-artifact@v4
with:
name: users_database_gen
path: api/src/shared/users_database_gen/
- uses: actions/download-artifact@v4
with:
name: user_service_gen
path: api/src/user_service_gen/
- name: Create local .env (required by Dockerfile)
run: |
echo "ENVIRONMENT=dev" > config/.env.local
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.DEV_GCP_MOBILITY_FEEDS_SA_KEY }}
- name: Login to Artifact Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGION }}-docker.pkg.dev
username: _json_key_base64
password: ${{ secrets.DEV_GCP_MOBILITY_FEEDS_SA_KEY }}
- name: Build & Push Docker image
run: |
scripts/docker-build-push.sh \
-project_id "${{ env.PROJECT_ID }}" \
-repo_name "${{ env.ARTIFACT_REPO }}" \
-service "${{ steps.names.outputs.service_name }}" \
-region "${{ env.REGION }}" \
-version "${{ steps.names.outputs.image_tag }}"
- name: GCloud Setup
uses: google-github-actions/setup-gcloud@v2
- name: Deploy to developer Cloud Run
# Creates/updates ONLY developer-feed-api-<suffix> — shared dev Cloud Run is untouched.
# Secret names follow the same DEV_<KEY> pattern used by Terraform (infra/feed-api/main.tf).
run: |
IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.ARTIFACT_REPO }}/${{ steps.names.outputs.service_name }}:${{ steps.names.outputs.image_tag }}"
gcloud run deploy "${{ steps.names.outputs.service_name }}" \
--image "$IMAGE" \
--platform managed \
--region "${{ env.REGION }}" \
--allow-unauthenticated \
--project "${{ env.PROJECT_ID }}" \
--service-account "${{ vars.DEV_MOBILITY_FEEDS_DEPLOYER_SERVICE_ACCOUNT }}" \
--update-secrets "FEEDS_DATABASE_URL=DEV_FEEDS_DATABASE_URL:latest,USERS_DATABASE_URL=DEV_USERS_DATABASE_URL:latest,S2S_JWT_SECRET=DEV_S2S_JWT_SECRET:latest" \
--set-env-vars "PROJECT_ID=${{ env.PROJECT_ID }}" \
--vpc-connector "projects/${{ env.VPC_CONNECTOR_PROJECT }}/locations/${{ env.REGION }}/connectors/${{ env.VPC_CONNECTOR }}" \
--vpc-egress all
- name: Get service URL
id: get_url
run: |
URL=$(gcloud run services describe "${{ steps.names.outputs.service_name }}" \
--platform managed \
--region "${{ env.REGION }}" \
--project "${{ env.PROJECT_ID }}" \
--format 'value(status.url)')
echo "url=${URL}" >> "$GITHUB_OUTPUT"
# ── Operations API: build zip and deploy to developer Cloud Function ────────
deploy-operations-api:
if: ${{ github.event.inputs.deploy_operations_api != 'false' }}
runs-on: ubuntu-latest
permissions: write-all
needs: [generate-and-build]
outputs:
function_name: ${{ steps.names.outputs.function_name }}
function_url: ${{ steps.get_url.outputs.url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set function name
id: names
run: |
echo "function_name=operations-api-developer-${{ github.event.inputs.name_suffix || 'dev' }}" >> "$GITHUB_OUTPUT"
- name: Download operations API build
uses: actions/download-artifact@v4
with:
name: operations_api_build
path: functions-python/operations_api/.dist/
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.DEV_GCP_MOBILITY_FEEDS_SA_KEY }}
- name: Load OPERATIONS_OAUTH2_CLIENT_ID from 1Password
uses: 1password/load-secrets-action@v2
with:
export-env: true
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
OPERATIONS_OAUTH2_CLIENT_ID: "op://rbiv7rvkkrsdlpcrz3bmv7nmcu/GCP_RETOOL_OAUTH2_CREDS/username"
- name: GCloud Setup
uses: google-github-actions/setup-gcloud@v2
- name: Deploy to developer Cloud Function
# Creates/updates ONLY operations-api-developer-<suffix> — shared operations-api is untouched.
# Secret names follow the same DEV_<KEY> pattern used by Terraform (infra/functions-python/main.tf).
run: |
gcloud functions deploy "${{ steps.names.outputs.function_name }}" \
--gen2 \
--project "${{ env.PROJECT_ID }}" \
--region "${{ env.REGION }}" \
--runtime python311 \
--entry-point main \
--source functions-python/operations_api/.dist/build \
--service-account "${{ vars.DEV_MOBILITY_FEEDS_DEPLOYER_SERVICE_ACCOUNT }}" \
--memory 1Gi \
--timeout 540s \
--max-instances 10 \
--min-instances 0 \
--concurrency 100 \
--cpu 1 \
--ingress-settings all \
--trigger-http \
--allow-unauthenticated \
--set-env-vars "ENVIRONMENT=dev,PROJECT_ID=${{ env.PROJECT_ID }},GCP_REGION=${{ env.REGION }},GOOGLE_CLIENT_ID=${OPERATIONS_OAUTH2_CLIENT_ID}" \
--set-secrets "FEEDS_DATABASE_URL=DEV_FEEDS_DATABASE_URL:latest,USERS_DATABASE_URL=DEV_USERS_DATABASE_URL:latest"
- name: Get function URL
id: get_url
run: |
URL=$(gcloud functions describe "${{ steps.names.outputs.function_name }}" \
--gen2 \
--region "${{ env.REGION }}" \
--project "${{ env.PROJECT_ID }}" \
--format 'value(serviceConfig.uri)')
echo "url=${URL}" >> "$GITHUB_OUTPUT"
# ── Summary ───────────────────────────────────────────────────────────────
summary:
runs-on: ubuntu-latest
needs: [deploy-feeds-api, deploy-operations-api]
if: always()
steps:
- name: Write job summary
run: |
echo "## 🚀 Developer API deployment" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "| Service | Name | URL |" >> "$GITHUB_STEP_SUMMARY"
echo "|---------|------|-----|" >> "$GITHUB_STEP_SUMMARY"
FEEDS_URL="${{ needs.deploy-feeds-api.outputs.service_url }}"
FEEDS_NAME="${{ needs.deploy-feeds-api.outputs.service_name }}"
if [ -n "$FEEDS_URL" ]; then
echo "| Feeds API | \`${FEEDS_NAME}\` | [${FEEDS_URL}/docs/](${FEEDS_URL}/docs/) |" >> "$GITHUB_STEP_SUMMARY"
fi
OPS_URL="${{ needs.deploy-operations-api.outputs.function_url }}"
OPS_NAME="${{ needs.deploy-operations-api.outputs.function_name }}"
if [ -n "$OPS_URL" ]; then
echo "| Operations API | \`${OPS_NAME}\` | [${OPS_URL}](${OPS_URL}) |" >> "$GITHUB_STEP_SUMMARY"
fi
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "> ⚠️ These are developer services sharing the **dev databases** (read/write)." >> "$GITHUB_STEP_SUMMARY"
echo "> No shared Cloud Run, Terraform state, load balancer, or IAM was modified." >> "$GITHUB_STEP_SUMMARY"