Changeset 0.21.1.1 (#87)

This commit is contained in:
2026-03-01 16:40:26 +00:00
parent 70aa78e486
commit 09c7281552
20 changed files with 853 additions and 102 deletions

View File

@@ -394,7 +394,7 @@ jobs:
# ── Determine environment ──────────────────
- name: Determine environment
id: env
id: setup
run: |
# All environments share one host: switchboard.DOMAIN
# Environments are separated by path prefix (BASE_PATH)
@@ -472,20 +472,20 @@ jobs:
PGPASSWORD: ${{ secrets.POSTGRES_ADMIN_PASSWORD }}
APP_USER: ${{ secrets.POSTGRES_USER }}
APP_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
DB_NAME: ${{ steps.env.outputs.DB_NAME }}
DB_NAME: ${{ steps.setup.outputs.DB_NAME }}
run: |
chmod +x scripts/db-bootstrap.sh
scripts/db-bootstrap.sh
# ── Dev: Upgrade Test (dev only) ───────────
- name: "Dev: test migration upgrade"
if: steps.env.outputs.DB_WIPE == 'true'
if: steps.setup.outputs.DB_WIPE == 'true'
env:
PGHOST: ${{ env.POSTGRES_HOST }}
PGPORT: ${{ env.POSTGRES_PORT }}
PGUSER: ${{ secrets.POSTGRES_USER }}
PGPASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
PGDATABASE: ${{ steps.env.outputs.DB_NAME }}
PGDATABASE: ${{ steps.setup.outputs.DB_NAME }}
run: |
echo "━━━ Upgrade test: applying migrations to existing dev DB ━━━"
@@ -531,28 +531,28 @@ jobs:
# ── Dev: Validate Schema ───────────────────
- name: "Dev: validate schema"
if: steps.env.outputs.DB_WIPE == 'true'
if: steps.setup.outputs.DB_WIPE == 'true'
env:
PGHOST: ${{ env.POSTGRES_HOST }}
PGPORT: ${{ env.POSTGRES_PORT }}
PGUSER: ${{ secrets.POSTGRES_USER }}
PGPASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
PGDATABASE: ${{ steps.env.outputs.DB_NAME }}
PGDATABASE: ${{ steps.setup.outputs.DB_NAME }}
run: |
chmod +x scripts/db-validate.sh
scripts/db-validate.sh
# ── Dev Wipe (fresh install test) ──────────
- name: "Dev: wipe for fresh install test"
if: steps.env.outputs.DB_WIPE == 'true'
if: steps.setup.outputs.DB_WIPE == 'true'
env:
PGHOST: ${{ env.POSTGRES_HOST }}
PGPORT: ${{ env.POSTGRES_PORT }}
PGUSER: ${{ secrets.POSTGRES_USER }}
PGPASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
PGDATABASE: ${{ steps.env.outputs.DB_NAME }}
PGDATABASE: ${{ steps.setup.outputs.DB_NAME }}
run: |
DB="${{ steps.env.outputs.DB_NAME }}"
DB="${{ steps.setup.outputs.DB_NAME }}"
if [[ "${DB}" != *_dev ]]; then
echo "❌ REFUSING to wipe '${DB}' — only *_dev databases can be wiped"
@@ -575,46 +575,46 @@ jobs:
- name: Build backend image
run: |
docker build -f server/Dockerfile \
-t ${BE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }} \
-t ${BE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} \
.
# ── Build Frontend Image ─────────────────────
- name: Build frontend image
run: |
docker build -f Dockerfile.frontend \
-t ${FE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }} \
-t ${FE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} \
.
# ── Tag release versions ─────────────────────
- name: Tag release versions
if: steps.env.outputs.EXTRA_TAG != ''
if: steps.setup.outputs.EXTRA_TAG != ''
run: |
docker tag ${BE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }} ${BE_IMAGE}:${{ steps.env.outputs.EXTRA_TAG }}
docker tag ${FE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }} ${FE_IMAGE}:${{ steps.env.outputs.EXTRA_TAG }}
docker tag ${BE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} ${BE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
docker tag ${FE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} ${FE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
# ── Push to Internal Registry ────────────────
- name: Push images
run: |
docker push ${BE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }}
docker push ${FE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }}
if [[ -n "${{ steps.env.outputs.EXTRA_TAG }}" ]]; then
docker push ${BE_IMAGE}:${{ steps.env.outputs.EXTRA_TAG }}
docker push ${FE_IMAGE}:${{ steps.env.outputs.EXTRA_TAG }}
docker push ${BE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }}
docker push ${FE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }}
if [[ -n "${{ steps.setup.outputs.EXTRA_TAG }}" ]]; then
docker push ${BE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
docker push ${FE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
fi
# ── Build + Push Unified to Docker Hub (release only) ──
- name: Build and push unified image
if: steps.env.outputs.is_release == 'true'
if: steps.setup.outputs.is_release == 'true'
run: |
docker build -f Dockerfile \
-t ${DOCKERHUB_IMAGE}:latest \
-t ${DOCKERHUB_IMAGE}:${{ steps.env.outputs.EXTRA_TAG }} \
-t ${DOCKERHUB_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }} \
.
if [[ -n "${{ secrets.DOCKERHUB_TOKEN }}" ]]; then
echo "${{ secrets.DOCKERHUB_TOKEN }}" | \
docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
docker push ${DOCKERHUB_IMAGE}:latest
docker push ${DOCKERHUB_IMAGE}:${{ steps.env.outputs.EXTRA_TAG }}
docker push ${DOCKERHUB_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
else
echo "⚠ Docker Hub credentials not configured, skipping push"
fi
@@ -679,23 +679,23 @@ jobs:
- name: Render and apply manifests
env:
ENVIRONMENT: ${{ steps.env.outputs.ENVIRONMENT }}
GIN_MODE: ${{ steps.env.outputs.GIN_MODE }}
IMAGE_TAG: ${{ steps.env.outputs.IMAGE_TAG }}
DEPLOY_SUFFIX: ${{ steps.env.outputs.DEPLOY_SUFFIX }}
DEPLOY_HOST: ${{ steps.env.outputs.DEPLOY_HOST }}
BASE_PATH: ${{ steps.env.outputs.BASE_PATH }}
DB_NAME: ${{ steps.env.outputs.DB_NAME }}
FE_REPLICAS: ${{ steps.env.outputs.FE_REPLICAS }}
BE_REPLICAS: ${{ steps.env.outputs.BE_REPLICAS }}
FE_MEMORY_REQUEST: ${{ steps.env.outputs.FE_MEMORY_REQUEST }}
FE_MEMORY_LIMIT: ${{ steps.env.outputs.FE_MEMORY_LIMIT }}
FE_CPU_REQUEST: ${{ steps.env.outputs.FE_CPU_REQUEST }}
FE_CPU_LIMIT: ${{ steps.env.outputs.FE_CPU_LIMIT }}
BE_MEMORY_REQUEST: ${{ steps.env.outputs.BE_MEMORY_REQUEST }}
BE_MEMORY_LIMIT: ${{ steps.env.outputs.BE_MEMORY_LIMIT }}
BE_CPU_REQUEST: ${{ steps.env.outputs.BE_CPU_REQUEST }}
BE_CPU_LIMIT: ${{ steps.env.outputs.BE_CPU_LIMIT }}
ENVIRONMENT: ${{ steps.setup.outputs.ENVIRONMENT }}
GIN_MODE: ${{ steps.setup.outputs.GIN_MODE }}
IMAGE_TAG: ${{ steps.setup.outputs.IMAGE_TAG }}
DEPLOY_SUFFIX: ${{ steps.setup.outputs.DEPLOY_SUFFIX }}
DEPLOY_HOST: ${{ steps.setup.outputs.DEPLOY_HOST }}
BASE_PATH: ${{ steps.setup.outputs.BASE_PATH }}
DB_NAME: ${{ steps.setup.outputs.DB_NAME }}
FE_REPLICAS: ${{ steps.setup.outputs.FE_REPLICAS }}
BE_REPLICAS: ${{ steps.setup.outputs.BE_REPLICAS }}
FE_MEMORY_REQUEST: ${{ steps.setup.outputs.FE_MEMORY_REQUEST }}
FE_MEMORY_LIMIT: ${{ steps.setup.outputs.FE_MEMORY_LIMIT }}
FE_CPU_REQUEST: ${{ steps.setup.outputs.FE_CPU_REQUEST }}
FE_CPU_LIMIT: ${{ steps.setup.outputs.FE_CPU_LIMIT }}
BE_MEMORY_REQUEST: ${{ steps.setup.outputs.BE_MEMORY_REQUEST }}
BE_MEMORY_LIMIT: ${{ steps.setup.outputs.BE_MEMORY_LIMIT }}
BE_CPU_REQUEST: ${{ steps.setup.outputs.BE_CPU_REQUEST }}
BE_CPU_LIMIT: ${{ steps.setup.outputs.BE_CPU_LIMIT }}
# Storage (v0.12.0+)
STORAGE_CLASS: ${{ vars.STORAGE_CLASS }}
STORAGE_SIZE: ${{ vars.STORAGE_SIZE || '10Gi' }}
@@ -727,8 +727,8 @@ jobs:
- name: Rollout and verify
env:
SUFFIX: ${{ steps.env.outputs.DEPLOY_SUFFIX }}
ENV: ${{ steps.env.outputs.ENVIRONMENT }}
SUFFIX: ${{ steps.setup.outputs.DEPLOY_SUFFIX }}
ENV: ${{ steps.setup.outputs.ENVIRONMENT }}
run: |
kubectl rollout restart deployment/switchboard-be${SUFFIX} -n ${NAMESPACE}
kubectl rollout restart deployment/switchboard-fe${SUFFIX} -n ${NAMESPACE}
@@ -753,36 +753,46 @@ jobs:
# ── Post-deploy: verify schema ─────────────
- name: Verify schema migration
env:
EXPECTED_DB: ${{ steps.setup.outputs.DB_NAME }}
run: |
sleep 5
HOST="${{ steps.env.outputs.DEPLOY_HOST }}"
BP="${{ steps.env.outputs.BASE_PATH }}"
HEALTH=$(curl -sf "https://${HOST}${BP}/api/v1/health" 2>/dev/null || echo "unreachable")
HOST="${{ steps.setup.outputs.DEPLOY_HOST }}"
BP="${{ steps.setup.outputs.BASE_PATH }}"
HEALTH=$(curl -sf "https://${HOST}${BP}/health" 2>/dev/null || echo "unreachable")
echo "Health: ${HEALTH}"
SCHEMA=$(echo "${HEALTH}" | grep -o '"schema_version":"[^"]*"' | cut -d'"' -f4 || true)
DB_OK=$(echo "${HEALTH}" | grep -o '"database":true' || true)
ACTUAL_DB=$(echo "${HEALTH}" | grep -o '"database_name":"[^"]*"' | cut -d'"' -f4 || true)
if [[ -n "${SCHEMA}" ]] && [[ -n "${DB_OK}" ]]; then
echo "✅ Schema: ${SCHEMA} | DB: connected"
echo "✅ Schema: ${SCHEMA} | DB: ${ACTUAL_DB}"
else
echo "⚠ Could not verify schema (backend may still be starting)"
echo " Response: ${HEALTH:0:200}"
fi
# Verify the backend connected to the correct database
if [[ -n "${ACTUAL_DB}" ]] && [[ "${ACTUAL_DB}" != "${EXPECTED_DB}" ]]; then
echo "❌ DATABASE MISMATCH: expected=${EXPECTED_DB} actual=${ACTUAL_DB}"
echo " The backend is connected to the WRONG database!"
exit 1
fi
- name: Summary
run: |
HOST="${{ steps.env.outputs.DEPLOY_HOST }}"
BP="${{ steps.env.outputs.BASE_PATH }}"
echo "## ✅ Deployed to ${{ steps.env.outputs.env_label }}" >> $GITHUB_STEP_SUMMARY
HOST="${{ steps.setup.outputs.DEPLOY_HOST }}"
BP="${{ steps.setup.outputs.BASE_PATH }}"
echo "## ✅ Deployed to ${{ steps.setup.outputs.env_label }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| | |" >> $GITHUB_STEP_SUMMARY
echo "|---|---|" >> $GITHUB_STEP_SUMMARY
echo "| **URL** | https://${HOST}${BP}/ |" >> $GITHUB_STEP_SUMMARY
echo "| **Backend** | \`${BE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Frontend** | \`${FE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Database** | \`${{ steps.env.outputs.DB_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **DB Wipe** | ${{ steps.env.outputs.DB_WIPE }} |" >> $GITHUB_STEP_SUMMARY
echo "| **Backend** | \`${BE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Frontend** | \`${FE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Database** | \`${{ steps.setup.outputs.DB_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **DB Wipe** | ${{ steps.setup.outputs.DB_WIPE }} |" >> $GITHUB_STEP_SUMMARY
if [[ -n "${{ vars.STORAGE_CLASS }}" ]]; then
if [[ "${{ vars.STORAGE_BACKEND }}" == "s3" ]]; then
echo "| **Storage** | S3 (bucket: ${{ vars.S3_BUCKET }}, PVC scratch: ${{ vars.STORAGE_CLASS }}) |" >> $GITHUB_STEP_SUMMARY
@@ -792,6 +802,6 @@ jobs:
else
echo "| **Storage** | Disabled (STORAGE_CLASS not set) |" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ steps.env.outputs.is_release }}" == "true" ]]; then
echo "| **Docker Hub** | \`${DOCKERHUB_IMAGE}:${{ steps.env.outputs.EXTRA_TAG }}\` (unified) |" >> $GITHUB_STEP_SUMMARY
if [[ "${{ steps.setup.outputs.is_release }}" == "true" ]]; then
echo "| **Docker Hub** | \`${DOCKERHUB_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}\` (unified) |" >> $GITHUB_STEP_SUMMARY
fi