feat(install): автоустановка --auto/--clean + arch-скрипты
- install.sh: режим --auto (неинтерактивный: placeholder BOT_TOKEN, ADMIN_IDS=0, секреты генерируются автоматически — для CI/SSH/установки на машины без TTY), --clean (очистка старых контейнеров/образов), авто-детект не-TTY stdin - package.json: arch:build/arch:index/arch:index:full/incremental/arch:status
This commit is contained in:
84
install.sh
84
install.sh
@@ -5,8 +5,28 @@ set -euo pipefail
|
|||||||
# Telegram Shop — установщик
|
# Telegram Shop — установщик
|
||||||
# Скрипт для развёртывания на x86_64 и ARM64 (Orange Pi, RPi)
|
# Скрипт для развёртывания на x86_64 и ARM64 (Orange Pi, RPi)
|
||||||
# Совместим с POSIX sh (Alpine ash)
|
# Совместим с POSIX sh (Alpine ash)
|
||||||
|
#
|
||||||
|
# Режимы:
|
||||||
|
# install.sh — интерактивный (запрашивает BOT_TOKEN/ADMIN_IDS)
|
||||||
|
# install.sh --auto — неинтерактивный: placeholder BOT_TOKEN, ADMIN_IDS=0,
|
||||||
|
# секреты генерируются автоматически (для CI/SSH)
|
||||||
|
# install.sh --clean — очистка старых контейнеров/образов перед установкой
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
AUTO=0
|
||||||
|
CLEAN=0
|
||||||
|
for ARG in "$@"; do
|
||||||
|
case "$ARG" in
|
||||||
|
--auto) AUTO=1 ;;
|
||||||
|
--clean) CLEAN=1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Неинтерактивный режим также включается, если stdin не терминал
|
||||||
|
if [ ! -t 0 ]; then
|
||||||
|
AUTO=1
|
||||||
|
fi
|
||||||
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
@@ -51,6 +71,27 @@ esac
|
|||||||
print_ok "Архитектура: $ARCH_NAME"
|
print_ok "Архитектура: $ARCH_NAME"
|
||||||
print_info "Docker автоматически соберёт образ под текущую архитектуру"
|
print_info "Docker автоматически соберёт образ под текущую архитектуру"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 0.5. Очистка (--clean): удалить старые контейнеры/образы/тома
|
||||||
|
# ============================================================
|
||||||
|
if [ "$CLEAN" -eq 1 ]; then
|
||||||
|
print_step "Очистка старых контейнеров и образов"
|
||||||
|
if [ -f docker-compose.yml ]; then
|
||||||
|
docker compose down --rmi all --volumes 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
# Удалить осиротевшие контейнеры/образы/тома проекта telegram-shop
|
||||||
|
docker ps -aq --filter "name=telegram_shop_prod" | xargs -r docker rm -f 2>/dev/null || true
|
||||||
|
docker ps -aq --filter "name=tg_shop_admin" | xargs -r docker rm -f 2>/dev/null || true
|
||||||
|
docker ps -aq --filter "name=tor-proxy" | xargs -r docker rm -f 2>/dev/null || true
|
||||||
|
docker images -q "git.softuniq.eu/telegram-market/telegram-shop*" | xargs -r docker rmi -f 2>/dev/null || true
|
||||||
|
docker images -q "telegram-shop-*" | xargs -r docker rmi -f 2>/dev/null || true
|
||||||
|
docker volume rm tor_proxy_data 2>/dev/null || true
|
||||||
|
docker network rm tor_proxy_net telegram-shop_default 2>/dev/null || true
|
||||||
|
# Удалить локальную БД и загрузки (чистая переустановка)
|
||||||
|
rm -rf db uploads
|
||||||
|
print_ok "Очистка завершена (tor-ssh-client не тронут)"
|
||||||
|
fi
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 1. Проверка / установка Docker
|
# 1. Проверка / установка Docker
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -200,10 +241,16 @@ generate_random_hex() {
|
|||||||
# BOT_TOKEN
|
# BOT_TOKEN
|
||||||
current_bot_token=$(grep -E "^BOT_TOKEN=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
current_bot_token=$(grep -E "^BOT_TOKEN=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
||||||
if [ -z "$current_bot_token" ] || [ "$current_bot_token" = "your_bot_token_here" ]; then
|
if [ -z "$current_bot_token" ] || [ "$current_bot_token" = "your_bot_token_here" ]; then
|
||||||
print_warn "BOT_TOKEN не задан или содержит placeholder."
|
if [ "$AUTO" -eq 1 ]; then
|
||||||
read_secret "Введите BOT_TOKEN (от @BotFather): "
|
bot_token="REPLACE_ME_LATER"
|
||||||
update_env_var "BOT_TOKEN" "$input"
|
update_env_var "BOT_TOKEN" "$bot_token"
|
||||||
bot_token="$input"
|
print_warn "BOT_TOKEN не задан — установлен placeholder (внесите реальный токен в админке)"
|
||||||
|
else
|
||||||
|
print_warn "BOT_TOKEN не задан или содержит placeholder."
|
||||||
|
read_secret "Введите BOT_TOKEN (от @BotFather): "
|
||||||
|
update_env_var "BOT_TOKEN" "$input"
|
||||||
|
bot_token="$input"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
bot_token="$current_bot_token"
|
bot_token="$current_bot_token"
|
||||||
fi
|
fi
|
||||||
@@ -211,11 +258,17 @@ fi
|
|||||||
# ADMIN_IDS
|
# ADMIN_IDS
|
||||||
current_admin_ids=$(grep -E "^ADMIN_IDS=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
current_admin_ids=$(grep -E "^ADMIN_IDS=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
||||||
if [ -z "$current_admin_ids" ] || [ "$current_admin_ids" = "123456789,987654321" ]; then
|
if [ -z "$current_admin_ids" ] || [ "$current_admin_ids" = "123456789,987654321" ]; then
|
||||||
print_warn "ADMIN_IDS не задан или содержит placeholder."
|
if [ "$AUTO" -eq 1 ]; then
|
||||||
printf "Введите ADMIN_IDS (через запятую, например: 123456789,987654321): "
|
admin_ids="0"
|
||||||
read -r input
|
update_env_var "ADMIN_IDS" "$admin_ids"
|
||||||
update_env_var "ADMIN_IDS" "$input"
|
print_warn "ADMIN_IDS не задан — установлен 0 (настройте в админке)"
|
||||||
admin_ids="$input"
|
else
|
||||||
|
print_warn "ADMIN_IDS не задан или содержит placeholder."
|
||||||
|
printf "Введите ADMIN_IDS (через запятую, например: 123456789,987654321): "
|
||||||
|
read -r input
|
||||||
|
update_env_var "ADMIN_IDS" "$input"
|
||||||
|
admin_ids="$input"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
admin_ids="$current_admin_ids"
|
admin_ids="$current_admin_ids"
|
||||||
fi
|
fi
|
||||||
@@ -232,7 +285,7 @@ fi
|
|||||||
|
|
||||||
# ADMIN_SECRET
|
# ADMIN_SECRET
|
||||||
current_admin_secret=$(grep -E "^ADMIN_SECRET=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
current_admin_secret=$(grep -E "^ADMIN_SECRET=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
||||||
if [ -z "$current_admin_secret" ] || [ "$current_admin_secret" = "changeme" ]; then
|
if [ -z "$current_admin_secret" ] || [ "$current_admin_secret" = "changeme" ] || [ "$current_admin_secret" = "your_admin_token_here" ]; then
|
||||||
admin_secret=$(generate_random_hex)
|
admin_secret=$(generate_random_hex)
|
||||||
update_env_var "ADMIN_SECRET" "$admin_secret"
|
update_env_var "ADMIN_SECRET" "$admin_secret"
|
||||||
print_ok "ADMIN_SECRET сгенерирован автоматически"
|
print_ok "ADMIN_SECRET сгенерирован автоматически"
|
||||||
@@ -242,7 +295,7 @@ fi
|
|||||||
|
|
||||||
# SUPER_ADMIN_SECRET
|
# SUPER_ADMIN_SECRET
|
||||||
current_super_admin_secret=$(grep -E "^SUPER_ADMIN_SECRET=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
current_super_admin_secret=$(grep -E "^SUPER_ADMIN_SECRET=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
||||||
if [ -z "$current_super_admin_secret" ] || [ "$current_super_admin_secret" = "changeme_super" ]; then
|
if [ -z "$current_super_admin_secret" ] || [ "$current_super_admin_secret" = "changeme_super" ] || [ "$current_super_admin_secret" = "your_super_admin_token_here" ]; then
|
||||||
# Генерация до тех пор, пока не получим значение, отличное от ADMIN_SECRET
|
# Генерация до тех пор, пока не получим значение, отличное от ADMIN_SECRET
|
||||||
super_admin_secret=""
|
super_admin_secret=""
|
||||||
while [ -z "$super_admin_secret" ] || [ "$super_admin_secret" = "$admin_secret" ]; do
|
while [ -z "$super_admin_secret" ] || [ "$super_admin_secret" = "$admin_secret" ]; do
|
||||||
@@ -266,7 +319,7 @@ fi
|
|||||||
|
|
||||||
# ADMIN_URL
|
# ADMIN_URL
|
||||||
current_admin_url=$(grep -E "^ADMIN_URL=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
current_admin_url=$(grep -E "^ADMIN_URL=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"') || true
|
||||||
if [ -z "$current_admin_url" ]; then
|
if [ -z "$current_admin_url" ] || [ "$current_admin_url" = "http://your-host:3000" ] || [ "$current_admin_url" = "your-host" ]; then
|
||||||
# Попытка определить LAN IP
|
# Попытка определить LAN IP
|
||||||
lan_ip=$(hostname -I | awk '{print $1}')
|
lan_ip=$(hostname -I | awk '{print $1}')
|
||||||
if [ -z "$lan_ip" ]; then
|
if [ -z "$lan_ip" ]; then
|
||||||
@@ -307,6 +360,13 @@ print_info "Образы собираются в CI (Gitea Actions, buildx multi
|
|||||||
IMAGE_TAG="${IMAGE_TAG:-latest}"
|
IMAGE_TAG="${IMAGE_TAG:-latest}"
|
||||||
print_info "Используемая версия образа: $IMAGE_TAG"
|
print_info "Используемая версия образа: $IMAGE_TAG"
|
||||||
|
|
||||||
|
# Логин в приватный Gitea Container Registry (если задан токен)
|
||||||
|
if [ -n "${GITEA_TOKEN:-}" ]; then
|
||||||
|
echo "${GITEA_TOKEN}" | docker login git.softuniq.eu -u oauth2 --password-stdin >/dev/null 2>&1 \
|
||||||
|
&& print_ok "Авторизация в Gitea Container Registry" \
|
||||||
|
|| print_warn "Не удалось авторизоваться в registry (GITEA_TOKEN)"
|
||||||
|
fi
|
||||||
|
|
||||||
$COMPOSE_CMD pull telegram_shop_prod tg_shop_admin
|
$COMPOSE_CMD pull telegram_shop_prod tg_shop_admin
|
||||||
print_ok "Образы telegram-shop:${IMAGE_TAG} и telegram-shop-admin:${IMAGE_TAG} загружены"
|
print_ok "Образы telegram-shop:${IMAGE_TAG} и telegram-shop-admin:${IMAGE_TAG} загружены"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,12 @@
|
|||||||
"test:watch": "vitest",
|
"test:watch": "vitest",
|
||||||
"start": "node src/index.js",
|
"start": "node src/index.js",
|
||||||
"dev": "nodemon src/index.js",
|
"dev": "nodemon src/index.js",
|
||||||
"lint": "find src -name '*.js' -print0 | xargs -0 -n1 node --check"
|
"lint": "find src -name '*.js' -print0 | xargs -0 -n1 node --check",
|
||||||
|
"arch:build": "docker compose -f docker/docker-compose.architect.yml build",
|
||||||
|
"arch:index": "docker compose -f docker/docker-compose.architect.yml run --rm architect-indexer",
|
||||||
|
"arch:index:full": "docker compose -f docker/docker-compose.architect.yml run --rm architect-indexer --mode full",
|
||||||
|
"arch:index:incremental": "docker compose -f docker/docker-compose.architect.yml run --rm architect-indexer --mode incremental",
|
||||||
|
"arch:status": "docker compose -f docker/docker-compose.architect.yml ps"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
|
|||||||
Reference in New Issue
Block a user