Перенос в master всего, кроме админки: ТОП-группы, порядок групп, запуск без Docker
Админка осталась отдельной ветвью admin-panel; в master её нет (ни кода, ни страниц, ни переменных окружения, ни тома настроек). Что перенесено: - parsing: имена групп вида «ИВТ-ТОП-11БО» распознаются, порядок групп = порядок столбцов таблицы (похожие заголовки с пробелами группой не считаются); - main: GET /groups отдаёт группы в порядке столбцов; интервал обновления из SCHEDULE_INTERVAL_MINUTES (со старым SCHEDULE_CACHE_TTL как fallback); - cache: по интервалу сверяем modified — если файл не менялся, не скачиваем; при загрузке считаем sha256 и пишем в лог и /status, изменился ли файл; - source: запросы к Яндекс.Диску с no-cache и меткой времени; - frontend: ответы API с Cache-Control: no-store, общий .env из корня проекта (и backend, и frontend), страницы/прокси админки нет; - Dockerfile/compose/.env.example: без ADMIN_* и без тома настроек; в api-образ попадают все модули backend (проверяется тестом test_deploy); - Makefile: make help/venv/run/run-api/run-front/test + docker-цели — «make run» поднимает всё локально без Docker; - README: быстрый старт, полный список зависимостей, запуск локально и в Docker; - deploy/: пример nginx и инструкция «второй стенд рядом с основным». Тесты: 114 (удалены админские), все зелёные.
This commit is contained in:
40
tests/test_deploy.py
Normal file
40
tests/test_deploy.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""Проверки сборки образов: все нужные файлы должны копироваться.
|
||||
|
||||
Ошибка «в Dockerfile забыли COPY какого-то модуля» роняет контейнер на импорте,
|
||||
а тесты из исходников её не видят (они запускаются из рабочей копии). Ловим
|
||||
статически, без docker.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DOCKERFILE = ROOT / "Dockerfile"
|
||||
COMPOSE = ROOT / "docker-compose.yml"
|
||||
|
||||
|
||||
def _stage(name: str) -> str:
|
||||
dockerfile = DOCKERFILE.read_text(encoding="utf-8")
|
||||
part = dockerfile.split(f"FROM base AS {name}", 1)[1]
|
||||
for other in ("api", "frontend"):
|
||||
if other != name:
|
||||
part = part.split(f"FROM base AS {other}", 1)[0]
|
||||
return part
|
||||
|
||||
|
||||
def test_api_image_copies_every_backend_module():
|
||||
stage = _stage("api")
|
||||
for module in sorted((ROOT / "src" / "backend").glob("*.py")):
|
||||
assert module.name in stage, f"{module.name} не копируется в образ api"
|
||||
assert "src/backend/schedule" in stage, "пакет schedule не копируется в образ api"
|
||||
|
||||
|
||||
def test_frontend_image_copies_static():
|
||||
stage = _stage("frontend")
|
||||
for path in ("src/frontend/main.py", "src/frontend/static"):
|
||||
assert path in stage, f"{path} не копируется в образ frontend"
|
||||
|
||||
|
||||
def test_compose_passes_required_env():
|
||||
compose = COMPOSE.read_text(encoding="utf-8")
|
||||
for var in ("SCHEDULE_LINK", "SCHEDULE_INTERVAL_MINUTES", "SCHEDULE_API"):
|
||||
assert var in compose, f"{var} не передаётся контейнерам"
|
||||
Reference in New Issue
Block a user