🔧 Restructure scripts and add CLI tool

 New features:
- Add CLI tool for container command execution
- Reorganize all scripts into bin/ directory
- Create convenient wrappers in project root
- Add local changes auto-commit functionality
- Enhanced backup repository management

📁 Structure changes:
- Move all scripts to bin/ directory
- Create wrapper scripts in root (cli, update, start, stop, logs)
- Add setup-backup.sh for backup repository management
- Update documentation with new CLI examples

🛠️ CLI capabilities:
- Django commands (shell, migrate, collectstatic, etc.)
- System commands (bash, logs, status)
- Container management (restart, status)
- Interactive and non-interactive modes

📚 Documentation:
- Updated SCRIPTS_README.md with CLI examples
- Added troubleshooting section
- Comprehensive usage examples
This commit is contained in:
2025-11-25 06:51:52 +09:00
parent bd028d09e6
commit 8f1e0459fc
22 changed files with 618 additions and 64 deletions

370
bin/update.sh Executable file
View File

@@ -0,0 +1,370 @@
#!/bin/bash
# =============================================================================
# SmartSolTech - Скрипт автоматического обновления
# =============================================================================
set -e # Выход при любой ошибке
# Цвета для вывода
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Функция для логирования
log() {
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
success() {
echo -e "${GREEN}$1${NC}"
}
warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
error() {
echo -e "${RED}$1${NC}"
}
# Функция проверки зависимостей
check_dependencies() {
log "Проверка зависимостей..."
if ! command -v git &> /dev/null; then
error "Git не установлен"
exit 1
fi
if ! command -v docker &> /dev/null; then
error "Docker не установлен"
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
error "Docker Compose не установлен"
exit 1
fi
success "Все зависимости найдены"
}
# Функция очистки staticfiles
cleanup_staticfiles() {
log "Очистка staticfiles..."
if [ -d "smartsoltech/staticfiles" ]; then
warning "Найдена папка staticfiles, удаляем..."
chmod -R 755 smartsoltech/staticfiles 2>/dev/null || true
rm -rf smartsoltech/staticfiles
success "Staticfiles очищены"
fi
}
# Функция сохранения локальных изменений
save_local_changes() {
log "Проверка локальных изменений..."
# Проверяем есть ли изменения в рабочей директории или индексе
if [ -n "$(git status --porcelain)" ]; then
warning "Обнаружены локальные изменения, сохраняем в коммит..."
# Добавляем все изменения
git add .
# Создаем коммит с временной меткой
local commit_msg="Auto commit before update $(date '+%Y-%m-%d %H:%M:%S')"
if git commit -m "$commit_msg"; then
success "Локальные изменения сохранены в коммит"
log "Коммит: $commit_msg"
else
warning "Не удалось создать коммит (возможно нет изменений для коммита)"
fi
else
log "Локальных изменений не обнаружено"
fi
}
update_code() {
local remote_name="${1:-origin}"
log "Обновление кода из репозитория $remote_name..."
# Проверяем существование удаленного репозитория
if ! git remote | grep -q "^${remote_name}$"; then
error "Удаленный репозиторий '$remote_name' не найден"
log "Доступные репозитории:"
git remote -v
return 1
fi
# Настраиваем стратегию pull если не настроено
if [ -z "$(git config pull.rebase 2>/dev/null)" ]; then
log "Настраиваем стратегию Git pull..."
git config pull.rebase false
fi
# Получаем обновления
log "Получение обновлений из $remote_name..."
git fetch $remote_name
# Обновляем текущую ветку
local current_branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
# Пробуем обновить с обработкой конфликтов
if ! git pull $remote_name $current_branch; then
error "Не удалось обновить код. Возможно есть конфликты."
log "Попробуйте выполнить команды вручную:"
log " git status"
log " git merge --abort # если нужно отменить"
log " git pull $remote_name $current_branch"
return 1
fi
success "Код обновлен с ветки $current_branch из $remote_name"
}
# Функция остановки контейнеров
stop_containers() {
log "Остановка контейнеров..."
if docker-compose ps | grep -q "Up"; then
docker-compose down
success "Контейнеры остановлены"
else
warning "Контейнеры уже остановлены"
fi
}
# Функция сборки образов
build_images() {
log "Сборка Docker образов..."
# Принудительная пересборка
docker-compose build --no-cache
success "Образы собраны"
}
# Функция запуска контейнеров
start_containers() {
log "Запуск контейнеров..."
# Запуск в фоновом режиме
docker-compose up -d
# Ожидание готовности
log "Ожидание готовности сервисов..."
sleep 10
# Проверка статуса
if docker-compose ps | grep -q "Exit"; then
error "Некоторые контейнеры завершились с ошибкой"
docker-compose ps
return 1
fi
success "Контейнеры запущены"
}
# Функция выполнения миграций
run_migrations() {
log "Выполнение миграций Django..."
# Ожидание готовности БД
log "Ожидание готовности базы данных..."
sleep 15
# Выполнение миграций
docker-compose exec -T web python smartsoltech/manage.py migrate
success "Миграции выполнены"
}
# Функция сбора статических файлов
collect_static() {
log "Сбор статических файлов..."
docker-compose exec -T web python smartsoltech/manage.py collectstatic --noinput
success "Статические файлы собраны"
}
# Функция проверки состояния сервисов
health_check() {
log "Проверка состояния сервисов..."
# Проверка веб-сервера
local max_attempts=30
local attempt=1
while [ $attempt -le $max_attempts ]; do
if curl -sf http://localhost:8000/ > /dev/null 2>&1; then
success "Веб-сервер доступен"
break
fi
if [ $attempt -eq $max_attempts ]; then
error "Веб-сервер недоступен после $max_attempts попыток"
return 1
fi
log "Попытка $attempt/$max_attempts - ожидание веб-сервера..."
sleep 5
((attempt++))
done
# Показать статус контейнеров
echo ""
log "Статус контейнеров:"
docker-compose ps
success "Проверка здоровья завершена"
}
# Функция отображения логов
show_logs() {
log "Последние логи сервисов:"
echo ""
docker-compose logs --tail=20 web
}
# Функция бэкапа в удаленный репозиторий
backup_to_remote() {
local backup_remote="${1:-backup}"
# Пропускаем если это тот же репозиторий что используется для обновления
local update_remote="${2:-origin}"
if [ "$backup_remote" = "$update_remote" ]; then
log "Пропускаем бэкап - используется тот же репозиторий для обновления"
return 0
fi
log "Создание бэкапа в удаленном репозитории $backup_remote..."
if git remote | grep -q "^${backup_remote}$"; then
# Пушим текущее состояние в backup (изменения уже сохранены в коммит)
if git push $backup_remote master; then
success "Бэкап создан в удаленном репозитории $backup_remote"
else
warning "Не удалось создать бэкап в $backup_remote"
fi
else
warning "$backup_remote репозиторий не настроен, пропускаем бэкап"
fi
}
# Главная функция
main() {
local remote_source="${1:-origin}"
local backup_remote="${2:-backup}"
echo ""
echo "🚀 SmartSolTech - Автоматическое обновление"
echo "=========================================="
echo "📡 Источник: $remote_source"
if git remote | grep -q "^${backup_remote}$"; then
echo "💾 Бэкап: $backup_remote"
fi
echo ""
# Проверка что мы в правильной директории
if [ ! -f "docker-compose.yml" ]; then
error "docker-compose.yml не найден. Запустите скрипт из корня проекта."
exit 1
fi
local start_time
start_time=$(date +%s)
# Выполняем все этапы
check_dependencies
save_local_changes
backup_to_remote "$backup_remote" "$remote_source"
cleanup_staticfiles
update_code "$remote_source"
stop_containers
build_images
start_containers
run_migrations
collect_static
health_check
local end_time
end_time=$(date +%s)
local duration=$((end_time - start_time))
echo ""
echo "🎉 Обновление завершено успешно!"
echo "⏱️ Время выполнения: ${duration} секунд"
echo "📡 Источник обновления: $remote_source"
echo ""
echo "📊 Полезная информация:"
echo " • Веб-сайт: http://localhost:8000"
echo " • Админка: http://localhost:8000/admin"
echo " • PgAdmin: http://localhost:8080"
echo ""
# Предложение показать логи
read -p "Показать логи сервисов? (y/N): " show_logs_choice
if [[ $show_logs_choice =~ ^[Yy]$ ]]; then
show_logs
fi
success "Готово!"
}
# Обработка прерываний
trap 'echo ""; error "Обновление прервано пользователем"; exit 130' INT TERM
# Обработка ошибок
error_handler() {
local line_no=$1
error "Ошибка на строке $line_no"
echo ""
echo "Для диагностики можете выполнить:"
echo " docker-compose logs"
echo " docker-compose ps"
exit 1
}
trap 'error_handler $LINENO' ERR
# Запуск с параметрами
case "${1:-}" in
--help|-h)
echo "SmartSolTech - Скрипт автоматического обновления"
echo ""
echo "Использование:"
echo " $0 - Полное обновление из origin (по умолчанию)"
echo " $0 origin - Обновление из origin репозитория"
echo " $0 backup - Обновление из backup репозитория"
echo " $0 origin backup - Обновление из origin с бэкапом в backup"
echo " $0 backup origin - Обновление из backup с бэкапом в origin"
echo " $0 --help - Показать эту справку"
echo " $0 --logs - Показать логи без обновления"
echo " $0 --status - Показать статус без обновления"
echo ""
echo "Примеры:"
echo " $0 # обновление из origin"
echo " $0 backup # обновление из backup репозитория"
echo " $0 origin backup # обновление из origin, бэкап в backup"
echo ""
exit 0
;;
--logs)
show_logs
exit 0
;;
--status)
docker-compose ps
health_check
exit 0
;;
*)
# Передаем все параметры в main
main "$@"
;;
esac