ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 48s
ci / api (push) Successful in 51s
ci / recommender (push) Canceled after 2s
ci / ts (packages + web) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (apps/web/Dockerfile, web, ) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, api, api) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, storage-agent, storage-agent) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/recommender/Dockerfile, recommender, ) (push) Canceled after 0s
ci / mobile (Metro-бандл Android) (push) Canceled after 0s
Security and robustness: - storage-agent rejects an empty INTERNAL_TOKEN (config notEmpty + middleware) - api takes the client IP only from X-Real-IP (chi RealIP trusted True-Client-IP) - /readyz reports ok/fail and logs the cause; checks run in parallel with a timeout - storage-agent shuts down gracefully; shared httpx.NewServer/Serve with IdleTimeout - goose migrations take a Postgres advisory lock - recommender readyz: per-check timeout, redis socket timeouts Clients: - Android release allows cleartext HTTP for LAN servers (expo-build-properties) - checkServer times out after 10s; connect button is disabled while checking Deploy and CI: - install.sh hands cache/uploads/updates/models to the non-root service users - update.sh refuses downgrades unless PIPU_ALLOW_DOWNGRADE=1 - recommender/analyzer get only the env they need; required secrets fail fast - nginx security headers and CSP; strip True-Client-IP - dev compose binds ports to 127.0.0.1; postgres/redis images pinned - version.mjs fails on a malformed explicit tag instead of releasing 0.0.0-dev - contract check catches untracked generated files - final releases fail without a release keystore; changelog skips rc tags Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
3.3 KiB
Bash
73 lines
3.3 KiB
Bash
#!/usr/bin/env bash
|
|
# Установка / обновление / откат из клонированного репозитория: образы собираются локально.
|
|
# ./update.sh — последний релизный тег (без -rc)
|
|
# ./update.sh v0.2.0 — конкретная версия (можно без «v»)
|
|
# ./update.sh main — текущая ветка main (для тестов, не для продакшена)
|
|
set -euo pipefail
|
|
|
|
# git checkout может заменить этот файл прямо во время работы — выполняемся из временной копии.
|
|
if [ -z "${PIPU_UPDATE_REEXEC:-}" ]; then
|
|
tmp="$(mktemp)"
|
|
cp "$0" "$tmp"
|
|
PIPU_UPDATE_REEXEC=1 PIPU_DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)" exec bash "$tmp" "$@"
|
|
fi
|
|
trap 'rm -f "$0"' EXIT
|
|
cd "$PIPU_DEPLOY_DIR"
|
|
|
|
[ -f .env ] || { echo "нет .env — сначала sudo ./install.sh" >&2; exit 1; }
|
|
|
|
REF="${1:-}"
|
|
git fetch --tags --prune --quiet origin
|
|
|
|
if [ -z "$REF" ]; then
|
|
REF="$(git tag -l 'v*' --sort=-v:refname | grep -v -- '-rc' | head -1)"
|
|
[ -n "$REF" ] || { echo "в репозитории нет релизных тегов; укажите версию или main" >&2; exit 1; }
|
|
elif [[ "$REF" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
|
REF="v$REF"
|
|
fi
|
|
|
|
# Откат на более старую версию: миграции БД назад не применяются, старый api может не понять новую схему.
|
|
CURRENT="$(sed -n 's/^PIPU_VERSION=//p' .env)"
|
|
TARGET="${REF#v}"
|
|
core() { [[ "$1" =~ ^([0-9]+\.[0-9]+\.[0-9]+) ]] && echo "${BASH_REMATCH[1]}"; }
|
|
cur_core="$(core "$CURRENT" || true)"
|
|
tgt_core="$(core "$TARGET" || true)"
|
|
# сравниваем только MAJOR.MINOR.PATCH: переход 0.2.0-rc.1 → 0.2.0 откатом не считается
|
|
if [ -n "$cur_core" ] && [ -n "$tgt_core" ] && [ "$cur_core" != "$tgt_core" ] &&
|
|
[ "$(printf '%s\n%s\n' "$cur_core" "$tgt_core" | sort -V | head -1)" = "$tgt_core" ]; then
|
|
echo "внимание: $CURRENT → $TARGET — это откат. Миграции БД не откатываются;" >&2
|
|
echo " сделайте резервную копию (docs/deployment.md) и проверьте, что старая версия совместима со схемой." >&2
|
|
if [ "${PIPU_ALLOW_DOWNGRADE:-}" != 1 ]; then
|
|
echo " Чтобы продолжить: PIPU_ALLOW_DOWNGRADE=1 ./update.sh $REF" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
echo "→ переключаемся на $REF"
|
|
if git show-ref --verify --quiet "refs/remotes/origin/$REF"; then
|
|
git checkout --quiet "$REF"
|
|
git merge --ff-only --quiet "origin/$REF"
|
|
else
|
|
git checkout --quiet --detach "$REF"
|
|
fi
|
|
|
|
VERSION="$(git describe --tags --always --dirty)"
|
|
VERSION="${VERSION#v}"
|
|
sed -i "s|^PIPU_VERSION=.*|PIPU_VERSION=$VERSION|" .env
|
|
echo "→ версия $VERSION, сборка образов (первая сборка — 5–15 минут)"
|
|
|
|
docker compose build --pull
|
|
docker compose up -d --remove-orphans
|
|
docker image prune -f >/dev/null
|
|
|
|
echo "→ ждём готовности api"
|
|
for _ in $(seq 1 60); do
|
|
if docker compose exec -T nginx wget -qO- http://localhost/readyz >/dev/null 2>&1; then
|
|
echo "pipu $VERSION запущен"
|
|
exit 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
echo "api не стал готов за 2 минуты: docker compose logs api" >&2
|
|
exit 1
|