Initial commit
This commit is contained in:
352
skills/symfony-skill/scripts/deploy.sh
Normal file
352
skills/symfony-skill/scripts/deploy.sh
Normal file
@@ -0,0 +1,352 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Symfony Deployment Script
|
||||
# Usage: ./deploy.sh [environment] [branch]
|
||||
# Example: ./deploy.sh production main
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
ENVIRONMENT=${1:-production}
|
||||
BRANCH=${2:-main}
|
||||
PROJECT_PATH="/var/www/symfony-app"
|
||||
BACKUP_PATH="/var/backups/symfony-app"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
check_requirements() {
|
||||
log_info "Checking requirements..."
|
||||
|
||||
# Check if PHP is installed
|
||||
if ! command -v php &> /dev/null; then
|
||||
log_error "PHP is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if Composer is installed
|
||||
if ! command -v composer &> /dev/null; then
|
||||
log_error "Composer is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if Git is installed
|
||||
if ! command -v git &> /dev/null; then
|
||||
log_error "Git is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check PHP version
|
||||
PHP_VERSION=$(php -r "echo PHP_VERSION;")
|
||||
MIN_PHP_VERSION="8.1.0"
|
||||
|
||||
if [ "$(printf '%s\n' "$MIN_PHP_VERSION" "$PHP_VERSION" | sort -V | head -n1)" != "$MIN_PHP_VERSION" ]; then
|
||||
log_error "PHP version must be at least $MIN_PHP_VERSION (current: $PHP_VERSION)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "All requirements met"
|
||||
}
|
||||
|
||||
create_backup() {
|
||||
log_info "Creating backup..."
|
||||
|
||||
# Create backup directory if it doesn't exist
|
||||
mkdir -p "$BACKUP_PATH"
|
||||
|
||||
# Backup database
|
||||
if [ -f "$PROJECT_PATH/.env.local" ]; then
|
||||
source "$PROJECT_PATH/.env.local"
|
||||
|
||||
if [ ! -z "$DATABASE_URL" ]; then
|
||||
# Parse database URL
|
||||
DB_USER=$(echo $DATABASE_URL | sed -E 's/.*:\/\/([^:]+):.*/\1/')
|
||||
DB_PASS=$(echo $DATABASE_URL | sed -E 's/.*:\/\/[^:]+:([^@]+)@.*/\1/')
|
||||
DB_HOST=$(echo $DATABASE_URL | sed -E 's/.*@([^:\/]+).*/\1/')
|
||||
DB_NAME=$(echo $DATABASE_URL | sed -E 's/.*\///')
|
||||
|
||||
mysqldump -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$BACKUP_PATH/db_backup_$TIMESTAMP.sql"
|
||||
log_info "Database backup created: db_backup_$TIMESTAMP.sql"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Backup files
|
||||
tar -czf "$BACKUP_PATH/files_backup_$TIMESTAMP.tar.gz" \
|
||||
-C "$PROJECT_PATH" \
|
||||
--exclude=var/cache \
|
||||
--exclude=var/log \
|
||||
--exclude=vendor \
|
||||
--exclude=node_modules \
|
||||
.
|
||||
|
||||
log_info "Files backup created: files_backup_$TIMESTAMP.tar.gz"
|
||||
|
||||
# Keep only last 5 backups
|
||||
ls -1dt "$BACKUP_PATH"/* | tail -n +11 | xargs -r rm -f
|
||||
}
|
||||
|
||||
pull_latest_code() {
|
||||
log_info "Pulling latest code from $BRANCH branch..."
|
||||
|
||||
cd "$PROJECT_PATH"
|
||||
|
||||
# Stash any local changes
|
||||
git stash
|
||||
|
||||
# Fetch latest changes
|
||||
git fetch origin
|
||||
|
||||
# Checkout and pull the specified branch
|
||||
git checkout "$BRANCH"
|
||||
git pull origin "$BRANCH"
|
||||
|
||||
log_info "Code updated to latest version"
|
||||
}
|
||||
|
||||
install_dependencies() {
|
||||
log_info "Installing dependencies..."
|
||||
|
||||
cd "$PROJECT_PATH"
|
||||
|
||||
# Install Composer dependencies
|
||||
if [ "$ENVIRONMENT" = "production" ]; then
|
||||
composer install --no-dev --optimize-autoloader --no-interaction
|
||||
else
|
||||
composer install --optimize-autoloader --no-interaction
|
||||
fi
|
||||
|
||||
# Install NPM dependencies if package.json exists
|
||||
if [ -f "package.json" ]; then
|
||||
npm ci
|
||||
|
||||
# Build assets
|
||||
if [ "$ENVIRONMENT" = "production" ]; then
|
||||
npm run build
|
||||
else
|
||||
npm run dev
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Dependencies installed"
|
||||
}
|
||||
|
||||
run_migrations() {
|
||||
log_info "Running database migrations..."
|
||||
|
||||
cd "$PROJECT_PATH"
|
||||
|
||||
# Check if there are pending migrations
|
||||
PENDING=$(php bin/console doctrine:migrations:status --show-versions | grep "not migrated" | wc -l)
|
||||
|
||||
if [ "$PENDING" -gt 0 ]; then
|
||||
log_info "Found $PENDING pending migration(s)"
|
||||
|
||||
# Run migrations
|
||||
php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration
|
||||
|
||||
log_info "Migrations completed"
|
||||
else
|
||||
log_info "No pending migrations"
|
||||
fi
|
||||
}
|
||||
|
||||
clear_cache() {
|
||||
log_info "Clearing cache..."
|
||||
|
||||
cd "$PROJECT_PATH"
|
||||
|
||||
# Clear Symfony cache
|
||||
php bin/console cache:clear --env="$ENVIRONMENT" --no-warmup
|
||||
php bin/console cache:warmup --env="$ENVIRONMENT"
|
||||
|
||||
# Clear OPcache if available
|
||||
if command -v cachetool &> /dev/null; then
|
||||
cachetool opcache:reset
|
||||
log_info "OPcache cleared"
|
||||
fi
|
||||
|
||||
log_info "Cache cleared and warmed up"
|
||||
}
|
||||
|
||||
update_permissions() {
|
||||
log_info "Updating file permissions..."
|
||||
|
||||
cd "$PROJECT_PATH"
|
||||
|
||||
# Set proper permissions for var directory
|
||||
chmod -R 775 var/
|
||||
|
||||
# Set proper ownership (adjust user:group as needed)
|
||||
if [ ! -z "$WEB_USER" ]; then
|
||||
chown -R "$WEB_USER":"$WEB_USER" var/
|
||||
fi
|
||||
|
||||
log_info "Permissions updated"
|
||||
}
|
||||
|
||||
run_tests() {
|
||||
log_info "Running tests..."
|
||||
|
||||
cd "$PROJECT_PATH"
|
||||
|
||||
# Run PHPUnit tests if they exist
|
||||
if [ -f "bin/phpunit" ] || [ -f "vendor/bin/phpunit" ]; then
|
||||
if [ "$ENVIRONMENT" != "production" ]; then
|
||||
php bin/phpunit --testdox || {
|
||||
log_error "Tests failed! Deployment aborted."
|
||||
exit 1
|
||||
}
|
||||
log_info "All tests passed"
|
||||
else
|
||||
log_warning "Skipping tests in production environment"
|
||||
fi
|
||||
else
|
||||
log_warning "PHPUnit not found, skipping tests"
|
||||
fi
|
||||
}
|
||||
|
||||
restart_services() {
|
||||
log_info "Restarting services..."
|
||||
|
||||
# Restart PHP-FPM
|
||||
if systemctl is-active --quiet php8.1-fpm; then
|
||||
systemctl reload php8.1-fpm
|
||||
log_info "PHP-FPM reloaded"
|
||||
fi
|
||||
|
||||
# Restart web server
|
||||
if systemctl is-active --quiet nginx; then
|
||||
systemctl reload nginx
|
||||
log_info "Nginx reloaded"
|
||||
elif systemctl is-active --quiet apache2; then
|
||||
systemctl reload apache2
|
||||
log_info "Apache reloaded"
|
||||
fi
|
||||
|
||||
# Restart queue workers if Messenger is used
|
||||
if systemctl is-active --quiet symfony-messenger; then
|
||||
systemctl restart symfony-messenger
|
||||
log_info "Messenger workers restarted"
|
||||
fi
|
||||
}
|
||||
|
||||
health_check() {
|
||||
log_info "Performing health check..."
|
||||
|
||||
cd "$PROJECT_PATH"
|
||||
|
||||
# Check if the application responds
|
||||
if [ ! -z "$APP_URL" ]; then
|
||||
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$APP_URL/health-check")
|
||||
|
||||
if [ "$HTTP_STATUS" -eq 200 ]; then
|
||||
log_info "Health check passed (HTTP $HTTP_STATUS)"
|
||||
else
|
||||
log_error "Health check failed (HTTP $HTTP_STATUS)"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check database connection
|
||||
php bin/console doctrine:query:sql "SELECT 1" > /dev/null 2>&1 || {
|
||||
log_error "Database connection failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
log_info "All health checks passed"
|
||||
}
|
||||
|
||||
notify_deployment() {
|
||||
MESSAGE="$1"
|
||||
|
||||
# Send notification (configure your notification method)
|
||||
# Example: Slack webhook
|
||||
if [ ! -z "$SLACK_WEBHOOK" ]; then
|
||||
curl -X POST -H 'Content-type: application/json' \
|
||||
--data "{\"text\":\"Deployment: $MESSAGE\"}" \
|
||||
"$SLACK_WEBHOOK"
|
||||
fi
|
||||
|
||||
# Log to deployment log
|
||||
echo "[$(date)] $MESSAGE" >> "$PROJECT_PATH/var/log/deployments.log"
|
||||
}
|
||||
|
||||
rollback() {
|
||||
log_error "Deployment failed! Rolling back..."
|
||||
|
||||
# Restore database from backup
|
||||
if [ -f "$BACKUP_PATH/db_backup_$TIMESTAMP.sql" ]; then
|
||||
mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$BACKUP_PATH/db_backup_$TIMESTAMP.sql"
|
||||
log_info "Database restored from backup"
|
||||
fi
|
||||
|
||||
# Restore files from backup
|
||||
if [ -f "$BACKUP_PATH/files_backup_$TIMESTAMP.tar.gz" ]; then
|
||||
rm -rf "$PROJECT_PATH"/*
|
||||
tar -xzf "$BACKUP_PATH/files_backup_$TIMESTAMP.tar.gz" -C "$PROJECT_PATH"
|
||||
log_info "Files restored from backup"
|
||||
fi
|
||||
|
||||
clear_cache
|
||||
restart_services
|
||||
|
||||
notify_deployment "❌ Deployment failed and rolled back on $ENVIRONMENT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Main deployment process
|
||||
main() {
|
||||
log_info "========================================="
|
||||
log_info "Starting Symfony deployment"
|
||||
log_info "Environment: $ENVIRONMENT"
|
||||
log_info "Branch: $BRANCH"
|
||||
log_info "Timestamp: $TIMESTAMP"
|
||||
log_info "========================================="
|
||||
|
||||
# Set error trap
|
||||
trap rollback ERR
|
||||
|
||||
# Execute deployment steps
|
||||
check_requirements
|
||||
create_backup
|
||||
pull_latest_code
|
||||
install_dependencies
|
||||
run_migrations
|
||||
clear_cache
|
||||
update_permissions
|
||||
run_tests
|
||||
restart_services
|
||||
health_check
|
||||
|
||||
# Remove error trap after successful deployment
|
||||
trap - ERR
|
||||
|
||||
log_info "========================================="
|
||||
log_info "Deployment completed successfully!"
|
||||
log_info "========================================="
|
||||
|
||||
notify_deployment "✅ Successfully deployed to $ENVIRONMENT from $BRANCH"
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
|
||||
# Exit successfully
|
||||
exit 0
|
||||
Reference in New Issue
Block a user