- Updated `README.md` to include instructions for the new `redeploy-ubuntu.sh` script and added a link to the new `REDEPLOY_GUIDE.md`. - Created `REDEPLOY_GUIDE.md` detailing the redeployment process, including backup creation, code updates, and troubleshooting steps. - Introduced `redeploy-hint.md` for GitHub Actions automation example, outlining setup for automatic redeployment on push events. - Improved documentation structure for better navigation and clarity.
		
			
				
	
	
		
			306 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| #!/usr/bin/env bash
 | ||
| 
 | ||
| ###############################################################################
 | ||
| # AI Code Review Agent - Redeploy Script для Ubuntu/Debian
 | ||
| ###############################################################################
 | ||
| #
 | ||
| # Этот скрипт обновляет и перезапускает AI Review Agent на сервере
 | ||
| #
 | ||
| # Использование:
 | ||
| #   sudo bash redeploy-ubuntu.sh
 | ||
| #   или
 | ||
| #   sudo ./redeploy-ubuntu.sh
 | ||
| #
 | ||
| ###############################################################################
 | ||
| 
 | ||
| # Проверка, что используется bash
 | ||
| if [ -z "$BASH_VERSION" ]; then
 | ||
|     echo "ERROR: Этот скрипт требует bash. Запустите: sudo bash redeploy-ubuntu.sh"
 | ||
|     exit 1
 | ||
| fi
 | ||
| 
 | ||
| set -e  # Выход при ошибке
 | ||
| 
 | ||
| # Цвета для вывода
 | ||
| RED='\033[0;31m'
 | ||
| GREEN='\033[0;32m'
 | ||
| YELLOW='\033[1;33m'
 | ||
| BLUE='\033[0;34m'
 | ||
| NC='\033[0m' # No Color
 | ||
| 
 | ||
| # Функции для красивого вывода
 | ||
| print_step() {
 | ||
|     echo -e "\n${BLUE}[STEP $1/$2]${NC} $3"
 | ||
| }
 | ||
| 
 | ||
| print_success() {
 | ||
|     echo -e "${GREEN}[OK]${NC} $1"
 | ||
| }
 | ||
| 
 | ||
| print_error() {
 | ||
|     echo -e "${RED}[ERROR]${NC} $1"
 | ||
| }
 | ||
| 
 | ||
| print_warning() {
 | ||
|     echo -e "${YELLOW}[WARNING]${NC} $1"
 | ||
| }
 | ||
| 
 | ||
| print_header() {
 | ||
|     echo -e "\n${GREEN}╔════════════════════════════════════════╗${NC}"
 | ||
|     echo -e "${GREEN}║   AI Review Agent - Redeploy           ║${NC}"
 | ||
|     echo -e "${GREEN}╚════════════════════════════════════════╝${NC}\n"
 | ||
| }
 | ||
| 
 | ||
| # Проверка прав root
 | ||
| if [ "$EUID" -ne 0 ]; then 
 | ||
|     print_error "Запустите скрипт с sudo"
 | ||
|     exit 1
 | ||
| fi
 | ||
| 
 | ||
| print_header
 | ||
| 
 | ||
| # Определить пользователя, который запустил sudo
 | ||
| REAL_USER="${SUDO_USER:-$USER}"
 | ||
| if [ "$REAL_USER" = "root" ]; then
 | ||
|     print_error "Не запускайте этот скрипт напрямую из-под root. Используйте sudo от обычного пользователя."
 | ||
|     exit 1
 | ||
| fi
 | ||
| 
 | ||
| # Определить директорию установки
 | ||
| # Если скрипт запущен из текущей директории, используем её
 | ||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 | ||
| INSTALL_DIR="${SCRIPT_DIR}"
 | ||
| SERVICE_NAME="ai-review"
 | ||
| 
 | ||
| # Проверить, что это похоже на директорию AI Review
 | ||
| if [ ! -d "$INSTALL_DIR/backend" ] || [ ! -d "$INSTALL_DIR/frontend" ]; then
 | ||
|     print_error "Не найдены директории backend или frontend"
 | ||
|     print_warning "Запустите скрипт из корня проекта AI Review Agent"
 | ||
|     exit 1
 | ||
| fi
 | ||
| 
 | ||
| # Проверка, что сервис установлен
 | ||
| if ! systemctl list-unit-files | grep -q "^${SERVICE_NAME}.service"; then
 | ||
|     print_warning "Сервис ${SERVICE_NAME} не найден в systemd"
 | ||
|     print_warning "Продолжаем без управления сервисом..."
 | ||
|     SERVICE_EXISTS=false
 | ||
| else
 | ||
|     SERVICE_EXISTS=true
 | ||
| fi
 | ||
| 
 | ||
| cd "$INSTALL_DIR"
 | ||
| print_warning "Рабочая директория: $INSTALL_DIR"
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Шаг 1: Остановка сервиса
 | ||
| # ============================================================================
 | ||
| print_step 1 7 "Остановка сервиса..."
 | ||
