From 711c6ae7b01048e43fc59a1abba5cc91a7d86df4 Mon Sep 17 00:00:00 2001 From: agent Date: Tue, 15 Sep 2026 17:54:18 +0300 Subject: [PATCH] fix: verify deployed runtime version --- .gitea/workflows/ci.yml | 18 ++++++++++++++++-- CHANGELOG.md | 4 ++++ README.md | 2 +- app/version.py | 6 +++--- pyproject.toml | 2 +- tests/test_api.py | 2 +- 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index fd9631a..a1ac110 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -37,9 +37,13 @@ jobs: steps: - uses: actions/checkout@v4 - name: Prepare release + id: prepare shell: bash run: | set -euo pipefail + backend_version="$(sed -n 's/^BACKEND_VERSION = "\(.*\)"$/\1/p' app/version.py)" + test -n "$backend_version" + echo "backend_version=$backend_version" >> "$GITHUB_OUTPUT" tar --exclude=.git --exclude=.env -cf "$RUNNER_TEMP/$RELEASE_NAME" . printf '%s\n' "$PROD_SSH_KEY" > "$RUNNER_TEMP/deploy_key" printf '%s\n' "$PROD_KNOWN_HOSTS" > "$RUNNER_TEMP/known_hosts" @@ -67,10 +71,13 @@ jobs: -o BatchMode=yes \ -o UserKnownHostsFile="$RUNNER_TEMP/known_hosts" \ "$PROD_USER@$PROD_HOST" \ - "PROD_PATH='$PROD_PATH' RELEASE_NAME='$RELEASE_NAME' bash -s" <<'REMOTE' + "PROD_PATH='$PROD_PATH' RELEASE_NAME='$RELEASE_NAME' EXPECTED_BACKEND_VERSION='$EXPECTED_BACKEND_VERSION' bash -s" <<'REMOTE' set -euo pipefail cd "$PROD_PATH" release="$HOME/$RELEASE_NAME" + test -f "$release" + archive_version="$(tar -xOf "$release" ./app/version.py | sed -n 's/^BACKEND_VERSION = "\(.*\)"$/\1/p')" + test "$archive_version" = "$EXPECTED_BACKEND_VERSION" mkdir -p "$HOME/backups/miem_workers" backup="$HOME/backups/miem_workers/miem_workers-$(date +%Y%m%d-%H%M%S).sql" docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > "$backup" @@ -79,7 +86,13 @@ jobs: -v "$PROD_PATH":/dst \ alpine:3.20 sh -c 'tar -xf /src/release.tar -C /dst' docker compose up -d --build - curl --fail --silent --show-error http://127.0.0.1:8000/api/health + runtime_version="$(docker compose exec -T api python -c 'from app.version import BACKEND_VERSION; print(BACKEND_VERSION)')" + test "$runtime_version" = "$EXPECTED_BACKEND_VERSION" + health="$(curl --fail --silent --show-error http://127.0.0.1:8000/api/health)" + case "$health" in + *"\"status\":\"ok\""*"\"backend_version\":\"$EXPECTED_BACKEND_VERSION\""*) ;; + *) echo "Unexpected health response: $health" >&2; exit 1 ;; + esac find "$HOME/backups/miem_workers" -maxdepth 1 -type f -name 'miem_workers-*.sql' ! -path "$backup" -delete docker compose ps rm -f "$release" @@ -87,3 +100,4 @@ jobs: env: PROD_HOST: ${{ secrets.PROD_HOST }} PROD_USER: ${{ secrets.PROD_USER }} + EXPECTED_BACKEND_VERSION: ${{ steps.prepare.outputs.backend_version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 361b1b3..0227fc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.8.10 + +- Production deploy проверяет совпадение версии release-архива и запущенного API. + ## 0.8.9 - Контейнеры API, worker и PostgreSQL автоматически перезапускаются после остановки или перезагрузки хоста. diff --git a/README.md b/README.md index 00c16ad..da75122 100644 --- a/README.md +++ b/README.md @@ -135,4 +135,4 @@ node --check app/static/admin.js Тесты с данными используют временную SQLite; отдельные API smoke-тесты запускают приложение с его текущей конфигурацией. Браузерная проверка: `pip install playwright`, `python -m playwright install chromium`, затем `python tests/browser_admin.py`. Она проверяет реальный рендеринг страниц, клавиатуру, диалог, фильтры и восстановление прогресса после ошибки. Скриншоты сохраняются во временную папку; путь выводится в конце. -Версия сервиса: `0.8.9`. Админка всегда показывает версии backend и frontend в footer. +Версия сервиса: `0.8.10`. Админка всегда показывает версии backend и frontend в footer. diff --git a/app/version.py b/app/version.py index 794937e..2c042c8 100644 --- a/app/version.py +++ b/app/version.py @@ -1,3 +1,3 @@ -APP_VERSION = "0.8.9" -FRONTEND_VERSION = "0.8.9" -BACKEND_VERSION = "0.8.9" +APP_VERSION = "0.8.10" +FRONTEND_VERSION = "0.8.10" +BACKEND_VERSION = "0.8.10" diff --git a/pyproject.toml b/pyproject.toml index eed873f..4228ebc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "miem-workers" -version = "0.8.9" +version = "0.8.10" description = "MIEM employees parser, admin API, and web admin" requires-python = ">=3.11" dependencies = [ diff --git a/tests/test_api.py b/tests/test_api.py index 1db517d..9aa714b 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -18,7 +18,7 @@ def test_health_returns_versions(): response = TestClient(app).get("/api/health") assert response.status_code == 200 - assert response.json()["backend_version"] == "0.8.9" + assert response.json()["backend_version"] == "0.8.10" def test_api_employees_and_stats_require_admin_session():