feat(ci): add database migrations step to tagged staging deployments

Adds a new 'migrations' job that runs after deploy to automatically
push schema changes to the database. Features:

- Runs db:push after container deployment
- Retry logic with exponential backoff (3 attempts)
- 2-minute timeout per attempt
- Skipped for web-only projects (manacore)
- Reports migration status in deployment summary

This ensures schema changes are automatically applied when deploying
new versions via tags (e.g., todo-staging-v1.0.0).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Wuesteon 2025-12-09 16:40:46 +01:00
parent f440ca2a8d
commit 79b4bb07ed

View file

@ -419,17 +419,118 @@ jobs:
echo "- **Deployed by**: ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY echo "- **Deployed by**: ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "- **Timestamp**: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY echo "- **Timestamp**: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
# Run database migrations after deploy
migrations:
name: Database Migrations
runs-on: ubuntu-latest
needs: [parse-deployment, deploy]
# Only run for projects with backends (not manacore which is web-only)
if: needs.parse-deployment.outputs.project != 'manacore'
steps:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.STAGING_SSH_KEY }}
- name: Add staging server to known hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H ${{ secrets.STAGING_HOST }} >> ~/.ssh/known_hosts
- name: Run database migrations
env:
PROJECT: ${{ needs.parse-deployment.outputs.project }}
run: |
# Determine service name based on project
case "$PROJECT" in
mana-core-auth)
SERVICE_NAME="mana-core-auth"
;;
*)
SERVICE_NAME="${PROJECT}-backend"
;;
esac
echo "Running database migrations for $SERVICE_NAME..."
ssh ${{ secrets.STAGING_USER }}@${{ secrets.STAGING_HOST }} << EOF
cd ~/manacore-staging
echo "=== Database Migration for $SERVICE_NAME ==="
# Check if service is running
if ! docker compose ps $SERVICE_NAME --format '{{.State}}' 2>/dev/null | grep -q "running"; then
echo "⚠️ Service $SERVICE_NAME is not running, skipping migrations"
exit 0
fi
# Migration function with retry logic
run_db_push() {
local service=\$1
local max_attempts=3
local timeout=120 # 2 minutes
local attempt=1
while [ \$attempt -le \$max_attempts ]; do
echo "[\$service] db:push attempt \$attempt/\$max_attempts..."
# Try db:push with timeout (staging uses push, not migrate)
if timeout \$timeout docker compose exec -T \$service pnpm run db:push 2>&1; then
echo "✅ [\$service] Database schema pushed successfully"
return 0
else
exit_code=\$?
if [ \$exit_code -eq 124 ]; then
echo "⚠️ [\$service] db:push timeout after \${timeout}s"
else
echo "⚠️ [\$service] db:push failed with exit code \$exit_code"
fi
attempt=\$((attempt + 1))
if [ \$attempt -le \$max_attempts ]; then
wait_time=\$((5 * attempt)) # Backoff: 5s, 10s, 15s
echo " Waiting \${wait_time}s before retry..."
sleep \$wait_time
fi
fi
done
echo "❌ [\$service] db:push failed after \$max_attempts attempts"
return 1
}
# Run db:push for the service
run_db_push $SERVICE_NAME || {
echo "❌ Database migration failed for $SERVICE_NAME"
echo "⚠️ You may need to run migrations manually:"
echo " ssh deploy@\${{ secrets.STAGING_HOST }} 'cd ~/manacore-staging && docker compose exec -T $SERVICE_NAME pnpm run db:push'"
exit 1
}
echo ""
echo "✅ Database migrations completed for $SERVICE_NAME"
EOF
- name: Migration summary
if: always()
run: |
echo "## Database Migrations" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Project**: ${{ needs.parse-deployment.outputs.project }}" >> $GITHUB_STEP_SUMMARY
echo "- **Status**: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
# Notify on completion # Notify on completion
notify: notify:
name: Deployment Complete name: Deployment Complete
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [parse-deployment, build, deploy] needs: [parse-deployment, build, deploy, migrations]
if: always() if: always()
steps: steps:
- name: Deployment notification - name: Deployment notification
run: | run: |
BUILD_STATUS="${{ needs.build.result }}" BUILD_STATUS="${{ needs.build.result }}"
DEPLOY_STATUS="${{ needs.deploy.result }}" DEPLOY_STATUS="${{ needs.deploy.result }}"
MIGRATION_STATUS="${{ needs.migrations.result }}"
PROJECT="${{ needs.parse-deployment.outputs.project }}" PROJECT="${{ needs.parse-deployment.outputs.project }}"
VERSION="${{ needs.parse-deployment.outputs.version }}" VERSION="${{ needs.parse-deployment.outputs.version }}"
@ -439,13 +540,21 @@ jobs:
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Build | $BUILD_STATUS |" >> $GITHUB_STEP_SUMMARY echo "| Build | $BUILD_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "| Deploy | $DEPLOY_STATUS |" >> $GITHUB_STEP_SUMMARY echo "| Deploy | $DEPLOY_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "| Migrations | $MIGRATION_STATUS |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Project**: $PROJECT" >> $GITHUB_STEP_SUMMARY echo "- **Project**: $PROJECT" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: $VERSION" >> $GITHUB_STEP_SUMMARY echo "- **Version**: $VERSION" >> $GITHUB_STEP_SUMMARY
# Check all stages (migrations can be skipped for web-only projects)
if [ "$BUILD_STATUS" == "success" ] && [ "$DEPLOY_STATUS" == "success" ]; then if [ "$BUILD_STATUS" == "success" ] && [ "$DEPLOY_STATUS" == "success" ]; then
echo "" >> $GITHUB_STEP_SUMMARY if [ "$MIGRATION_STATUS" == "success" ] || [ "$MIGRATION_STATUS" == "skipped" ]; then
echo "All apps deployed successfully to staging" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "All stages completed successfully" >> $GITHUB_STEP_SUMMARY
else
echo "" >> $GITHUB_STEP_SUMMARY
echo "⚠️ Migrations failed - database may need manual update" >> $GITHUB_STEP_SUMMARY
exit 1
fi
else else
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "Some deployments failed - check individual job logs" >> $GITHUB_STEP_SUMMARY echo "Some deployments failed - check individual job logs" >> $GITHUB_STEP_SUMMARY