Пара 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
Практика: Красный → зелёный
- Запустите предоставленный ci/check.sh.
- В отдельной ветке измените обработку hours=-1 так, чтобы она стала ошибочной.
- Найдите тест, который обнаружил дефект; объясните его смысл.
- Исправьте код, повторите тесты и сборку; оформите fix: commit.
Результат: Вывод упавшей и успешной проверки для конкретного commit.
Проверка: Тест ловит реальный дефект контракта; в workflow нет production-секретов.
Неисправность для разбора: Сборку объявляют доказательством корректности входных данных.
Решение и диагностика
Базовый tests/test_app.py проверяет диапазон, типы, boolean/NaN и HTTP-статусы. Не исправляйте тест под ошибочный код. После возврата проверки входа запустите bash ci/check.sh и git diff перед commit. При недоступности registry Docker отделите проблему скачивания образа от результата Python-тестов, зафиксируйте оба статуса честно.
Основные выводы
- Что заявленные проверки прошли для конкретного состояния, не абсолютную исправность.
- Чтобы ошибка или недоверенный код имели меньше полномочий.
Самостоятельная работа
Добавить один осмысленный тест edge-case и объяснить, какой дефект он предотвращает.