#!/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 ""