Files
glchat/deploy/update.sh
T
grendervill 63466fb75b fix(ops): update не делает shallow-fetch и объясняет конфликт ветки
Частичный fetch переводил обычный клон в shallow, после чего pull --ff-only
падал с «Not possible to fast-forward» без подсказки, что делать.
2026-09-22 20:49:29 +03:00

112 lines
4.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# glchat: обновление стека (AGENT.md 9.3, 10.11).
set -euo pipefail
GLCHAT_ETC_DIR="${GLCHAT_ETC_DIR:-/opt/glchat}"
ENV_FILE="${GLCHAT_ETC_DIR}/.env"
COMPOSE_FILE="${GLCHAT_ETC_DIR}/compose.yaml"
REPO_DIR_DEFAULT="${GLCHAT_REPO_DIR:-/opt/glchat-src}"
# app_check_url печатает адрес /readyz с учётом привязки приложения: во внешнем
# режиме оно слушает WireGuard-адрес, и проверка localhost всегда падала бы.
app_check_url() {
local port="$1" host="${2:-}"
case "$host" in
0.0.0.0 | "" | "::") host="127.0.0.1" ;;
esac
printf 'http://%s:%s/readyz' "$host" "$port"
}
log() { printf '[update] %s\n' "$*"; }
die() {
printf '[update] ошибка: %s\n' "$*" >&2
exit 1
}
TARGET_VERSION=""
CHANNEL=""
while [ "$#" -gt 0 ]; do
case "$1" in
--version) TARGET_VERSION="${2:?}"; shift 2 ;;
--channel) CHANNEL="${2:?}"; shift 2 ;;
*) die "неизвестный аргумент: $1" ;;
esac
done
[ -f "$ENV_FILE" ] || die "не найден ${ENV_FILE}"
[ -f "$COMPOSE_FILE" ] || die "не найден ${COMPOSE_FILE}"
# shellcheck disable=SC1090
set -a && . "$ENV_FILE" && set +a
CURRENT="${APP_VERSION:-unknown}"
TARGET="${TARGET_VERSION:-$CURRENT}"
[ -n "$CHANNEL" ] && TARGET_CHANNEL="$CHANNEL" || TARGET_CHANNEL="${CHANNEL_NAME:-stable}"
log "текущая версия: ${CURRENT} → целевая: ${TARGET} (канал ${TARGET_CHANNEL})"
if [ "$CURRENT" = "$TARGET" ] && [ -z "${GLCHAT_FORCE_UPDATE:-}" ]; then
log "версия не изменилась; для принудительного обновления задайте GLCHAT_FORCE_UPDATE=1"
fi
log "бэкап перед обновлением (обязательно)"
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/backup.sh" || die "бэкап не удался; обновление остановлено"
compose_args=(-f "$COMPOSE_FILE")
[ "${PROXY_MODE:-embedded}" = "embedded" ] && compose_args+=(--profile embedded-proxy)
if [ "$APP_IMAGE" = "glchat:local" ] || [ -z "${APP_IMAGE:-}" ]; then
REPO_DIR="${GLCHAT_REPO_DIR:-$REPO_DIR_DEFAULT}"
if [ -d "${REPO_DIR}/.git" ]; then
log "обновляем исходники в ${REPO_DIR}"
# Без --depth: частичный fetch переводит обычный клон в shallow, и
# следующий `pull --ff-only` падает с «Not possible to fast-forward».
git -C "$REPO_DIR" fetch --tags origin ||
die "не удалось получить обновления; проверьте доступ к ${REPO_DIR}"
if [ -n "$TARGET_VERSION" ]; then
git -C "$REPO_DIR" checkout "$TARGET_VERSION" ||
die "не удалось переключиться на ${TARGET_VERSION}"
else
git -C "$REPO_DIR" pull --ff-only ||
die "локальные изменения мешают обновлению: git -C ${REPO_DIR} reset --hard origin/main"
fi
log "пересобираем образ"
docker build -t "${APP_IMAGE:-glchat:local}" \
--build-arg "VERSION=${TARGET}" \
--build-arg "COMMIT=$(git -C "$REPO_DIR" rev-parse --short HEAD)" \
--build-arg "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
"$REPO_DIR" || die "сборка не удалась"
else
die "каталог исходников ${REPO_DIR} не найден; выполните git clone или задайте GLCHAT_REPO_DIR"
fi
else
log "скачиваем образ ${APP_IMAGE}"
docker pull "$APP_IMAGE" || die "не удалось скачать образ"
fi
log "применяем новую версию"
(cd "$GLCHAT_ETC_DIR" && docker compose "${compose_args[@]}" up -d --remove-orphans) || die "не удалось поднять стек"
READY_URL="$(app_check_url "${APP_PORT:-8080}" "${GLCHAT_APP_BIND:-}")"
log "ожидаем готовности ${READY_URL} (миграции выполняются на старте приложения)"
for _ in $(seq 1 45); do
if curl -fsS "$READY_URL" >/dev/null 2>&1; then
log "приложение готово"
break
fi
sleep 2
done
if ! curl -fsS "$READY_URL" >/dev/null 2>&1; then
die "приложение не поднялось; откат: glchat restore <бэкап>, затем docker compose up -d"
fi
if command -v sed >/dev/null 2>&1; then
sed -i "s/^APP_VERSION=.*/APP_VERSION=${TARGET}/" "$ENV_FILE"
sed -i "s/^CHANNEL_NAME=.*/CHANNEL_NAME=${TARGET_CHANNEL}/" "$ENV_FILE" 2>/dev/null || printf 'CHANNEL_NAME=%s\n' "$TARGET_CHANNEL" >>"$ENV_FILE"
fi
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/smoke.sh" || log "smoke-тест с замечаниями"
log "обновление завершено: ${TARGET}"