198 lines
12 KiB
YAML
198 lines
12 KiB
YAML
name: Build & Deploy
|
|
|
|
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/${{ github.repository }}:${{ github.sha }} \
|
|
-t registry.infra.mintel.me/${{ github.repository }}: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 }}
|
|
|
|
# Derive domain from NEXT_PUBLIC_BASE_URL (strip https:// and trailing slash)
|
|
DOMAIN=$(echo "$NEXT_PUBLIC_BASE_URL" | sed -E 's|https?://||' | sed -E 's|/.*||')
|
|
|
|
if [ "$BRANCH" = "main" ]; then
|
|
ENV_FILE=.env.prod
|
|
# For production, we want both root and www
|
|
TRAEFIK_HOST="\`$DOMAIN\`, \`www.$DOMAIN\`"
|
|
else
|
|
ENV_FILE=.env.staging
|
|
TRAEFIK_HOST="\`$DOMAIN\`"
|
|
fi
|
|
|
|
echo "🚀 Deploying branch $BRANCH to $ENV_FILE..."
|
|
echo "🌐 Domain: $DOMAIN"
|
|
|
|
# Setup SSH
|
|
mkdir -p ~/.ssh
|
|
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_ed25519
|
|
chmod 600 ~/.ssh/id_ed25519
|
|
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null
|
|
|
|
# Create .env file content
|
|
cat > /tmp/app.env << EOF
|
|
# ============================================================================
|
|
# Environment Configuration ($BRANCH)
|
|
# ============================================================================
|
|
# Auto-generated by CI/CD workflow
|
|
# ============================================================================
|
|
|
|
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
|
|
|
|
APP_DIR="/home/deploy/sites/${{ github.event.repository.name }}"
|
|
ssh -o StrictHostKeyChecking=accept-new root@${{ secrets.SSH_HOST }} "mkdir -p $APP_DIR"
|
|
scp -o StrictHostKeyChecking=accept-new /tmp/app.env root@${{ secrets.SSH_HOST }}:$APP_DIR/$ENV_FILE
|
|
scp -o StrictHostKeyChecking=accept-new docker-compose.yml root@${{ secrets.SSH_HOST }}:$APP_DIR/docker-compose.yml
|
|
|
|
ssh -o StrictHostKeyChecking=accept-new root@${{ secrets.SSH_HOST }} bash << EOF
|
|
set -e
|
|
cd $APP_DIR
|
|
|
|
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/app.env
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
# LOGGING: Workflow Summary
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
- name: 📊 Workflow Summary
|
|
if: always()
|
|
run: |
|
|
echo "📊 Status: ${{ job.status }}"
|
|
echo "🎯 Target: ${{ secrets.SSH_HOST }}"
|
|
echo "🌿 Branch: ${{ github.ref_name }}"
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
# NOTIFICATION: Gotify
|
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
- name: 🔔 Gotify Notification (Success)
|
|
if: success()
|
|
run: |
|
|
echo "Sending success notification to Gotify..."
|
|
curl -k -s -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"
|
|
|
|
- name: 🔔 Gotify Notification (Failure)
|
|
if: failure()
|
|
run: |
|
|
echo "Sending failure notification to Gotify..."
|
|
curl -k -s -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"
|