| 
 | ||
| if [ "$SERVICE_EXISTS" = true ]; then
 | ||
|     systemctl stop "$SERVICE_NAME" || print_warning "Не удалось остановить сервис"
 | ||
|     print_success "Сервис остановлен"
 | ||
| else
 | ||
|     print_warning "Сервис не установлен, пропускаем остановку"
 | ||
| fi
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Шаг 2: Создание backup
 | ||
| # ============================================================================
 | ||
| print_step 2 7 "Создание backup..."
 | ||
| 
 | ||
| BACKUP_DIR="$INSTALL_DIR/backups"
 | ||
| mkdir -p "$BACKUP_DIR" || print_warning "Не удалось создать директорию backup"
 | ||
| BACKUP_NAME="backup-$(date +%Y%m%d-%H%M%S)"
 | ||
| BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"
 | ||
| 
 | ||
| # Backup базы данных
 | ||
| if [ -f "$INSTALL_DIR/backend/review.db" ]; then
 | ||
|     mkdir -p "$BACKUP_PATH"
 | ||
|     cp "$INSTALL_DIR/backend/review.db" "$BACKUP_PATH/" 2>/dev/null || {
 | ||
|         print_warning "Не удалось создать backup БД"
 | ||
|     }
 | ||
|     if [ -f "$BACKUP_PATH/review.db" ]; then
 | ||
|         print_success "База данных сохранена в $BACKUP_PATH"
 | ||
|     fi
 | ||
| else
 | ||
|     print_warning "База данных не найдена, пропускаем backup"
 | ||
| fi
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Шаг 3: Обновление кода
 | ||
| # ============================================================================
 | ||
| print_step 3 7 "Обновление кода..."
 | ||
| 
 | ||
| # Проверка, что это git репозиторий
 | ||
| if [ -d ".git" ]; then
 | ||
|     # Сохранить изменения в .env если есть
 | ||
|     if [ -f "backend/.env" ]; then
 | ||
|         cp backend/.env /tmp/ai-review-env-backup 2>/dev/null || true
 | ||
|     fi
 | ||
|     
 | ||
|     # Получить текущую ветку
 | ||
|     CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
 | ||
|     print_warning "Текущая ветка: $CURRENT_BRANCH"
 | ||
|     
 | ||
|     # Обновить код
 | ||
|     sudo -u "$REAL_USER" git fetch --all 2>/dev/null || print_warning "Не удалось обновить из git"
 | ||
|     sudo -u "$REAL_USER" git pull origin "$CURRENT_BRANCH" 2>/dev/null || print_warning "Не удалось выполнить git pull"
 | ||
|     
 | ||
|     # Восстановить .env
 | ||
|     if [ -f "/tmp/ai-review-env-backup" ]; then
 | ||
|         cp /tmp/ai-review-env-backup backend/.env 2>/dev/null || true
 | ||
|         rm /tmp/ai-review-env-backup 2>/dev/null || true
 | ||
|     fi
 | ||
|     
 | ||
|     print_success "Код обновлен"
 | ||
| else
 | ||
|     print_warning "Не git репозиторий, пропускаем обновление кода"
 | ||
|     print_warning "Предполагается, что код уже обновлен вручную"
 | ||
|     sleep 2
 | ||
| fi
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Шаг 4: Обновление зависимостей Backend
 | ||
| # ============================================================================
 | ||
| print_step 4 7 "Обновление зависимостей Backend..."
 | ||
| 
 | ||
| cd backend
 | ||
| 
 | ||
| # Активировать venv и установить зависимости
 | ||
| if [ -d "venv" ]; then
 | ||
|     sudo -u "$REAL_USER" bash -c "
 | ||
|         source venv/bin/activate
 | ||
|         pip install --upgrade pip > /dev/null 2>&1
 | ||
|         pip install -r requirements.txt > /dev/null 2>&1
 | ||
|     "
 | ||
|     print_success "Зависимости Backend обновлены"
 | ||
| else
 | ||
|     print_error "Virtual environment не найден"
 | ||
|     exit 1
 | ||
| fi
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Шаг 5: Применение миграций БД
 | ||
| # ============================================================================
 | ||
| print_step 5 7 "Применение миграций БД..."
 | ||
| 
 | ||
| if [ -f "migrate.py" ]; then
 | ||
|     sudo -u "$REAL_USER" bash -c "
 | ||
|         source venv/bin/activate
 | ||
|         python migrate.py
 | ||
|     " 2>&1 | grep -E "(✅|Таблицы|создан)" || true
 | ||
|     print_success "Миграции применены"
 | ||
| else
 | ||
|     print_warning "Скрипт миграции не найден, пропускаем"
 | ||
| fi
 | ||
| 
 | ||
| cd ..
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Шаг 6: Сборка Frontend
 | ||
| # ============================================================================
 | ||
| print_step 6 7 "Сборка Frontend..."
 | ||
| 
 | ||
| cd frontend
 | ||
