name: Build, Test and Push Flask App on: push: branches: [ main, master ] env: PYTHON_VERSION: '3.11' jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Устанавливаем Python и необходимые пакеты - name: Install Python and dependencies run: | apt-get update apt-get install -y python3 python3-pip python3-venv python3-dev # Проверяем установку python3 --version pip3 --version # Убеждаемся что venv доступен python3 -m venv --help || (echo "venv not available"; exit 1) # Кэширование pip пакетов - name: Cache pip packages uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('dependencies.txt', 'requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- # Создаем виртуальное окружение - name: Create virtual environment run: | # Удаляем старую venv если есть rm -rf venv # Создаем новую venv python3 -m venv venv # Проверяем что venv создалась if [ ! -f venv/bin/activate ]; then echo "❌ Не удалось создать виртуальное окружение" exit 1 fi echo "✅ Виртуальное окружение создано" # Устанавливаем переменные окружения echo "VIRTUAL_ENV=$PWD/venv" >> $GITHUB_ENV echo "$PWD/venv/bin" >> $GITHUB_PATH # Активируем для текущего шага . venv/bin/activate # Обновляем pip pip install --upgrade pip echo "✅ Настройка виртуального окружения завершена" - name: Install dependencies run: | # Активируем виртуальное окружение . venv/bin/activate # Устанавливаем зависимости из файла if [ -f dependencies.txt ]; then pip install --no-cache-dir -r dependencies.txt elif [ -f requirements.txt ]; then pip install --no-cache-dir -r requirements.txt else # Минимальный набор pip install flask gunicorn fi # Устанавливаем тестовые зависимости pip install pytest requests gunicorn echo "✅ Зависимости установлены" - name: Verify application run: | # Активируем виртуальное окружение . venv/bin/activate # Проверяем что Flask установлен python3 -c "import flask; print(f'Flask version: {flask.__version__}')" # Проверяем импорт приложения if [ -f app.py ]; then python3 -c "import app; print('✅ Приложение импортируется успешно')" || \ (echo "❌ Не удалось импортировать приложение"; exit 1) else echo "⚠️ app.py не найден, пропускаем проверку импорта" fi - name: Start Flask application run: | # Активируем виртуальное окружение . venv/bin/activate # Запускаем Flask в фоне flask run --host 0.0.0.0 --debug > flask.log 2>&1 & APP_PID=$! echo "APP_PID=$APP_PID" >> $GITHUB_ENV echo "Flask запущен с PID: $APP_PID" # Проверяем порт echo "Ожидаем запуск Flask на порту 5000..." for i in {1..15}; do if curl -sf http://localhost:5000/health 2>/dev/null; then echo "✅ Flask приложение запущено" exit 0 fi echo "Попытка $i: Flask еще не готов..." sleep 5 done # Если не запустился, показываем логи echo "❌ Не удалось запустить Flask приложение" echo "=== Логи Flask ===" cat flask.log exit 1 - name: Run tests run: | # Активируем виртуальное окружение . venv/bin/activate # Запускаем тесты если они есть if [ -f test_api.py ]; then python3 test_api.py echo "✅ API тесты завершены" else echo "⚠️ test_api.py не найден" fi # Запускаем pytest тесты if [ -d tests ] && [ "$(ls -A tests)" ]; then pytest tests/ -v --tb=short else echo "⚠️ pytest тесты не найдены" fi - name: Validate Gunicorn run: | # Активируем виртуальное окружение . venv/bin/activate if [ -f app.py ]; then gunicorn --check-config app:app echo "✅ Конфигурация Gunicorn корректна" else echo "⚠️ app.py не найден, пропускаем проверку gunicorn" fi - name: Stop Flask application if: always() && env.APP_PID != '' run: | echo "Останавливаем Flask приложение (PID: $APP_PID)" kill $APP_PID 2>/dev/null || true pkill -f "python3 app.py" 2>/dev/null || true echo "✅ Flask приложение остановлено" - name: Clean up Python cache if: always() run: | find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true find . -type f -name "*.pyc" -delete 2>/dev/null || true echo "✅ Кэш Python очищен" docker-build-and-push: needs: test # ✅ Теперь это работает, так как test в том же workflow runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Docker CLI run: | apt-get update apt-get install -y docker.io docker --version - name: Configure Docker CLI for insecure registry run: | mkdir -p ~/.docker echo '{"insecure-registries" : ["git.rustprogersteam.ru"]}' > ~/.docker/config.json cat ~/.docker/config.json - name: 'Docker Tags' id: tags uses: https://github.com/cssnr/docker-tags-action@v2 with: images: 'git.rustprogersteam.ru/pvhproject/pvhbackend/' - name: Login to Docker Registry uses: docker/login-action@v3 with: registry: git.rustprogersteam.ru username: ${{ vars.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . push: true tags: | git.rustprogersteam.ru/pvhproject/pvhbackend/pvh:latest git.rustprogersteam.ru/pvhproject/pvhbackend/pvh:${{ github.sha }} labels: ${{ steps.tags.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max deploy: needs: docker-build-and-push runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Ansible run: sudo apt-get update && sudo apt-get install -y ansible - name: Set up SSH key run: | mkdir -p ~/.ssh echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key # Отключаем проверку known_hosts (или добавьте реальный ключ сервера) echo "${{ secrets.SERVER_IP }} ssh-rsa AAAAB3..." >> ~/.ssh/known_hosts # Для автоматического принятия хоста можно использовать: # ssh-keyscan -H ${{ secrets.SERVER_IP }} >> ~/.ssh/known_hosts env: SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} - name: Run Ansible playbook run: | ansible-playbook -i "${{ secrets.SERVER_IP }}," .forgejo/workflows/restart_compose.yml \ --user "${{ secrets.SERVER_USER }}" \ --private-key ~/.ssh/deploy_key \ --become