202 lines
6.7 KiB
YAML

name: Deployment Pipeline
on:
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
default: 'preview'
type: choice
options:
- preview
- production
skip_tests:
description: 'Skip tests (emergency deployment)'
required: false
default: false
type: boolean
force_deploy:
description: 'Force deployment even if checks fail'
required: false
default: false
type: boolean
schedule:
# Deploy to preview every Sunday at 2 AM UTC
- cron: '0 2 * * 0'
env:
NODE_VERSION: '20'
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
jobs:
pre-deployment-checks:
name: Pre-Deployment Checks
runs-on: ubuntu-latest
timeout-minutes: 10
if: ${{ !inputs.skip_tests }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci --no-audit --no-fund
- name: Quick lint check
run: npm run ci:lint
- name: TypeScript check
run: npm run ci:typecheck
- name: Run tests
run: npm run ci:test
build-and-deploy:
name: Build and Deploy
runs-on: ubuntu-latest
timeout-minutes: 20
needs: [pre-deployment-checks]
if: always() && (needs.pre-deployment-checks.result == 'success' || inputs.skip_tests || inputs.force_deploy)
environment: ${{ inputs.environment || 'preview' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci --no-audit --no-fund
- name: Build application
run: |
echo "Building application for ${{ inputs.environment || 'preview' }} environment..."
npm run ci:build
# Generate deployment ID
DEPLOY_ID=$(date +%Y%m%d-%H%M%S)-${GITHUB_SHA::8}
echo "DEPLOY_ID=$DEPLOY_ID" >> $GITHUB_ENV
echo "Deployment ID: $DEPLOY_ID"
- name: Database migration (Production only)
if: inputs.environment == 'production'
run: |
echo "Running database migrations for production..."
# In a real scenario, this would run actual migrations
echo "Database migrations completed (simulated)"
- name: Deploy to Cloudflare
run: |
echo "Deploying to Cloudflare ${{ inputs.environment || 'preview' }} environment..."
CLOUDFLARE_ACCOUNT_ID=${{ env.CLOUDFLARE_ACCOUNT_ID }} npx @opennextjs/cloudflare deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
- name: Wait for deployment
run: |
echo "Waiting for deployment to propagate..."
sleep 15
- name: Health check
run: |
echo "Performing health check..."
MAX_RETRIES=5
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
if curl -f -s https://united-tattoo.christyl116.workers.dev > /dev/null; then
echo "✅ Health check passed!"
break
else
RETRY_COUNT=$((RETRY_COUNT + 1))
echo "Health check failed, retrying... ($RETRY_COUNT/$MAX_RETRIES)"
sleep 10
fi
done
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo "❌ Health check failed after $MAX_RETRIES attempts"
exit 1
fi
- name: Performance check
run: |
echo "Running performance check..."
# Basic performance check
RESPONSE_TIME=$(curl -o /dev/null -s -w '%{time_total}' https://united-tattoo.christyl116.workers.dev)
echo "Response time: ${RESPONSE_TIME}s"
# Check if response time is acceptable (less than 2 seconds)
if (( $(echo "$RESPONSE_TIME < 2.0" | bc -l) )); then
echo "✅ Performance check passed"
else
echo "⚠️ Performance check warning: Response time is ${RESPONSE_TIME}s"
fi
- name: SEO check
run: |
echo "Checking SEO metadata..."
curl -s https://united-tattoo.christyl116.workers.dev | grep -q "application/ld+json" && echo "✅ JSON-LD found" || echo "⚠️ JSON-LD not found"
curl -s https://united-tattoo.christyl116.workers.dev | grep -q "og:title" && echo "✅ Open Graph tags found" || echo "⚠️ Open Graph tags not found"
- name: Create deployment record
run: |
echo "Creating deployment record..."
# In a real scenario, this would create a record in your database or logging system
echo "Deployment ID: $DEPLOY_ID" > deployment-info.txt
echo "Environment: ${{ inputs.environment || 'preview' }}" >> deployment-info.txt
echo "Commit: $GITHUB_SHA" >> deployment-info.txt
echo "Timestamp: $(date -u)" >> deployment-info.txt
echo "URL: https://united-tattoo.christyl116.workers.dev" >> deployment-info.txt
- name: Upload deployment info
uses: actions/upload-artifact@v4
with:
name: deployment-info-${{ inputs.environment || 'preview' }}-${{ env.DEPLOY_ID }}
path: deployment-info.txt
retention-days: 90
- name: Notify success
if: success()
run: |
echo "🎉 Deployment to ${{ inputs.environment || 'preview' }} completed successfully!"
echo "Deployment ID: $DEPLOY_ID"
echo "URL: https://united-tattoo.christyl116.workers.dev"
- name: Notify failure
if: failure()
run: |
echo "❌ Deployment to ${{ inputs.environment || 'preview' }} failed!"
echo "Deployment ID: $DEPLOY_ID"
echo "Please check the logs for details."
rollback:
name: Rollback (if needed)
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [build-and-deploy]
if: failure() && inputs.environment == 'production'
environment: production
steps:
- name: Rollback deployment
run: |
echo "Rolling back production deployment..."
# In a real scenario, this would implement actual rollback logic
echo "Rollback completed (simulated)"
- name: Verify rollback
run: |
echo "Verifying rollback..."
curl -f https://united-tattoo.christyl116.workers.dev || exit 1
echo "✅ Rollback verification successful"