Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
493b864
add user flag implementation
davidgamez Jun 5, 2026
0868bf0
fix feature falg import and query operations
davidgamez Jun 5, 2026
bc13799
add feature flag default and value types implementation
davidgamez Jun 8, 2026
1322ec8
fix fature flag value response
davidgamez Jun 9, 2026
b216317
fix lint
davidgamez Jun 9, 2026
579c5f7
fix sql permissions
davidgamez Jun 9, 2026
2cde18a
fix sql access
davidgamez Jun 10, 2026
85bd02a
change parameter name
davidgamez Jun 10, 2026
fac1525
add liquibase parameter
davidgamez Jun 10, 2026
3546ed2
revert permissions
davidgamez Jun 10, 2026
faa83be
add user env for apis
davidgamez Jun 10, 2026
aeaf5ee
testinmg wf
davidgamez Jun 10, 2026
66534d2
testinmg wf
davidgamez Jun 10, 2026
fdea16e
fix build
davidgamez Jun 10, 2026
01eab4d
fix build
davidgamez Jun 10, 2026
f9fd39f
fix build
davidgamez Jun 10, 2026
91d3ba7
fix build
davidgamez Jun 10, 2026
e3f6373
fix build
davidgamez Jun 10, 2026
cdfe272
fix build
davidgamez Jun 10, 2026
84b51ef
fix build
davidgamez Jun 10, 2026
49879cb
fix dev creds
davidgamez Jun 10, 2026
0eab2eb
rename personal to developer
davidgamez Jun 10, 2026
5f62f9d
Merge branch 'main' into user_feature_flag
davidgamez Jun 11, 2026
450aa85
fix users db
davidgamez Jun 11, 2026
b4d4b72
removing dev cred
davidgamez Jun 11, 2026
d9818cb
removing dev cred
davidgamez Jun 11, 2026
c2b9222
add feat delete and feature defaults to all users
davidgamez Jun 11, 2026
ebb1d09
fix default value
davidgamez Jun 11, 2026
9d420bb
fix async issue
davidgamez Jun 11, 2026
bd49089
add total limit and offset for pagination
davidgamez Jun 12, 2026
591b2db
change patch to put in feature flag endpoint
davidgamez Jun 15, 2026
8adb808
verify proper value type
davidgamez Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
341 changes: 341 additions & 0 deletions .github/workflows/api-deploy-developer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,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"
Loading
Loading