Files
full-stack-fastapi/.gitea/workflows/deploy.yml
魏风 0879346d40
Some checks failed
Deploy to Production / deploy (push) Successful in 1m45s
Playwright Tests / test-playwright (push) Failing after 18s
Test Backend / test-backend (push) Failing after 12s
Test Docker Compose / test-docker-compose (push) Has been cancelled
Merge branch 'main' into bt to align Alembic with production DB
2026-05-11 10:47:08 +08:00

125 lines
5.6 KiB
YAML

name: Deploy to Production
on:
push:
branches:
- main
- bt
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
run: |
git clone "http://172.17.0.1:3000/${{ github.repository }}.git" .
git checkout "${{ github.sha }}"
- name: Create .env.production from secrets
run: |
cat > .env.production << 'ENVEOF'
DOMAIN=${{ secrets.DOMAIN }}
BACKEND_HOST=${{ secrets.BACKEND_HOST }}
FRONTEND_HOST=${{ secrets.FRONTEND_HOST }}
ENVIRONMENT=production
PROJECT_NAME=${{ secrets.PROJECT_NAME }}
BACKEND_CORS_ORIGINS=${{ secrets.BACKEND_CORS_ORIGINS }}
SECRET_KEY=${{ secrets.SECRET_KEY }}
FIRST_SUPERUSER=${{ secrets.FIRST_SUPERUSER }}
FIRST_SUPERUSER_PASSWORD=${{ secrets.FIRST_SUPERUSER_PASSWORD }}
SMTP_HOST=${{ secrets.SMTP_HOST }}
SMTP_USER=${{ secrets.SMTP_USER }}
SMTP_PASSWORD=${{ secrets.SMTP_PASSWORD }}
EMAILS_FROM_EMAIL=${{ secrets.EMAILS_FROM_EMAIL }}
SMTP_TLS=${{ secrets.SMTP_TLS }}
SMTP_SSL=${{ secrets.SMTP_SSL }}
SMTP_PORT=${{ secrets.SMTP_PORT }}
POSTGRES_SERVER=${{ secrets.POSTGRES_SERVER }}
POSTGRES_PORT=${{ secrets.POSTGRES_PORT }}
POSTGRES_DB=${{ secrets.POSTGRES_DB }}
POSTGRES_USER=${{ secrets.POSTGRES_USER }}
POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }}
SENTRY_DSN=${{ secrets.SENTRY_DSN }}
MQTT_HOST=${{ secrets.MQTT_HOST }}
MQTT_PORT=${{ secrets.MQTT_PORT }}
MQTT_USERNAME=${{ secrets.MQTT_USERNAME }}
MQTT_PASSWORD=${{ secrets.MQTT_PASSWORD }}
MQTT_TOPIC_PATTERN=${{ secrets.MQTT_TOPIC_PATTERN }}
MQTT_CLIENT_ID=${{ secrets.MQTT_CLIENT_ID }}
RAW_HOT_RETENTION_DAYS=${{ secrets.RAW_HOT_RETENTION_DAYS }}
RAW_ARCHIVE_BASE_DIR=${{ secrets.RAW_ARCHIVE_BASE_DIR }}
PARSER_BATCH_SIZE=${{ secrets.PARSER_BATCH_SIZE }}
PARSER_POLL_INTERVAL_MS=${{ secrets.PARSER_POLL_INTERVAL_MS }}
DOCKER_IMAGE_BACKEND=${{ secrets.DOCKER_IMAGE_BACKEND }}
DOCKER_IMAGE_FRONTEND=${{ secrets.DOCKER_IMAGE_FRONTEND }}
ENVEOF
# Fallback defaults if image name secrets are empty
sed -i 's/^DOCKER_IMAGE_BACKEND=$/DOCKER_IMAGE_BACKEND=backend/' .env.production
sed -i 's/^DOCKER_IMAGE_FRONTEND=$/DOCKER_IMAGE_FRONTEND=frontend/' .env.production
sed -i 's/^MQTT_HOST=$/MQTT_HOST=1Panel-emqx-Rniy/' .env.production
sed -i 's/^MQTT_PORT=$/MQTT_PORT=1883/' .env.production
sed -i 's/^MQTT_USERNAME=$/MQTT_USERNAME=weefnn/' .env.production
sed -i 's/^MQTT_PASSWORD=$/MQTT_PASSWORD=123456/' .env.production
sed -i 's%^MQTT_TOPIC_PATTERN=$%MQTT_TOPIC_PATTERN=terminal/+/raw%' .env.production
sed -i 's/^MQTT_CLIENT_ID=$/MQTT_CLIENT_ID=spatialhub-mqtt-ingestor/' .env.production
sed -i 's/^RAW_HOT_RETENTION_DAYS=$/RAW_HOT_RETENTION_DAYS=90/' .env.production
sed -i 's%^RAW_ARCHIVE_BASE_DIR=$%RAW_ARCHIVE_BASE_DIR=/data/archive/gnss%' .env.production
sed -i 's/^PARSER_BATCH_SIZE=$/PARSER_BATCH_SIZE=200/' .env.production
sed -i 's/^PARSER_POLL_INTERVAL_MS=$/PARSER_POLL_INTERVAL_MS=300/' .env.production
- name: Build Docker images
run: docker compose --env-file .env.production -f compose.prod.yml build
- name: Stop existing services
run: docker compose --env-file .env.production -f compose.prod.yml down --remove-orphans || true
- name: Start services
run: docker compose --env-file .env.production -f compose.prod.yml up -d
- name: Wait for backend health check
run: |
echo "Waiting for backend container health=healthy..."
for i in $(seq 1 30); do
status=$(docker inspect -f '{{.State.Health.Status}}' full-stack-fastapi-backend-1 2>/dev/null || echo "unknown")
if [ "$status" = "healthy" ]; then
echo "✅ Backend is healthy!"
exit 0
fi
echo "Attempt $i/30 - status=$status, waiting 10s..."
sleep 10
done
echo "❌ Backend health check failed after 300s"
docker compose --env-file .env.production -f compose.prod.yml logs backend
exit 1
- name: Verify frontend
run: |
if docker compose --env-file .env.production -f compose.prod.yml ps frontend --status running | grep -q frontend; then
echo "✅ Frontend is accessible!"
else
echo "❌ Frontend is not accessible"
docker compose --env-file .env.production -f compose.prod.yml logs frontend
exit 1
fi
- name: Verify mqtt workers
run: |
if docker compose --env-file .env.production -f compose.prod.yml ps mqtt-ingestor --status running | grep -q mqtt-ingestor; then
echo "✅ mqtt-ingestor is running!"
else
echo "❌ mqtt-ingestor is not running"
docker compose --env-file .env.production -f compose.prod.yml logs mqtt-ingestor
exit 1
fi
if docker compose --env-file .env.production -f compose.prod.yml ps mqtt-parser-worker --status running | grep -q mqtt-parser-worker; then
echo "✅ mqtt-parser-worker is running!"
else
echo "❌ mqtt-parser-worker is not running"
docker compose --env-file .env.production -f compose.prod.yml logs mqtt-parser-worker
exit 1
fi
- name: Cleanup old Docker images
run: docker image prune -f || true