Files
klz-cables.com/.gitea/workflows/deploy.yml
Marc Mintel 7f2f6f5aca
Some checks failed
Build & Deploy KLZ Cables / build-and-deploy (push) Failing after 5m48s
deploy
2026-01-29 11:33:30 +01:00

361 lines
20 KiB
YAML

name: Build & Deploy KLZ Cables
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: docker
steps:
# ═══════════════════════════════════════════════════════════════════════════════
# LOGGING: Workflow Start - Full Transparency
# ═══════════════════════════════════════════════════════════════════════════════
- name: 📋 Log Workflow Start
run: |
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ KLZ Cables Deployment Workflow Started ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""
echo "📋 Workflow Information:"
echo " • Repository: ${{ github.repository }}"
echo " • Branch: ${{ github.ref }}"
echo " • Commit: ${{ github.sha }}"
echo " • Actor: ${{ github.actor }}"
echo " • Run ID: ${{ github.run_id }}"
echo " • Timestamp: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
echo ""
echo "🔍 Environment Details:"
echo " • Runner OS: ${{ runner.os }}"
echo " • Workspace: ${{ github.workspace }}"
echo ""
- name: Checkout repository
uses: actions/checkout@v4
# ═══════════════════════════════════════════════════════════════════════════════
# LOGGING: Registry Login Phase
# ═══════════════════════════════════════════════════════════════════════════════
- name: 🔐 Login to private registry
run: |
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ Step: Registry Login ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""
echo "🔐 Authenticating with private registry..."
echo " Registry: registry.infra.mintel.me"
echo " User: ${{ secrets.REGISTRY_USER != '' && '***' || 'NOT SET' }}"
echo ""
# Execute login with error handling
if echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin 2>&1; then
echo "✅ Registry login successful"
else
echo "❌ Registry login failed"
exit 1
fi
echo ""
# ═══════════════════════════════════════════════════════════════════════════════
# LOGGING: Build Phase
# ═══════════════════════════════════════════════════════════════════════════════
- name: 🏗️ Build Docker image
run: |
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ Step: Build Docker Image ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""
echo "🏗️ Building Docker image with buildx..."
echo " Platform: linux/arm64"
echo " Target: registry.infra.mintel.me/mintel/klz-cables.com:latest"
echo ""
echo "📦 Build Arguments (NEXT_PUBLIC_* only - baked into client bundle):"
echo " • NEXT_PUBLIC_BASE_URL: ${{ secrets.NEXT_PUBLIC_BASE_URL != '' && '***' || 'NOT SET' }}"
echo " • NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID != '' && '***' || 'NOT SET' }}"
echo " • NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${{ secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL != '' && '***' || 'NOT SET' }}"
echo ""
echo "⏱️ Build started at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
echo ""
# Execute build with detailed logging
set -e
docker buildx build \
--pull \
--platform linux/arm64 \
--build-arg NEXT_PUBLIC_BASE_URL="${{ secrets.NEXT_PUBLIC_BASE_URL }}" \
--build-arg NEXT_PUBLIC_UMAMI_WEBSITE_ID="${{ secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID }}" \
--build-arg NEXT_PUBLIC_UMAMI_SCRIPT_URL="${{ secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL }}" \
-t registry.infra.mintel.me/mintel/klz-cables.com:latest \
--push .
BUILD_EXIT_CODE=$?
if [ $BUILD_EXIT_CODE -eq 0 ]; then
echo ""
echo "✅ Build completed successfully at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
echo ""
echo "📊 Image Details:"
IMAGE_SIZE=$(docker inspect registry.infra.mintel.me/mintel/klz-cables.com:latest --format='{{.Size}}')
IMAGE_SIZE_MB=$((IMAGE_SIZE / 1024 / 1024))
echo " • Size: ${IMAGE_SIZE_MB}MB"
docker inspect registry.infra.mintel.me/mintel/klz-cables.com:latest --format=' • Created: {{.Created}}'
docker inspect registry.infra.mintel.me/mintel/klz-cables.com:latest --format=' • Architecture: {{.Architecture}}'
else
echo ""
echo "❌ Build failed with exit code: $BUILD_EXIT_CODE"
exit $BUILD_EXIT_CODE
fi
echo ""
# ═══════════════════════════════════════════════════════════════════════════════
# LOGGING: Deployment Phase
# ═══════════════════════════════════════════════════════════════════════════════
- name: 🚀 Deploy to production server
run: |
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ Step: Deploy to Production Server ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""
echo "🚀 Starting deployment process..."
echo " Target Server: alpha.mintel.me"
echo " Deploy User: deploy (via sudo from root)"
echo " Target Path: /home/deploy/sites/klz-cables.com"
echo ""
# Setup SSH with logging
echo "🔐 Setting up SSH connection..."
mkdir -p ~/.ssh
echo "${{ secrets.ALPHA_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
echo "🔑 Adding host to known_hosts..."
ssh-keyscan -H alpha.mintel.me >> ~/.ssh/known_hosts 2>/dev/null
if [ $? -eq 0 ]; then
echo "✅ Host key added successfully"
else
echo "⚠️ Warning: Could not add host key"
fi
echo ""
# Create .env file content
echo "📝 Preparing environment configuration..."
cat > /tmp/klz-cables.env << EOF
# ============================================================================
# KLZ Cables - Production Environment Configuration
# ============================================================================
# Auto-generated by CI/CD workflow
# DO NOT EDIT MANUALLY - Changes will be overwritten on next deployment
# ============================================================================
# Application
NODE_ENV=production
NEXT_PUBLIC_BASE_URL=${{ secrets.NEXT_PUBLIC_BASE_URL }}
# Analytics (Umami)
NEXT_PUBLIC_UMAMI_WEBSITE_ID=${{ secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID }}
NEXT_PUBLIC_UMAMI_SCRIPT_URL=${{ secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL }}
# Error Tracking (GlitchTip/Sentry)
SENTRY_DSN=${{ secrets.SENTRY_DSN }}
# Email Configuration (Mailgun)
MAIL_HOST=${{ secrets.MAIL_HOST }}
MAIL_PORT=${{ secrets.MAIL_PORT }}
MAIL_USERNAME=${{ secrets.MAIL_USERNAME }}
MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}
MAIL_FROM=${{ secrets.MAIL_FROM }}
MAIL_RECIPIENTS=${{ secrets.MAIL_RECIPIENTS }}
EOF
echo "✅ Environment file prepared"
echo ""
# Execute deployment commands with detailed logging
echo "📡 Connecting to server and executing deployment..."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Copy .env file to server
echo "📤 Uploading environment configuration..."
scp -o StrictHostKeyChecking=accept-new \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ConnectTimeout=10 \
/tmp/klz-cables.env \
root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/.env
if [ $? -eq 0 ]; then
echo "✅ Environment file uploaded successfully"
else
echo "❌ Failed to upload environment file"
exit 1
fi
echo ""
# SSH to server and run deployment
echo "🚀 Executing deployment on server..."
ssh -o StrictHostKeyChecking=accept-new \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ConnectTimeout=10 \
root@alpha.mintel.me bash << EOF
set -e
PROJECT_DIR="/home/deploy/sites/klz-cables.com"
cd "\$PROJECT_DIR"
echo "🔒 Securing environment file..."
chmod 600 .env
chown deploy:deploy .env
echo "🔐 Logging into Docker registry..."
echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin
echo "🔄 Pulling latest image..."
docker pull registry.infra.mintel.me/mintel/klz-cables.com:latest
echo "🔄 Stopping existing containers..."
docker-compose down
echo "🚀 Starting new containers..."
docker-compose up -d
echo "⏳ Waiting for services to be healthy..."
MAX_RETRIES=12
RETRY_COUNT=0
until curl -s -f http://127.0.0.1:3000/health > /dev/null || [ \$RETRY_COUNT -eq \$MAX_RETRIES ]; do
echo " • Waiting for health check... (\$((RETRY_COUNT + 1))/\$MAX_RETRIES)"
# Log the output of curl for debugging if it fails
curl -v http://127.0.0.1:3000/health 2>&1 | grep -E "< HTTP/|* Connection" || true
sleep 5
RETRY_COUNT=\$((RETRY_COUNT + 1))
done
if [ \$RETRY_COUNT -eq \$MAX_RETRIES ]; then
echo "❌ Health check failed after \$MAX_RETRIES retries"
echo "🔍 Container status:"
docker-compose ps
echo ""
echo "🔍 Container logs:"
docker-compose logs --tail=100
exit 1
fi
echo "✅ Health check passed!"
echo "🔍 Checking service status..."
docker-compose ps
echo ""
echo "✅ Deployment complete!"
EOF
DEPLOY_EXIT_CODE=$?
echo ""
# Clean up temporary env file
rm -f /tmp/klz-cables.env
if [ $DEPLOY_EXIT_CODE -eq 0 ]; then
echo "✅ Deployment completed successfully at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
else
echo "❌ Deployment failed with exit code: $DEPLOY_EXIT_CODE"
echo ""
echo "🔍 Troubleshooting Tips:"
echo " • Check server connectivity: ping alpha.mintel.me"
echo " • Verify SSH key permissions on server"
echo " • Check disk space on target server"
echo " • Review docker compose configuration"
echo " • Verify all required secrets are set in Gitea"
exit $DEPLOY_EXIT_CODE
fi
echo ""
# ═══════════════════════════════════════════════════════════════════════════════
# LOGGING: Workflow Summary
# ═══════════════════════════════════════════════════════════════════════════════
- name: 📊 Workflow Summary
if: always()
run: |
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ Workflow Summary ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""
echo "📊 Final Status:"
echo " • Workflow: ${{ job.status }}"
echo " • Completed: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
echo ""
echo "🎯 Deployment Target:"
echo " • Image: registry.infra.mintel.me/mintel/klz-cables.com:latest"
echo " • Server: alpha.mintel.me"
echo " • Service: klz-cables.com"
echo ""
echo "🔐 Security Notes:"
echo " • All secrets are masked (*** ) in logs"
echo " • SSH keys are created with 600 permissions"
echo " • Passwords are never displayed in plain text"
echo " • .env file is auto-generated from Gitea secrets"
echo " • .env file has 600 permissions on server"
echo ""
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
if [ "${{ job.status }}" == "success" ]; then
echo "║ ✅ DEPLOYMENT SUCCESSFUL ║"
else
echo "║ ❌ DEPLOYMENT FAILED ║"
fi
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
# ═══════════════════════════════════════════════════════════════════════════════
# NOTIFICATION: Gotify
# ═══════════════════════════════════════════════════════════════════════════════
- name: 🔔 Gotify Notification (Success)
if: success()
run: |
echo "Sending success notification to Gotify..."
RESPONSE=$(curl -k -s -w "\n%{http_code}" -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \
-F "title=✅ Deployment Success: ${{ github.repository }}" \
-F "message=The deployment of ${{ github.repository }} (branch: ${{ github.ref }}) was successful.
Commit: ${{ github.sha }}
Actor: ${{ github.actor }}
Run ID: ${{ github.run_id }}" \
-F "priority=5")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
echo "HTTP Status: $HTTP_CODE"
echo "Response Body: $BODY"
if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
echo "Failed to send Gotify notification"
exit 0 # Don't fail the workflow because of notification failure
fi
- name: 🔔 Gotify Notification (Failure)
if: failure()
run: |
echo "Sending failure notification to Gotify..."
RESPONSE=$(curl -k -s -w "\n%{http_code}" -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \
-F "title=❌ Deployment Failed: ${{ github.repository }}" \
-F "message=The deployment of ${{ github.repository }} (branch: ${{ github.ref }}) failed!
Commit: ${{ github.sha }}
Actor: ${{ github.actor }}
Run ID: ${{ github.run_id }}
Please check the logs for details." \
-F "priority=8")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
echo "HTTP Status: $HTTP_CODE"
echo "Response Body: $BODY"
if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
echo "Failed to send Gotify notification"
exit 0 # Don't fail the workflow because of notification failure
fi