mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 10:51:09 -05:00
feat: complete monorepo structure with frontend and shared resources
- Add complete backend/ directory with full Django application - Add frontend/ directory with Vite + TypeScript setup ready for Next.js - Add comprehensive shared/ directory with: - Complete documentation and memory-bank archives - Media files and avatars (letters, park/ride images) - Deployment scripts and automation tools - Shared types and utilities - Add architecture/ directory with migration guides - Configure pnpm workspace for monorepo development - Update .gitignore to exclude .django_tailwind_cli/ build artifacts - Preserve all historical documentation in shared/docs/memory-bank/ - Set up proper structure for full-stack development with shared resources
This commit is contained in:
340
shared/scripts/vm-deploy.sh
Executable file
340
shared/scripts/vm-deploy.sh
Executable file
@@ -0,0 +1,340 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ThrillWiki VM Deployment Script
|
||||
# This script runs on the Linux VM to deploy the latest code and restart the server
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
# Configuration
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
LOG_DIR="$PROJECT_DIR/logs"
|
||||
BACKUP_DIR="$PROJECT_DIR/backups"
|
||||
DEPLOY_LOG="$LOG_DIR/deploy.log"
|
||||
SERVICE_NAME="thrillwiki"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
local message="[$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
||||
echo -e "${BLUE}${message}${NC}"
|
||||
echo "$message" >> "$DEPLOY_LOG"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
local message="[$(date +'%Y-%m-%d %H:%M:%S')] ✓ $1"
|
||||
echo -e "${GREEN}${message}${NC}"
|
||||
echo "$message" >> "$DEPLOY_LOG"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
local message="[$(date +'%Y-%m-%d %H:%M:%S')] ⚠ $1"
|
||||
echo -e "${YELLOW}${message}${NC}"
|
||||
echo "$message" >> "$DEPLOY_LOG"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
local message="[$(date +'%Y-%m-%d %H:%M:%S')] ✗ $1"
|
||||
echo -e "${RED}${message}${NC}"
|
||||
echo "$message" >> "$DEPLOY_LOG"
|
||||
}
|
||||
|
||||
# Create necessary directories
|
||||
create_directories() {
|
||||
log "Creating necessary directories..."
|
||||
mkdir -p "$LOG_DIR" "$BACKUP_DIR"
|
||||
log_success "Directories created"
|
||||
}
|
||||
|
||||
# Backup current deployment
|
||||
backup_current() {
|
||||
log "Creating backup of current deployment..."
|
||||
local timestamp=$(date +'%Y%m%d_%H%M%S')
|
||||
local backup_path="$BACKUP_DIR/backup_$timestamp"
|
||||
|
||||
# Create backup of current code
|
||||
if [ -d "$PROJECT_DIR/.git" ]; then
|
||||
local current_commit=$(git -C "$PROJECT_DIR" rev-parse HEAD)
|
||||
echo "$current_commit" > "$backup_path.commit"
|
||||
log_success "Backup created with commit: ${current_commit:0:8}"
|
||||
else
|
||||
log_warning "Not a git repository, skipping backup"
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop the service
|
||||
stop_service() {
|
||||
log "Stopping ThrillWiki service..."
|
||||
|
||||
# Stop systemd service if it exists
|
||||
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||
sudo systemctl stop "$SERVICE_NAME"
|
||||
log_success "Systemd service stopped"
|
||||
else
|
||||
log "Systemd service not running"
|
||||
fi
|
||||
|
||||
# Kill any remaining Django processes on port 8000
|
||||
if lsof -ti :8000 >/dev/null 2>&1; then
|
||||
log "Stopping processes on port 8000..."
|
||||
lsof -ti :8000 | xargs kill -9 2>/dev/null || true
|
||||
log_success "Port 8000 processes stopped"
|
||||
fi
|
||||
|
||||
# Clean up Python cache
|
||||
log "Cleaning Python cache..."
|
||||
find "$PROJECT_DIR" -type d -name "__pycache__" -exec rm -r {} + 2>/dev/null || true
|
||||
log_success "Python cache cleaned"
|
||||
}
|
||||
|
||||
# Update code from git
|
||||
update_code() {
|
||||
log "Updating code from git repository..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Fetch latest changes
|
||||
git fetch origin
|
||||
log "Fetched latest changes"
|
||||
|
||||
# Get current and new commit info
|
||||
local old_commit=$(git rev-parse HEAD)
|
||||
local new_commit=$(git rev-parse origin/main)
|
||||
|
||||
if [ "$old_commit" = "$new_commit" ]; then
|
||||
log_warning "No new commits to deploy"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Updating from ${old_commit:0:8} to ${new_commit:0:8}"
|
||||
|
||||
# Pull latest changes
|
||||
git reset --hard origin/main
|
||||
log_success "Code updated successfully"
|
||||
|
||||
# Show what changed
|
||||
log "Changes in this deployment:"
|
||||
git log --oneline "$old_commit..$new_commit" || true
|
||||
}
|
||||
|
||||
# Install/update dependencies
|
||||
update_dependencies() {
|
||||
log "Updating dependencies..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Check if UV is installed
|
||||
if ! command -v uv &> /dev/null; then
|
||||
log_error "UV is not installed. Installing UV..."
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
source $HOME/.cargo/env
|
||||
fi
|
||||
|
||||
# Sync dependencies
|
||||
uv sync --no-dev || {
|
||||
log_error "Failed to sync dependencies"
|
||||
return 1
|
||||
}
|
||||
|
||||
log_success "Dependencies updated"
|
||||
}
|
||||
|
||||
# Run database migrations
|
||||
run_migrations() {
|
||||
log "Running database migrations..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Check for pending migrations
|
||||
if uv run manage.py showmigrations --plan | grep -q "\[ \]"; then
|
||||
log "Applying database migrations..."
|
||||
uv run manage.py migrate || {
|
||||
log_error "Database migrations failed"
|
||||
return 1
|
||||
}
|
||||
log_success "Database migrations completed"
|
||||
else
|
||||
log "No pending migrations"
|
||||
fi
|
||||
}
|
||||
|
||||
# Collect static files
|
||||
collect_static() {
|
||||
log "Collecting static files..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
uv run manage.py collectstatic --noinput || {
|
||||
log_warning "Static file collection failed, continuing..."
|
||||
}
|
||||
|
||||
log_success "Static files collected"
|
||||
}
|
||||
|
||||
# Start the service
|
||||
start_service() {
|
||||
log "Starting ThrillWiki service..."
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Start systemd service if it exists
|
||||
if systemctl list-unit-files | grep -q "^$SERVICE_NAME.service"; then
|
||||
sudo systemctl start "$SERVICE_NAME"
|
||||
sudo systemctl enable "$SERVICE_NAME"
|
||||
|
||||
# Wait for service to start
|
||||
sleep 5
|
||||
|
||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||
log_success "Systemd service started successfully"
|
||||
else
|
||||
log_error "Systemd service failed to start"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_warning "Systemd service not found, starting manually..."
|
||||
|
||||
# Start server in background
|
||||
nohup ./scripts/ci-start.sh > "$LOG_DIR/server.log" 2>&1 &
|
||||
local server_pid=$!
|
||||
|
||||
# Wait for server to start
|
||||
sleep 5
|
||||
|
||||
if kill -0 $server_pid 2>/dev/null; then
|
||||
echo $server_pid > "$LOG_DIR/server.pid"
|
||||
log_success "Server started manually with PID: $server_pid"
|
||||
else
|
||||
log_error "Failed to start server manually"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Health check
|
||||
health_check() {
|
||||
log "Performing health check..."
|
||||
|
||||
local max_attempts=30
|
||||
local attempt=1
|
||||
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
if curl -f -s http://localhost:8000/health >/dev/null 2>&1; then
|
||||
log_success "Health check passed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Health check attempt $attempt/$max_attempts failed, retrying..."
|
||||
sleep 2
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
log_error "Health check failed after $max_attempts attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Cleanup old backups
|
||||
cleanup_backups() {
|
||||
log "Cleaning up old backups..."
|
||||
|
||||
# Keep only the last 10 backups
|
||||
cd "$BACKUP_DIR"
|
||||
ls -t backup_*.commit 2>/dev/null | tail -n +11 | xargs rm -f 2>/dev/null || true
|
||||
|
||||
log_success "Old backups cleaned up"
|
||||
}
|
||||
|
||||
# Rollback function
|
||||
rollback() {
|
||||
log_error "Deployment failed, attempting rollback..."
|
||||
|
||||
local latest_backup=$(ls -t "$BACKUP_DIR"/backup_*.commit 2>/dev/null | head -n 1)
|
||||
|
||||
if [ -n "$latest_backup" ]; then
|
||||
local backup_commit=$(cat "$latest_backup")
|
||||
log "Rolling back to commit: ${backup_commit:0:8}"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
git reset --hard "$backup_commit"
|
||||
|
||||
# Restart service
|
||||
stop_service
|
||||
start_service
|
||||
|
||||
if health_check; then
|
||||
log_success "Rollback completed successfully"
|
||||
else
|
||||
log_error "Rollback failed - manual intervention required"
|
||||
fi
|
||||
else
|
||||
log_error "No backup found for rollback"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main deployment function
|
||||
deploy() {
|
||||
log "=== ThrillWiki Deployment Started ==="
|
||||
log "Timestamp: $(date)"
|
||||
log "User: $(whoami)"
|
||||
log "Host: $(hostname)"
|
||||
|
||||
# Trap errors for rollback
|
||||
trap rollback ERR
|
||||
|
||||
create_directories
|
||||
backup_current
|
||||
stop_service
|
||||
update_code
|
||||
update_dependencies
|
||||
run_migrations
|
||||
collect_static
|
||||
start_service
|
||||
health_check
|
||||
cleanup_backups
|
||||
|
||||
# Remove error trap
|
||||
trap - ERR
|
||||
|
||||
log_success "=== Deployment Completed Successfully ==="
|
||||
log "Server is now running the latest code"
|
||||
log "Check logs at: $LOG_DIR/"
|
||||
}
|
||||
|
||||
# Script execution
|
||||
case "${1:-deploy}" in
|
||||
deploy)
|
||||
deploy
|
||||
;;
|
||||
stop)
|
||||
stop_service
|
||||
;;
|
||||
start)
|
||||
start_service
|
||||
;;
|
||||
restart)
|
||||
stop_service
|
||||
start_service
|
||||
health_check
|
||||
;;
|
||||
status)
|
||||
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||
echo "Service is running"
|
||||
elif [ -f "$LOG_DIR/server.pid" ] && kill -0 "$(cat "$LOG_DIR/server.pid")" 2>/dev/null; then
|
||||
echo "Server is running manually"
|
||||
else
|
||||
echo "Service is not running"
|
||||
fi
|
||||
;;
|
||||
health)
|
||||
health_check
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {deploy|stop|start|restart|status|health}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user