feat(cd): complete environment support for dev/prod deployments

- Add workflow_dispatch inputs for manual environment selection
- Add detect-environment job to centralize environment detection
- Support both auto-trigger (branch-based) and manual deployment
- Use environment-specific secrets (DATABASE_URL vs DATABASE_URL_TEST)
- Dynamic Cloud Run service names based on environment
- Update concurrency group to use environment for manual triggers
This commit is contained in:
2026-03-15 22:01:17 +04:00
parent 6b38e0898c
commit 1cff14662e

View File

@@ -10,21 +10,93 @@ on:
- main - main
- dev - dev
workflow_dispatch: workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
default: 'dev'
type: choice
options:
- dev
- prod
ref:
description: 'Git ref to deploy (branch, tag, or SHA)'
required: true
default: 'dev'
permissions: permissions:
contents: read contents: read
id-token: write id-token: write
concurrency: concurrency:
group: cd-${{ github.ref_name }} group: cd-${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
cancel-in-progress: false cancel-in-progress: false
jobs: jobs:
detect-environment:
name: Detect environment
runs-on: ubuntu-latest
outputs:
target_env: ${{ steps.detect.outputs.target_env }}
github_environment: ${{ steps.detect.outputs.github_environment }}
db_schema: ${{ steps.detect.outputs.db_schema }}
service_suffix: ${{ steps.detect.outputs.service_suffix }}
bot_secret_id: ${{ steps.detect.outputs.bot_secret_id }}
db_secret_name: ${{ steps.detect.outputs.db_secret_name }}
ref: ${{ steps.detect.outputs.ref }}
steps:
- name: Determine target environment
id: detect
run: |
# Determine environment from input (manual) or branch (auto)
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
target_env="${{ inputs.environment }}"
ref="${{ inputs.ref }}"
else
# Auto-detect from branch
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
target_env="prod"
else
target_env="dev"
fi
ref="${{ github.event.workflow_run.head_sha }}"
fi
# Set derived values
if [[ "$target_env" == "prod" ]]; then
github_environment="Production"
db_schema="public"
service_suffix="prod"
bot_secret_id="telegram-bot-token"
db_secret_name="DATABASE_URL"
else
github_environment="Development"
db_schema="test"
service_suffix="dev"
bot_secret_id="telegram-bot-token-test"
db_secret_name="DATABASE_URL_TEST"
fi
echo "target_env=$target_env" >> "$GITHUB_OUTPUT"
echo "github_environment=$github_environment" >> "$GITHUB_OUTPUT"
echo "db_schema=$db_schema" >> "$GITHUB_OUTPUT"
echo "service_suffix=$service_suffix" >> "$GITHUB_OUTPUT"
echo "bot_secret_id=$bot_secret_id" >> "$GITHUB_OUTPUT"
echo "db_secret_name=$db_secret_name" >> "$GITHUB_OUTPUT"
echo "ref=$ref" >> "$GITHUB_OUTPUT"
echo "Target environment: $target_env"
echo "GitHub Environment: $github_environment"
echo "DB Schema: $db_schema"
echo "Service Suffix: $service_suffix"
echo "Deploy ref: $ref"
check-secrets: check-secrets:
name: Check deploy prerequisites name: Check deploy prerequisites
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Select GitHub Environment based on branch needs: detect-environment
environment: ${{ github.ref == 'refs/heads/main' && 'Production' || 'Development' }} environment: ${{ needs.detect-environment.outputs.github_environment }}
outputs: outputs:
eligible_event: ${{ steps.check.outputs.eligible_event }} eligible_event: ${{ steps.check.outputs.eligible_event }}
secrets_ok: ${{ steps.check.outputs.secrets_ok }} secrets_ok: ${{ steps.check.outputs.secrets_ok }}
@@ -37,7 +109,7 @@ jobs:
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }} GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }}
DATABASE_URL: ${{ secrets.DATABASE_URL }} DATABASE_URL: ${{ secrets[needs.detect-environment.outputs.db_secret_name] }}
run: | run: |
eligible_event=false eligible_event=false
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
@@ -63,25 +135,22 @@ jobs:
deploy: deploy:
name: Deploy Cloud Run name: Deploy Cloud Run
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: check-secrets needs: [detect-environment, check-secrets]
timeout-minutes: 30 timeout-minutes: 30
if: ${{ needs.check-secrets.outputs.eligible_event == 'true' && needs.check-secrets.outputs.secrets_ok == 'true' && needs.check-secrets.outputs.db_secret_ok == 'true' }} if: ${{ needs.check-secrets.outputs.eligible_event == 'true' && needs.check-secrets.outputs.secrets_ok == 'true' && needs.check-secrets.outputs.db_secret_ok == 'true' }}
environment: ${{ github.ref == 'refs/heads/main' && 'Production' || 'Development' }} environment: ${{ needs.detect-environment.outputs.github_environment }}
env: env:
GCP_REGION: ${{ vars.GCP_REGION || 'europe-west1' }} GCP_REGION: ${{ vars.GCP_REGION || 'europe-west1' }}
ARTIFACT_REPOSITORY: ${{ vars.ARTIFACT_REPOSITORY || 'household-bot' }} ARTIFACT_REPOSITORY: ${{ vars.ARTIFACT_REPOSITORY || 'household-bot' }}
# Dynamic Service Names based on environment SERVICE_SUFFIX: ${{ needs.detect-environment.outputs.service_suffix }}
# Branch 'main' -> Environment 'prod' -> household-prod-* DB_SCHEMA: ${{ needs.detect-environment.outputs.db_schema }}
# Branch 'dev' -> Environment 'dev' -> household-dev-* BOT_SECRET_ID: ${{ needs.detect-environment.outputs.bot_secret_id }}
CLOUD_RUN_SERVICE_BOT: ${{ github.ref == 'refs/heads/main' && 'household-prod-bot-api' || 'household-dev-bot-api' }}
CLOUD_RUN_SERVICE_MINI: ${{ github.ref == 'refs/heads/main' && 'household-prod-mini-app' || 'household-dev-mini-app' }}
TELEGRAM_BOT_TOKEN_SECRET_ID: ${{ github.ref == 'refs/heads/main' && 'telegram-bot-token' || 'telegram-bot-token-test' }}
steps: steps:
- name: Checkout deployment ref - name: Checkout deployment ref
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }} ref: ${{ needs.detect-environment.outputs.ref }}
- name: Setup Bun - name: Setup Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
@@ -99,8 +168,8 @@ jobs:
- name: Run database migrations - name: Run database migrations
env: env:
DATABASE_URL: ${{ secrets.DATABASE_URL }} DATABASE_URL: ${{ secrets[needs.detect-environment.outputs.db_secret_name] }}
DB_SCHEMA: ${{ github.ref == 'refs/heads/main' && 'public' || 'test' }} DB_SCHEMA: ${{ needs.detect-environment.outputs.db_schema }}
run: bun run db:migrate run: bun run db:migrate
- name: Setup gcloud - name: Setup gcloud
@@ -111,7 +180,7 @@ jobs:
run: | run: |
set +e set +e
token="$(gcloud secrets versions access latest \ token="$(gcloud secrets versions access latest \
--secret "${TELEGRAM_BOT_TOKEN_SECRET_ID}" \ --secret "${BOT_SECRET_ID}" \
--project "${{ secrets.GCP_PROJECT_ID }}" 2>/dev/null)" --project "${{ secrets.GCP_PROJECT_ID }}" 2>/dev/null)"
status=$? status=$?
set -e set -e
@@ -154,17 +223,17 @@ jobs:
- name: Deploy bot service - name: Deploy bot service
run: | run: |
gcloud run deploy "${CLOUD_RUN_SERVICE_BOT}" \ gcloud run deploy "household-${SERVICE_SUFFIX}-bot-api" \
--image "${{ steps.images.outputs.bot_image }}" \ --image "${{ steps.images.outputs.bot_image }}" \
--region "${GCP_REGION}" \ --region "${GCP_REGION}" \
--project "${{ secrets.GCP_PROJECT_ID }}" \ --project "${{ secrets.GCP_PROJECT_ID }}" \
--set-env-vars "DB_SCHEMA=${{ github.ref == 'refs/heads/main' && 'public' || 'test' }}" \ --set-env-vars "DB_SCHEMA=${DB_SCHEMA}" \
--allow-unauthenticated \ --allow-unauthenticated \
--quiet --quiet
- name: Deploy mini app service - name: Deploy mini app service
run: | run: |
gcloud run deploy "${CLOUD_RUN_SERVICE_MINI}" \ gcloud run deploy "household-${SERVICE_SUFFIX}-mini-app" \
--image "${{ steps.images.outputs.mini_image }}" \ --image "${{ steps.images.outputs.mini_image }}" \
--region "${GCP_REGION}" \ --region "${GCP_REGION}" \
--project "${{ secrets.GCP_PROJECT_ID }}" \ --project "${{ secrets.GCP_PROJECT_ID }}" \
@@ -182,7 +251,7 @@ jobs:
env: env:
TELEGRAM_BOT_TOKEN: ${{ steps.telegram-token.outputs.token }} TELEGRAM_BOT_TOKEN: ${{ steps.telegram-token.outputs.token }}
run: | run: |
SERVICE_URL=$(gcloud run services describe "${CLOUD_RUN_SERVICE_BOT}" \ SERVICE_URL=$(gcloud run services describe "household-${SERVICE_SUFFIX}-bot-api" \
--region "${GCP_REGION}" \ --region "${GCP_REGION}" \
--project "${{ secrets.GCP_PROJECT_ID }}" \ --project "${{ secrets.GCP_PROJECT_ID }}" \
--format 'value(status.url)') --format 'value(status.url)')