Some checks failed
HVAC Plugin CI/CD Pipeline / Security Analysis (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Unit Tests (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Integration Tests (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Notification (push) Has been cancelled
- Add multi-stage CI/CD pipeline with security scanning - Implement GitOps deployment automation with rollback capability - Add comprehensive security monitoring and compliance checks - Include dependency scanning, secrets detection, and WordPress security analysis - Support staging and production deployment workflows - Add automated backup and restore functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
483 lines
No EOL
18 KiB
YAML
483 lines
No EOL
18 KiB
YAML
name: GitOps Deployment Automation
|
|
|
|
on:
|
|
repository_dispatch:
|
|
types: [deploy-staging, deploy-production, rollback]
|
|
workflow_dispatch:
|
|
inputs:
|
|
environment:
|
|
description: 'Environment to deploy to'
|
|
required: true
|
|
default: 'staging'
|
|
type: choice
|
|
options:
|
|
- staging
|
|
- production
|
|
action:
|
|
description: 'Deployment action'
|
|
required: true
|
|
default: 'deploy'
|
|
type: choice
|
|
options:
|
|
- deploy
|
|
- rollback
|
|
- health-check
|
|
version:
|
|
description: 'Version/tag to deploy (leave empty for latest)'
|
|
required: false
|
|
type: string
|
|
|
|
env:
|
|
DEPLOYMENT_TIMEOUT: 300
|
|
HEALTH_CHECK_RETRIES: 5
|
|
BACKUP_RETENTION_DAYS: 30
|
|
|
|
jobs:
|
|
validate-deployment:
|
|
name: Validate Deployment Request
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
environment: ${{ steps.validate.outputs.environment }}
|
|
action: ${{ steps.validate.outputs.action }}
|
|
version: ${{ steps.validate.outputs.version }}
|
|
proceed: ${{ steps.validate.outputs.proceed }}
|
|
|
|
steps:
|
|
- name: Validate Input
|
|
id: validate
|
|
run: |
|
|
echo "🔍 Validating deployment request..."
|
|
|
|
# Determine environment
|
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
ENV="${{ github.event.inputs.environment }}"
|
|
ACTION="${{ github.event.inputs.action }}"
|
|
VERSION="${{ github.event.inputs.version }}"
|
|
elif [ "${{ github.event_name }}" = "repository_dispatch" ]; then
|
|
ENV="${{ github.event.client_payload.environment }}"
|
|
ACTION="${{ github.event.client_payload.action }}"
|
|
VERSION="${{ github.event.client_payload.version }}"
|
|
else
|
|
echo "❌ Invalid trigger event"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate environment
|
|
if [[ ! "$ENV" =~ ^(staging|production)$ ]]; then
|
|
echo "❌ Invalid environment: $ENV"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate action
|
|
if [[ ! "$ACTION" =~ ^(deploy|rollback|health-check)$ ]]; then
|
|
echo "❌ Invalid action: $ACTION"
|
|
exit 1
|
|
fi
|
|
|
|
# Production deployment additional validation
|
|
if [ "$ENV" = "production" ] && [ "$ACTION" = "deploy" ]; then
|
|
if [ "${{ github.ref_name }}" != "main" ]; then
|
|
echo "❌ Production deployments only allowed from main branch"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if staging deployment was successful recently
|
|
echo "🔍 Checking staging deployment status..."
|
|
# This would typically query your monitoring/deployment system
|
|
fi
|
|
|
|
echo "✅ Validation passed"
|
|
echo "environment=$ENV" >> $GITHUB_OUTPUT
|
|
echo "action=$ACTION" >> $GITHUB_OUTPUT
|
|
echo "version=${VERSION:-latest}" >> $GITHUB_OUTPUT
|
|
echo "proceed=true" >> $GITHUB_OUTPUT
|
|
|
|
backup-environment:
|
|
name: Create Environment Backup
|
|
runs-on: ubuntu-latest
|
|
needs: validate-deployment
|
|
if: needs.validate-deployment.outputs.proceed == 'true' && needs.validate-deployment.outputs.action == 'deploy'
|
|
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup SSH
|
|
run: |
|
|
mkdir -p ~/.ssh
|
|
if [ "${{ needs.validate-deployment.outputs.environment }}" = "staging" ]; then
|
|
echo "${{ secrets.STAGING_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
HOST="${{ secrets.STAGING_HOST }}"
|
|
USER="${{ secrets.STAGING_SSH_USER }}"
|
|
WP_PATH="${{ secrets.STAGING_WP_PATH }}"
|
|
else
|
|
echo "${{ secrets.PRODUCTION_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
HOST="${{ secrets.PRODUCTION_HOST }}"
|
|
USER="${{ secrets.PRODUCTION_SSH_USER }}"
|
|
WP_PATH="${{ secrets.PRODUCTION_WP_PATH }}"
|
|
fi
|
|
chmod 600 ~/.ssh/id_rsa
|
|
ssh-keyscan -H $HOST >> ~/.ssh/known_hosts
|
|
echo "HOST=$HOST" >> $GITHUB_ENV
|
|
echo "USER=$USER" >> $GITHUB_ENV
|
|
echo "WP_PATH=$WP_PATH" >> $GITHUB_ENV
|
|
|
|
- name: Create Full Backup
|
|
run: |
|
|
echo "💾 Creating full environment backup..."
|
|
|
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
BACKUP_NAME="hvac-plugin-${{ needs.validate-deployment.outputs.environment }}-$TIMESTAMP"
|
|
|
|
ssh $USER@$HOST "
|
|
cd $WP_PATH/wp-content/plugins
|
|
|
|
# Create plugin backup
|
|
tar -czf /tmp/${BACKUP_NAME}-plugin.tar.gz hvac-community-events/
|
|
|
|
# Create database backup
|
|
wp db export /tmp/${BACKUP_NAME}-db.sql --path=$WP_PATH
|
|
gzip /tmp/${BACKUP_NAME}-db.sql
|
|
|
|
# Create uploads backup (if plugin stores files there)
|
|
if [ -d '$WP_PATH/wp-content/uploads/hvac-events' ]; then
|
|
tar -czf /tmp/${BACKUP_NAME}-uploads.tar.gz -C $WP_PATH/wp-content/uploads hvac-events/
|
|
fi
|
|
|
|
echo '✅ Backup created: ${BACKUP_NAME}'
|
|
echo 'BACKUP_NAME=${BACKUP_NAME}' >> backup_info.txt
|
|
"
|
|
|
|
# Store backup info for rollback
|
|
echo "BACKUP_NAME=${BACKUP_NAME}" >> $GITHUB_ENV
|
|
|
|
- name: Verify Backup
|
|
run: |
|
|
echo "🔍 Verifying backup integrity..."
|
|
|
|
ssh $USER@$HOST "
|
|
cd /tmp
|
|
|
|
# Verify plugin backup
|
|
if [ -f ${BACKUP_NAME}-plugin.tar.gz ]; then
|
|
tar -tzf ${BACKUP_NAME}-plugin.tar.gz > /dev/null && echo '✅ Plugin backup verified'
|
|
else
|
|
echo '❌ Plugin backup missing'
|
|
exit 1
|
|
fi
|
|
|
|
# Verify database backup
|
|
if [ -f ${BACKUP_NAME}-db.sql.gz ]; then
|
|
gunzip -t ${BACKUP_NAME}-db.sql.gz && echo '✅ Database backup verified'
|
|
else
|
|
echo '❌ Database backup missing'
|
|
exit 1
|
|
fi
|
|
"
|
|
|
|
deploy:
|
|
name: Deploy Application
|
|
runs-on: ubuntu-latest
|
|
needs: [validate-deployment, backup-environment]
|
|
if: needs.validate-deployment.outputs.proceed == 'true' && needs.validate-deployment.outputs.action == 'deploy'
|
|
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ needs.validate-deployment.outputs.version != 'latest' && needs.validate-deployment.outputs.version || github.sha }}
|
|
|
|
- name: Setup Deployment Environment
|
|
run: |
|
|
echo "🚀 Setting up deployment for ${{ needs.validate-deployment.outputs.environment }}..."
|
|
|
|
# Install deployment tools
|
|
sudo apt-get update && sudo apt-get install -y rsync
|
|
|
|
# Setup SSH
|
|
mkdir -p ~/.ssh
|
|
if [ "${{ needs.validate-deployment.outputs.environment }}" = "staging" ]; then
|
|
echo "${{ secrets.STAGING_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
echo "DEPLOY_HOST=${{ secrets.STAGING_HOST }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_USER=${{ secrets.STAGING_SSH_USER }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_PATH=${{ secrets.STAGING_WP_PATH }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_URL=${{ secrets.STAGING_URL }}" >> $GITHUB_ENV
|
|
else
|
|
echo "${{ secrets.PRODUCTION_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
echo "DEPLOY_HOST=${{ secrets.PRODUCTION_HOST }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_USER=${{ secrets.PRODUCTION_SSH_USER }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_PATH=${{ secrets.PRODUCTION_WP_PATH }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_URL=${{ secrets.PRODUCTION_URL }}" >> $GITHUB_ENV
|
|
fi
|
|
chmod 600 ~/.ssh/id_rsa
|
|
ssh-keyscan -H $DEPLOY_HOST >> ~/.ssh/known_hosts
|
|
|
|
- name: Pre-deployment Health Check
|
|
run: |
|
|
echo "🏥 Running pre-deployment health check..."
|
|
|
|
# Check if site is accessible
|
|
if ! curl -f -s -o /dev/null -w "%{http_code}" $DEPLOY_URL | grep -q "200"; then
|
|
echo "⚠️ Site health check failed - proceeding with caution"
|
|
else
|
|
echo "✅ Pre-deployment health check passed"
|
|
fi
|
|
|
|
# Check plugin status
|
|
ssh $DEPLOY_USER@$DEPLOY_HOST "
|
|
cd $DEPLOY_PATH
|
|
if wp plugin is-active hvac-community-events; then
|
|
echo '✅ Plugin is currently active'
|
|
else
|
|
echo '⚠️ Plugin is currently inactive'
|
|
fi
|
|
"
|
|
|
|
- name: Execute Deployment
|
|
run: |
|
|
echo "🚀 Executing deployment..."
|
|
|
|
# Use existing deployment script if available
|
|
if [ -f scripts/deploy.sh ]; then
|
|
chmod +x scripts/deploy.sh
|
|
./scripts/deploy.sh ${{ needs.validate-deployment.outputs.environment }}
|
|
else
|
|
echo "📦 Manual deployment process..."
|
|
|
|
# Sync plugin files
|
|
rsync -avz --delete \
|
|
--exclude='.git*' \
|
|
--exclude='node_modules/' \
|
|
--exclude='tests/' \
|
|
--exclude='.forgejo/' \
|
|
./ $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/wp-content/plugins/hvac-community-events/
|
|
|
|
# Activate plugin and flush rewrite rules
|
|
ssh $DEPLOY_USER@$DEPLOY_HOST "
|
|
cd $DEPLOY_PATH
|
|
|
|
# Activate plugin
|
|
wp plugin activate hvac-community-events
|
|
|
|
# Flush rewrite rules
|
|
wp rewrite flush
|
|
|
|
# Clear any caches
|
|
if wp plugin is-active w3-total-cache; then
|
|
wp w3-total-cache flush
|
|
fi
|
|
|
|
if wp plugin is-active wp-super-cache; then
|
|
wp super-cache flush
|
|
fi
|
|
|
|
echo '✅ Deployment completed successfully'
|
|
"
|
|
fi
|
|
|
|
- name: Post-deployment Verification
|
|
run: |
|
|
echo "🔍 Running post-deployment verification..."
|
|
|
|
# Wait for deployment to settle
|
|
sleep 15
|
|
|
|
# Health check with retries
|
|
for i in $(seq 1 $HEALTH_CHECK_RETRIES); do
|
|
echo "Health check attempt $i/$HEALTH_CHECK_RETRIES..."
|
|
|
|
if curl -f -s -o /dev/null -w "%{http_code}" $DEPLOY_URL | grep -q "200"; then
|
|
echo "✅ Site is responding"
|
|
break
|
|
elif [ $i -eq $HEALTH_CHECK_RETRIES ]; then
|
|
echo "❌ Site health check failed after $HEALTH_CHECK_RETRIES attempts"
|
|
exit 1
|
|
else
|
|
echo "⏳ Waiting 10 seconds before retry..."
|
|
sleep 10
|
|
fi
|
|
done
|
|
|
|
# Plugin-specific checks
|
|
ssh $DEPLOY_USER@$DEPLOY_HOST "
|
|
cd $DEPLOY_PATH
|
|
|
|
# Verify plugin is active
|
|
if wp plugin is-active hvac-community-events; then
|
|
echo '✅ Plugin is active'
|
|
else
|
|
echo '❌ Plugin activation failed'
|
|
exit 1
|
|
fi
|
|
|
|
# Check for PHP errors in logs
|
|
if tail -n 20 /var/log/apache2/error.log | grep -i 'hvac-community-events' | grep -i error; then
|
|
echo '⚠️ PHP errors detected in logs'
|
|
else
|
|
echo '✅ No PHP errors detected'
|
|
fi
|
|
"
|
|
|
|
rollback:
|
|
name: Rollback Deployment
|
|
runs-on: ubuntu-latest
|
|
needs: validate-deployment
|
|
if: needs.validate-deployment.outputs.proceed == 'true' && needs.validate-deployment.outputs.action == 'rollback'
|
|
|
|
steps:
|
|
- name: Setup Rollback Environment
|
|
run: |
|
|
echo "🔄 Setting up rollback for ${{ needs.validate-deployment.outputs.environment }}..."
|
|
|
|
mkdir -p ~/.ssh
|
|
if [ "${{ needs.validate-deployment.outputs.environment }}" = "staging" ]; then
|
|
echo "${{ secrets.STAGING_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
echo "DEPLOY_HOST=${{ secrets.STAGING_HOST }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_USER=${{ secrets.STAGING_SSH_USER }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_PATH=${{ secrets.STAGING_WP_PATH }}" >> $GITHUB_ENV
|
|
else
|
|
echo "${{ secrets.PRODUCTION_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
echo "DEPLOY_HOST=${{ secrets.PRODUCTION_HOST }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_USER=${{ secrets.PRODUCTION_SSH_USER }}" >> $GITHUB_ENV
|
|
echo "DEPLOY_PATH=${{ secrets.PRODUCTION_WP_PATH }}" >> $GITHUB_ENV
|
|
fi
|
|
chmod 600 ~/.ssh/id_rsa
|
|
ssh-keyscan -H $DEPLOY_HOST >> ~/.ssh/known_hosts
|
|
|
|
- name: Execute Rollback
|
|
run: |
|
|
echo "🔄 Executing rollback..."
|
|
|
|
ssh $DEPLOY_USER@$DEPLOY_HOST "
|
|
cd /tmp
|
|
|
|
# Find most recent backup
|
|
LATEST_BACKUP=\$(ls -t hvac-plugin-${{ needs.validate-deployment.outputs.environment }}-*-plugin.tar.gz 2>/dev/null | head -n1)
|
|
|
|
if [ -z \"\$LATEST_BACKUP\" ]; then
|
|
echo '❌ No backup found for rollback'
|
|
exit 1
|
|
fi
|
|
|
|
echo \"Rolling back to: \$LATEST_BACKUP\"
|
|
|
|
# Deactivate current plugin
|
|
wp plugin deactivate hvac-community-events --path=$DEPLOY_PATH
|
|
|
|
# Remove current plugin directory
|
|
rm -rf $DEPLOY_PATH/wp-content/plugins/hvac-community-events
|
|
|
|
# Restore from backup
|
|
cd $DEPLOY_PATH/wp-content/plugins
|
|
tar -xzf /tmp/\$LATEST_BACKUP
|
|
|
|
# Reactivate plugin
|
|
wp plugin activate hvac-community-events --path=$DEPLOY_PATH
|
|
wp rewrite flush --path=$DEPLOY_PATH
|
|
|
|
echo '✅ Rollback completed successfully'
|
|
"
|
|
|
|
health-check:
|
|
name: Environment Health Check
|
|
runs-on: ubuntu-latest
|
|
needs: validate-deployment
|
|
if: needs.validate-deployment.outputs.proceed == 'true' && needs.validate-deployment.outputs.action == 'health-check'
|
|
|
|
steps:
|
|
- name: Comprehensive Health Check
|
|
run: |
|
|
echo "🏥 Running comprehensive health check for ${{ needs.validate-deployment.outputs.environment }}..."
|
|
|
|
# Setup environment variables
|
|
if [ "${{ needs.validate-deployment.outputs.environment }}" = "staging" ]; then
|
|
URL="${{ secrets.STAGING_URL }}"
|
|
SSH_KEY="${{ secrets.STAGING_SSH_KEY }}"
|
|
SSH_USER="${{ secrets.STAGING_SSH_USER }}"
|
|
SSH_HOST="${{ secrets.STAGING_HOST }}"
|
|
WP_PATH="${{ secrets.STAGING_WP_PATH }}"
|
|
else
|
|
URL="${{ secrets.PRODUCTION_URL }}"
|
|
SSH_KEY="${{ secrets.PRODUCTION_SSH_KEY }}"
|
|
SSH_USER="${{ secrets.PRODUCTION_SSH_USER }}"
|
|
SSH_HOST="${{ secrets.PRODUCTION_HOST }}"
|
|
WP_PATH="${{ secrets.PRODUCTION_WP_PATH }}"
|
|
fi
|
|
|
|
# Setup SSH
|
|
mkdir -p ~/.ssh
|
|
echo "$SSH_KEY" > ~/.ssh/id_rsa
|
|
chmod 600 ~/.ssh/id_rsa
|
|
ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
|
|
|
|
echo "🌐 Checking site accessibility..."
|
|
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL)
|
|
if [ "$HTTP_STATUS" = "200" ]; then
|
|
echo "✅ Site is accessible (HTTP $HTTP_STATUS)"
|
|
else
|
|
echo "❌ Site accessibility issue (HTTP $HTTP_STATUS)"
|
|
fi
|
|
|
|
echo "🔌 Checking plugin status..."
|
|
ssh $SSH_USER@$SSH_HOST "
|
|
cd $WP_PATH
|
|
|
|
if wp plugin is-active hvac-community-events; then
|
|
echo '✅ Plugin is active'
|
|
wp plugin get hvac-community-events --field=version
|
|
else
|
|
echo '❌ Plugin is not active'
|
|
fi
|
|
|
|
# Check for errors
|
|
if wp plugin list --status=error | grep hvac-community-events; then
|
|
echo '❌ Plugin has errors'
|
|
else
|
|
echo '✅ Plugin has no errors'
|
|
fi
|
|
|
|
# Database connectivity
|
|
if wp db check; then
|
|
echo '✅ Database connection healthy'
|
|
else
|
|
echo '❌ Database connection issues'
|
|
fi
|
|
"
|
|
|
|
cleanup:
|
|
name: Cleanup Old Backups
|
|
runs-on: ubuntu-latest
|
|
needs: [validate-deployment, deploy, rollback, health-check]
|
|
if: always() && needs.validate-deployment.outputs.proceed == 'true'
|
|
|
|
steps:
|
|
- name: Cleanup Old Backups
|
|
run: |
|
|
echo "🧹 Cleaning up old backups..."
|
|
|
|
# Setup SSH based on environment
|
|
mkdir -p ~/.ssh
|
|
if [ "${{ needs.validate-deployment.outputs.environment }}" = "staging" ]; then
|
|
echo "${{ secrets.STAGING_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
SSH_USER="${{ secrets.STAGING_SSH_USER }}"
|
|
SSH_HOST="${{ secrets.STAGING_HOST }}"
|
|
else
|
|
echo "${{ secrets.PRODUCTION_SSH_KEY }}" > ~/.ssh/id_rsa
|
|
SSH_USER="${{ secrets.PRODUCTION_SSH_USER }}"
|
|
SSH_HOST="${{ secrets.PRODUCTION_HOST }}"
|
|
fi
|
|
chmod 600 ~/.ssh/id_rsa
|
|
ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
|
|
|
|
ssh $SSH_USER@$SSH_HOST "
|
|
cd /tmp
|
|
|
|
# Remove backups older than retention period
|
|
find . -name 'hvac-plugin-${{ needs.validate-deployment.outputs.environment }}-*' -type f -mtime +$BACKUP_RETENTION_DAYS -delete
|
|
|
|
# Keep only the 5 most recent backups regardless of age
|
|
ls -t hvac-plugin-${{ needs.validate-deployment.outputs.environment }}-*-plugin.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm
|
|
ls -t hvac-plugin-${{ needs.validate-deployment.outputs.environment }}-*-db.sql.gz 2>/dev/null | tail -n +6 | xargs -r rm
|
|
|
|
echo '✅ Backup cleanup completed'
|
|
" |