| 
 | ||
| # Проверить наличие Node.js
 | ||
| if ! command -v node &> /dev/null; then
 | ||
|     print_error "Node.js не установлен"
 | ||
|     exit 1
 | ||
| fi
 | ||
| 
 | ||
| # Установить зависимости если нужно
 | ||
| if [ ! -d "node_modules" ]; then
 | ||
|     print_warning "Установка зависимостей..."
 | ||
|     sudo -u "$REAL_USER" npm install > /dev/null 2>&1
 | ||
| fi
 | ||
| 
 | ||
| # Создать .env.production для правильных URL
 | ||
| cat > .env.production << EOF
 | ||
| VITE_API_URL=/api
 | ||
| VITE_WS_URL=
 | ||
| EOF
 | ||
| 
 | ||
| # Собрать frontend
 | ||
| sudo -u "$REAL_USER" npm run build 2>&1 | grep -E "(✓|built in)" || true
 | ||
| print_success "Frontend собран"
 | ||
| 
 | ||
| # Проверить, что build создан
 | ||
| if [ ! -d "../backend/public" ]; then
 | ||
|     print_error "Frontend не собрался в backend/public"
 | ||
|     exit 1
 | ||
| fi
 | ||
| 
 | ||
| cd ..
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Шаг 7: Запуск сервиса
 | ||
| # ============================================================================
 | ||
| print_step 7 7 "Запуск сервиса..."
 | ||
| 
 | ||
| # Установить правильные права
 | ||
| chown -R "$REAL_USER:$REAL_USER" "$INSTALL_DIR" 2>/dev/null || print_warning "Не удалось установить права"
 | ||
| 
 | ||
| if [ "$SERVICE_EXISTS" = true ]; then
 | ||
|     # Запустить сервис
 | ||
|     systemctl start "$SERVICE_NAME"
 | ||
|     
 | ||
|     # Подождать немного
 | ||
|     sleep 2
 | ||
|     
 | ||
|     # Проверить статус
 | ||
|     if systemctl is-active --quiet "$SERVICE_NAME"; then
 | ||
|         print_success "Сервис запущен"
 | ||
|     else
 | ||
|         print_error "Сервис не запустился"
 | ||
|         echo ""
 | ||
|         echo "Логи сервиса:"
 | ||
|         journalctl -u "$SERVICE_NAME" -n 20 --no-pager
 | ||
|         exit 1
 | ||
|     fi
 | ||
| else
 | ||
|     print_warning "Сервис не установлен в systemd"
 | ||
|     print_warning "Запустите вручную: cd backend && source venv/bin/activate && uvicorn app.main:app --host 0.0.0.0 --port 8000"
 | ||
| fi
 | ||
| 
 | ||
| # ============================================================================
 | ||
| # Финал
 | ||
| # ============================================================================
 | ||
| echo ""
 | ||
| echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
 | ||
| echo -e "${GREEN}║   Redeploy завершен успешно! ✅        ║${NC}"
 | ||
| echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
 | ||
| echo ""
 | ||
| 
 | ||
| # Получить IP адрес
 | ||
| SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
 | ||
| if [ -z "$SERVER_IP" ]; then
 | ||
|     SERVER_IP="localhost"
 | ||
| fi
 | ||
| 
 | ||
| echo "Сервис: http://${SERVER_IP}:8000"
 | ||
| if [ "$SERVICE_EXISTS" = true ]; then
 | ||
|     echo "Статус: systemctl status $SERVICE_NAME"
 | ||
|     echo "Логи:   journalctl -u $SERVICE_NAME -f"
 | ||
| else
 | ||
|     echo "Запуск: cd $INSTALL_DIR/backend && source venv/bin/activate && uvicorn app.main:app --host 0.0.0.0 --port 8000"
 | ||
| fi
 | ||
| echo ""
 | ||
| 
 | ||
| if [ -f "$BACKUP_PATH/review.db" ]; then
 | ||
|     echo "Backup создан: $BACKUP_PATH"
 | ||
|     echo ""
 | ||
|     echo -e "${YELLOW}Для отката к предыдущей версии:${NC}"
 | ||
|     echo "  1. Остановите сервис"
 | ||
|     if [ -d ".git" ]; then
 | ||
|         echo "  2. Восстановите БД: sudo cp $BACKUP_PATH/review.db $INSTALL_DIR/backend/"
 | ||
|         echo "  3. Откатите git: cd $INSTALL_DIR && git reset --hard HEAD~1"
 | ||
|         echo "  4. Запустите redeploy снова: cd $INSTALL_DIR && sudo bash redeploy-ubuntu.sh"
 | ||
|     else
 | ||
|         echo "  2. Восстановите БД: sudo cp $BACKUP_PATH/review.db $INSTALL_DIR/backend/"
 | ||
|         echo "  3. Восстановите старые файлы вручную"
 | ||
|     fi
 | ||
| fi
 | ||
| echo ""
 | ||
| 
 |