mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 21:14:02 +00:00
Update GitHub Actions workflows to rely on repository variables and simplify build/deploy logic. cd.yml: switch secret/project lookups to vars, adjust workflow_run detection for auto-deploy, remove derived secret outputs, resolve Artifact Registry image tags from the triggering SHA, and use vars for Google Cloud auth and project references. ci.yml: add dev to PR branches, condense the quality matrix commands, rework the images job to authenticate and push only on branch pushes while doing build-only on PRs (with proper cache usage), add id-token permission, and introduce a final CI gate job that aggregates job results to block CD when CI fails. Also includes minor formatting and whitespace cleanups.
242 lines
8.3 KiB
YAML
242 lines
8.3 KiB
YAML
name: CD
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows:
|
|
- CI
|
|
types:
|
|
- completed
|
|
branches:
|
|
- main
|
|
- dev
|
|
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:
|
|
contents: read
|
|
id-token: write
|
|
|
|
concurrency:
|
|
group: cd-${{ github.event_name == 'workflow_dispatch' && inputs.environment || github.ref_name }}
|
|
cancel-in-progress: false
|
|
|
|
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 }}
|
|
ref: ${{ steps.detect.outputs.ref }}
|
|
|
|
steps:
|
|
- name: Determine target environment
|
|
id: detect
|
|
run: |
|
|
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
target_env="${{ inputs.environment }}"
|
|
ref="${{ inputs.ref }}"
|
|
else
|
|
if [[ "${{ github.event.workflow_run.head_branch }}" == "main" ]]; then
|
|
target_env="prod"
|
|
else
|
|
target_env="dev"
|
|
fi
|
|
ref="${{ github.event.workflow_run.head_sha }}"
|
|
fi
|
|
|
|
if [[ "$target_env" == "prod" ]]; then
|
|
github_environment="Production"
|
|
db_schema="public"
|
|
service_suffix="prod"
|
|
else
|
|
github_environment="Development"
|
|
db_schema="test"
|
|
service_suffix="dev"
|
|
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 "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:
|
|
name: Check deploy prerequisites
|
|
runs-on: ubuntu-latest
|
|
needs: detect-environment
|
|
environment: ${{ needs.detect-environment.outputs.github_environment }}
|
|
outputs:
|
|
eligible_event: ${{ steps.check.outputs.eligible_event }}
|
|
secrets_ok: ${{ steps.check.outputs.secrets_ok }}
|
|
db_secret_ok: ${{ steps.check.outputs.db_secret_ok }}
|
|
|
|
steps:
|
|
- name: Evaluate trigger and required secrets
|
|
id: check
|
|
env:
|
|
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
|
|
GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
|
GCP_SERVICE_ACCOUNT: ${{ vars.GCP_SERVICE_ACCOUNT }}
|
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
run: |
|
|
eligible_event=false
|
|
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
eligible_event=true
|
|
elif [[ "${{ github.event_name }}" == "workflow_run" && "${{ github.event.workflow_run.conclusion }}" == "success" ]]; then
|
|
eligible_event=true
|
|
fi
|
|
|
|
vars_ok=false
|
|
if [[ -n "$GCP_PROJECT_ID" && -n "$GCP_WORKLOAD_IDENTITY_PROVIDER" && -n "$GCP_SERVICE_ACCOUNT" ]]; then
|
|
vars_ok=true
|
|
fi
|
|
|
|
db_secret_ok=false
|
|
if [[ -n "$DATABASE_URL" ]]; then
|
|
db_secret_ok=true
|
|
fi
|
|
|
|
echo "eligible_event=$eligible_event" >> "$GITHUB_OUTPUT"
|
|
echo "secrets_ok=$vars_ok" >> "$GITHUB_OUTPUT"
|
|
echo "db_secret_ok=$db_secret_ok" >> "$GITHUB_OUTPUT"
|
|
|
|
deploy:
|
|
name: Deploy Cloud Run
|
|
runs-on: ubuntu-latest
|
|
needs: [detect-environment, check-secrets]
|
|
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' }}
|
|
environment: ${{ needs.detect-environment.outputs.github_environment }}
|
|
env:
|
|
GCP_REGION: ${{ vars.GCP_REGION || 'europe-west1' }}
|
|
ARTIFACT_REPOSITORY: ${{ vars.ARTIFACT_REPOSITORY || 'household-bot' }}
|
|
SERVICE_SUFFIX: ${{ needs.detect-environment.outputs.service_suffix }}
|
|
DB_SCHEMA: ${{ needs.detect-environment.outputs.db_schema }}
|
|
BOT_SECRET_ID: ${{ vars.TELEGRAM_BOT_TOKEN_SECRET_ID }}
|
|
|
|
steps:
|
|
- name: Checkout deployment ref
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ needs.detect-environment.outputs.ref }}
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@v2
|
|
with:
|
|
bun-version-file: .bun-version
|
|
|
|
- name: Install dependencies
|
|
run: bun install --frozen-lockfile
|
|
|
|
- name: Authenticate to Google Cloud
|
|
uses: google-github-actions/auth@v2
|
|
with:
|
|
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
|
|
service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
|
|
|
|
- name: Run database migrations
|
|
env:
|
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
DB_SCHEMA: ${{ needs.detect-environment.outputs.db_schema }}
|
|
run: bun run db:migrate
|
|
|
|
- name: Setup gcloud
|
|
uses: google-github-actions/setup-gcloud@v2
|
|
|
|
- name: Resolve image tags
|
|
id: images
|
|
run: |
|
|
# For workflow_run, use the SHA from the triggering commit (which CI already built & pushed).
|
|
# For workflow_dispatch, the user-supplied ref may be a branch or tag name — resolve to SHA.
|
|
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
deploy_sha=$(git rev-parse HEAD)
|
|
else
|
|
deploy_sha="${{ github.event.workflow_run.head_sha }}"
|
|
fi
|
|
|
|
repo="${GCP_REGION}-docker.pkg.dev/${{ vars.GCP_PROJECT_ID }}/${ARTIFACT_REPOSITORY}"
|
|
echo "bot_image=${repo}/bot:${deploy_sha}" >> "$GITHUB_OUTPUT"
|
|
echo "mini_image=${repo}/miniapp:${deploy_sha}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Load Telegram bot token for command sync
|
|
id: telegram-token
|
|
run: |
|
|
set +e
|
|
token="$(gcloud secrets versions access latest \
|
|
--secret "${BOT_SECRET_ID}" \
|
|
--project "${{ vars.GCP_PROJECT_ID }}" 2>/dev/null)"
|
|
status=$?
|
|
set -e
|
|
|
|
if [[ $status -ne 0 || -z "$token" ]]; then
|
|
echo "available=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
echo "::add-mask::$token"
|
|
{
|
|
echo "available=true"
|
|
echo "token<<EOF"
|
|
echo "$token"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Deploy bot service
|
|
run: |
|
|
gcloud run deploy "household-${SERVICE_SUFFIX}-bot-api" \
|
|
--image "${{ steps.images.outputs.bot_image }}" \
|
|
--region "${GCP_REGION}" \
|
|
--project "${{ vars.GCP_PROJECT_ID }}" \
|
|
--set-env-vars "DB_SCHEMA=${DB_SCHEMA}" \
|
|
--allow-unauthenticated \
|
|
--quiet
|
|
|
|
- name: Deploy mini app service
|
|
run: |
|
|
gcloud run deploy "household-${SERVICE_SUFFIX}-mini-app" \
|
|
--image "${{ steps.images.outputs.mini_image }}" \
|
|
--region "${GCP_REGION}" \
|
|
--project "${{ vars.GCP_PROJECT_ID }}" \
|
|
--allow-unauthenticated \
|
|
--quiet
|
|
|
|
- name: Sync Telegram commands
|
|
if: ${{ steps.telegram-token.outputs.available == 'true' }}
|
|
env:
|
|
TELEGRAM_BOT_TOKEN: ${{ steps.telegram-token.outputs.token }}
|
|
run: bun run ops:telegram:commands set
|
|
|
|
- name: Set Telegram Webhook
|
|
if: ${{ steps.telegram-token.outputs.available == 'true' }}
|
|
env:
|
|
TELEGRAM_BOT_TOKEN: ${{ steps.telegram-token.outputs.token }}
|
|
run: |
|
|
SERVICE_URL=$(gcloud run services describe "household-${SERVICE_SUFFIX}-bot-api" \
|
|
--region "${GCP_REGION}" \
|
|
--project "${{ vars.GCP_PROJECT_ID }}" \
|
|
--format 'value(status.url)')
|
|
|
|
export TELEGRAM_WEBHOOK_URL="$SERVICE_URL/webhook/telegram"
|
|
bun run ops:telegram:webhook set
|