name: Build & Deploy KLZ Cables on: push: branches: [main, staging] jobs: build-and-deploy: runs-on: docker steps: # ═══════════════════════════════════════════════════════════════════════════════ # LOGGING: Workflow Start - Full Transparency # ═══════════════════════════════════════════════════════════════════════════════ - name: 📋 Log Workflow Start run: | echo "🚀 Starting deployment for ${{ github.repository }} (${{ github.ref }})" echo " • Branch: ${{ github.ref_name }}" echo " • Commit: ${{ github.sha }}" echo " • Timestamp: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" - name: Checkout repository uses: actions/checkout@v4 # ═══════════════════════════════════════════════════════════════════════════════ # LOGGING: Registry Login Phase # ═══════════════════════════════════════════════════════════════════════════════ - name: 🔐 Login to private registry run: | echo "🔐 Authenticating with registry.infra.mintel.me..." echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin # ═══════════════════════════════════════════════════════════════════════════════ # LOGGING: Build Phase # ═══════════════════════════════════════════════════════════════════════════════ - name: 🏗️ Build Docker image env: NEXT_PUBLIC_BASE_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_BASE_URL || (secrets.STAGING_NEXT_PUBLIC_BASE_URL || secrets.NEXT_PUBLIC_BASE_URL) }} NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID || (secrets.STAGING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID) }} NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || (secrets.STAGING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL) }} run: | echo "🏗️ Building Docker image (linux/arm64) for branch ${{ github.ref_name }}..." docker buildx build \ --pull \ --platform linux/arm64 \ --build-arg NEXT_PUBLIC_BASE_URL="$NEXT_PUBLIC_BASE_URL" \ --build-arg NEXT_PUBLIC_UMAMI_WEBSITE_ID="$NEXT_PUBLIC_UMAMI_WEBSITE_ID" \ --build-arg NEXT_PUBLIC_UMAMI_SCRIPT_URL="$NEXT_PUBLIC_UMAMI_SCRIPT_URL" \ -t registry.infra.mintel.me/mintel/klz-cables.com:${{ github.sha }} \ -t registry.infra.mintel.me/mintel/klz-cables.com:latest \ --push . # ═══════════════════════════════════════════════════════════════════════════════ # LOGGING: Deployment Phase # ═══════════════════════════════════════════════════════════════════════════════ - name: 🚀 Deploy to server env: NEXT_PUBLIC_BASE_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_BASE_URL || (secrets.STAGING_NEXT_PUBLIC_BASE_URL || secrets.NEXT_PUBLIC_BASE_URL) }} NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID || (secrets.STAGING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID) }} NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || (secrets.STAGING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL) }} SENTRY_DSN: ${{ github.ref_name == 'main' && secrets.SENTRY_DSN || (secrets.STAGING_SENTRY_DSN || secrets.SENTRY_DSN) }} MAIL_HOST: ${{ github.ref_name == 'main' && secrets.MAIL_HOST || (secrets.STAGING_MAIL_HOST || secrets.MAIL_HOST) }} MAIL_PORT: ${{ github.ref_name == 'main' && secrets.MAIL_PORT || (secrets.STAGING_MAIL_PORT || secrets.MAIL_PORT) }} MAIL_USERNAME: ${{ github.ref_name == 'main' && secrets.MAIL_USERNAME || (secrets.STAGING_MAIL_USERNAME || secrets.MAIL_USERNAME) }} MAIL_PASSWORD: ${{ github.ref_name == 'main' && secrets.MAIL_PASSWORD || (secrets.STAGING_MAIL_PASSWORD || secrets.MAIL_PASSWORD) }} MAIL_FROM: ${{ github.ref_name == 'main' && secrets.MAIL_FROM || (secrets.STAGING_MAIL_FROM || secrets.MAIL_FROM) }} MAIL_RECIPIENTS: ${{ github.ref_name == 'main' && secrets.MAIL_RECIPIENTS || (secrets.STAGING_MAIL_RECIPIENTS || secrets.MAIL_RECIPIENTS) }} run: | BRANCH=${{ github.ref_name }} if [ "$BRANCH" = "main" ]; then ENV_FILE=.env.prod TRAEFIK_HOST="klz-cables.com, www.klz-cables.com" else ENV_FILE=.env.staging TRAEFIK_HOST="staging.klz-cables.com" fi echo "🚀 Deploying branch $BRANCH to $ENV_FILE..." # Setup SSH mkdir -p ~/.ssh echo "${{ secrets.ALPHA_SSH_KEY }}" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H alpha.mintel.me >> ~/.ssh/known_hosts 2>/dev/null # Create .env file content cat > /tmp/klz-cables.env << EOF # ============================================================================ # KLZ Cables - Environment Configuration ($BRANCH) # ============================================================================ # Auto-generated by CI/CD workflow # DO NOT EDIT MANUALLY - Changes will be overwritten on next deployment # ============================================================================ NODE_ENV=production NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL NEXT_PUBLIC_UMAMI_WEBSITE_ID=$NEXT_PUBLIC_UMAMI_WEBSITE_ID NEXT_PUBLIC_UMAMI_SCRIPT_URL=$NEXT_PUBLIC_UMAMI_SCRIPT_URL SENTRY_DSN=$SENTRY_DSN MAIL_HOST=$MAIL_HOST MAIL_PORT=$MAIL_PORT MAIL_USERNAME=$MAIL_USERNAME MAIL_PASSWORD=$MAIL_PASSWORD MAIL_FROM=$MAIL_FROM MAIL_RECIPIENTS=$MAIL_RECIPIENTS # Deployment variables for docker-compose IMAGE_TAG=${{ github.sha }} TRAEFIK_HOST=$TRAEFIK_HOST ENV_FILE=$ENV_FILE EOF # Upload .env and docker-compose.yml scp -o StrictHostKeyChecking=accept-new /tmp/klz-cables.env root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/$ENV_FILE scp -o StrictHostKeyChecking=accept-new docker-compose.yml root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/docker-compose.yml ssh -o StrictHostKeyChecking=accept-new root@alpha.mintel.me bash << EOF set -e cd /home/deploy/sites/klz-cables.com chmod 600 $ENV_FILE chown deploy:deploy $ENV_FILE echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin echo "📥 Pulling images..." IMAGE_TAG=${{ github.sha }} ENV_FILE=$ENV_FILE TRAEFIK_HOST="$TRAEFIK_HOST" docker compose --env-file $ENV_FILE pull echo "🚀 Starting containers..." IMAGE_TAG=${{ github.sha }} ENV_FILE=$ENV_FILE TRAEFIK_HOST="$TRAEFIK_HOST" docker compose --env-file $ENV_FILE up -d echo "🧹 Cleaning up old images..." docker system prune -f echo "⏳ Giving the app a few seconds to warm up..." sleep 10 echo "🔍 Checking container status..." docker compose --env-file $ENV_FILE ps if ! docker compose --env-file $ENV_FILE ps | grep -q "Up"; then echo "❌ Container failed to start" docker compose --env-file $ENV_FILE logs --tail=100 exit 1 fi echo "✅ Deployment complete!" EOF rm -f /tmp/klz-cables.env # ═══════════════════════════════════════════════════════════════════════════════ # LOGGING: Workflow Summary # ═══════════════════════════════════════════════════════════════════════════════ - name: 📊 Workflow Summary if: always() run: | echo "📊 Status: ${{ job.status }}" echo "🎯 Target: alpha.mintel.me" echo "🌿 Branch: ${{ github.ref_name }}" # ═══════════════════════════════════════════════════════════════════════════════ # 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_name }}) 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_name }}) 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