Пара 17: CI: автоматические проверки изменения

90 минут · 3 курс, ML.

Содержание и результат

Создать проверяемый pipeline с тестами и сборкой и объяснить границу доверия CI.

План занятия

0–10: контекст и исходная задача. 10–40: устройство и механизмы. 40–55: демонстрация команд. 55–80: лабораторная работа. 80–90: разбор результата и фиксация исправлений.

Практика выполняется в своей учебной папке и на localhost. Подготовка окружения описана в lab/README.md.

CI — общий проверяемый маршрут

Каждое изменение проходит одинаковые необходимые проверки.

Continuous Integration означает частое объединение изменений с автоматической обратной связью. Workflow запускается по событию, job выполняет шаги на runner, шаг может вызвать команду или action. Для StudyPulse проверяем unittest и сборку образа. Зелёный pipeline означает, что конкретные проверки прошли для конкретного SHA, а не что всё на свете исправно. Ранние быстрые тесты дают обратную связь до дорогой сборки. Если нет внешнего хостинга, тот же маршрут работает через bash ci/check.sh локально — идея важнее доступности платформы.

Аналогия: единый контроль качества партии перед передачей дальше.

Тестирует поведение, а не уверенность автора

Проверяем контракт и случаи отказа.

Тест должен поймать важный дефект: неверный вход, неожиданный диапазон score, недоступный healthz или неверный артефакт. В проекте есть тесты вычисления и реальных HTTP-запросов. Тест, повторяющий ту же формулу тем же кодом, слабее проверки конкретного ожидаемого результата и границ. Не заменяем тесты красивым статусом или успешным импортом. На паре намеренно меняем коэффициент в копии и видим красный тест; затем исправляем. Ошибка сборки и ошибка теста имеют разные причины и вывод.

Аналогия: проверка торможения автомобиля полезнее подписи «тормоза предусмотрены».

Runner и секреты

Чужой код в CI не должен получать производственные полномочия.

Workflow запускает команды из репозитория и зависит от действий платформы. permissions: contents: read ограничивает встроенный токен для проверки. Не используем pull_request_target для выполнения недоверенного кода с секретами. Перед production фиксируем actions по SHA и обновляем их осознанно; теги удобны, но меняются. Учебный workflow не публикует образ и не подключается к серверу: он не нуждается в deploy-key. Не запускаем сторонние PR на runner с доступом к личному Docker socket и production-сети. Это объяснение границы доверия, без построения сложной корпоративной инфраструктуры.

Аналогия: приёмная для посетителей не должна выдавать ключи от серверной.

Команды и наблюдения

Окружение: Ubuntu / Bash, lab.

bash ci/check.sh
python3 -m unittest discover -s tests -v
docker build -t studypulse:ci .
git diff -- .github/workflows/ci.yml
# Change a tested behavior in a disposable copy, rerun, then restore it

Локальный CI не требует GitHub-аккаунта. Публикация репозитория внешнему сервису — необязательное упражнение студента.

Ожидаемый результат: Тесты проходят на исходном проекте; намеренный дефект даёт красный результат; сборка проверяется отдельно.

Вариант для macOS

Локальные тесты и сборка доступны. CI на ubuntu-24.04 остаётся Linux-средой, даже если разработчик работает на Mac. Различия регистра файлов и ARM/AMD64 нужно учитывать до выпуска.

python3 -m unittest discover -s tests -v
bash ci/check.sh

Практика: Красный → зелёный

  1. Запустите предоставленный ci/check.sh.
  2. В отдельной ветке измените обработку hours=-1 так, чтобы она стала ошибочной.
  3. Найдите тест, который обнаружил дефект; объясните его смысл.
  4. Исправьте код, повторите тесты и сборку; оформите fix: commit.

Результат: Вывод упавшей и успешной проверки для конкретного commit.

Проверка: Тест ловит реальный дефект контракта; в workflow нет production-секретов.

Неисправность для разбора: Сборку объявляют доказательством корректности входных данных.

Решение и диагностика

Базовый tests/test_app.py проверяет диапазон, типы, boolean/NaN и HTTP-статусы. Не исправляйте тест под ошибочный код. После возврата проверки входа запустите bash ci/check.sh и git diff перед commit. При недоступности registry Docker отделите проблему скачивания образа от результата Python-тестов, зафиксируйте оба статуса честно.

Основные выводы

Самостоятельная работа

Добавить один осмысленный тест edge-case и объяснить, какой дефект он предотвращает.

Источники