mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6a7e9fb5c | ||
|
|
b37b94c144 |
152
docs/RUNBOOK.md
Normal file
152
docs/RUNBOOK.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Раннбук: автосинк и деплой кабинета
|
||||
|
||||
Как устроено скрытие блока «Дополнительные опции» на странице Подписки и вся
|
||||
автоматика вокруг него: приватный форк, ежедневный синк с апстримом, сборка
|
||||
статики и выкладка на VPS.
|
||||
|
||||
Репозиторий: `chillpadclub/bedolaga-cabinet` (приватный форк
|
||||
`BEDOLAGA-DEV/bedolaga-cabinet`).
|
||||
|
||||
## Суть задачи
|
||||
|
||||
На странице `Подписка` нужно было скрыть блок «Дополнительные опции» (докупка
|
||||
устройств, трафика, управление серверами), не потеряв возможность и дальше
|
||||
получать обновления апстрима — проект активно развивается, жить на статичном
|
||||
форке было бы риском самим по себе.
|
||||
|
||||
Решение: приватный форк со своим патчем поверх + GitHub Action, который каждый
|
||||
день сам подтягивает апстрим, накатывает патч и собирает готовую статику для
|
||||
VPS.
|
||||
|
||||
## Патч: как спрятан блок
|
||||
|
||||
Файл — `src/pages/Subscription.tsx`. Условие рендера обёрнуто в `false &&`, но
|
||||
не правкой существующей строки, а **обёрткой снаружи** — так, чтобы ни одна
|
||||
оригинальная строка апстрима не менялась, только добавлены две строки до и две
|
||||
после:
|
||||
|
||||
```tsx
|
||||
{/* Additional Options — disabled on purpose */}
|
||||
{false && (
|
||||
<>
|
||||
{subscription && // ← строка апстрима не тронута
|
||||
(subscription.is_active || subscription.is_limited) &&
|
||||
...
|
||||
<div>...</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
```
|
||||
|
||||
Благодаря этому будущий `git merge` с апстримом конфликтует, только если
|
||||
апстрим правит саму первую или последнюю строку блока — а не любую строку
|
||||
внутри (докупка устройств, трафика и т.д.), которую вы всё равно не
|
||||
используете.
|
||||
|
||||
Компоненты `DeviceTopupSheet`, `DeviceReductionSheet`, `TrafficTopupSheet`,
|
||||
`ServerManagementSheet` остаются в коде и в сборке — просто не рендерятся. Это
|
||||
осознанный выбор в пользу простоты патча, а не баг.
|
||||
|
||||
## Как работает автоматика
|
||||
|
||||
Один workflow — `.github/workflows/sync-and-build.yml`. Запускается по
|
||||
расписанию (ежедневно, 06:00 UTC) и вручную кнопкой `Run workflow`.
|
||||
|
||||
1. **Merge апстрима** — `git fetch` + `merge upstream/main` поверх форка.
|
||||
2. **Чистка CI** — удаляет `dependabot.yml` и чужие workflow, если merge их
|
||||
принёс.
|
||||
3. **Push в форк** — только если merge реально что-то изменил.
|
||||
4. **Сборка** — `npm ci` + `npm run build:docker` (те же build-args, что и в
|
||||
официальном образе).
|
||||
5. **Релиз** — `tar.gz` статики → GitHub Release с тегом `vX.Y.Z`.
|
||||
6. **Уведомление** — сообщение в Telegram: готово или упало.
|
||||
|
||||
Если апстрим правит ровно ту же строку, что и патч, — шаг merge падает
|
||||
**намеренно**. Чужой код не должен домёрживаться в обход человека. Приходит
|
||||
сообщение в Telegram, конфликт разрешается руками локально, затем push — синк
|
||||
продолжается.
|
||||
|
||||
Сборка и релиз происходят, только если merge реально что-то поменял (или при
|
||||
ручном запуске) — вхолостую по расписанию ничего не собирается и не
|
||||
публикуется.
|
||||
|
||||
## Файлы
|
||||
|
||||
| Путь | Назначение |
|
||||
|---|---|
|
||||
| `.github/workflows/sync-and-build.yml` | Весь пайплайн: синк, чистка, сборка, релиз, уведомления |
|
||||
| `scripts/deploy-cabinet.sh` | Деплой на VPS: скачивает релиз, бэкапит текущую статику, раскатывает |
|
||||
| `src/pages/Subscription.tsx` | Патч — скрытый блок «Дополнительные опции» |
|
||||
| `docs/RUNBOOK.md` | Этот файл |
|
||||
|
||||
Удалено из форка сознательно (было в апстриме, плодило шум):
|
||||
|
||||
| Файл | Почему убран |
|
||||
|---|---|
|
||||
| `.github/dependabot.yml` | Открывал десятки PR на бамп версий — оставили только Dependabot alerts (без авто-PR) |
|
||||
| `ci.yml`, `lint.yml` | Тесты/линт апстрима — код уже проверен в апстриме до мёржа |
|
||||
| `codeql.yml`, `security-audit.yml` | Security-сканы апстрима, дублируют Dependabot alerts |
|
||||
| `docker.yml` | Пуш официального образа в GHCR — не нужен, мы публикуем статику |
|
||||
| `release-please.yml`, `release.yml` | Автобамп версии апстрима — версию читаем из `package.json` |
|
||||
|
||||
## Секреты и токены
|
||||
|
||||
| Что | Где хранится | Права |
|
||||
|---|---|---|
|
||||
| `TG_BOT_TOKEN` | GitHub → Settings → Secrets and variables → Actions | Отправка сообщений ботом |
|
||||
| `TG_CHAT_ID` | Там же | — |
|
||||
| Fine-grained PAT | VPS: `~/.cabinet-deploy-token`, права файла `600` | Только `Contents: Read-only` на этот репозиторий |
|
||||
|
||||
Токен для VPS специально ограничен одним репозиторием и правом только на
|
||||
чтение — даже если файл утечёт, им нельзя ничего запушить или изменить.
|
||||
|
||||
## Как выкатить на прод
|
||||
|
||||
На VPS:
|
||||
|
||||
```bash
|
||||
./deploy-cabinet.sh # последний релиз
|
||||
./deploy-cabinet.sh v1.63.0 # откат/установка конкретной версии
|
||||
```
|
||||
|
||||
Скрипт сам:
|
||||
1. скачивает `cabinet-dist.tar.gz` через `gh release download`;
|
||||
2. бэкапит текущую статику в `cabinet-dist.bak`;
|
||||
3. раскатывает новую через `rsync -a --delete` (чистит устаревшие
|
||||
хэшированные JS-чанки, не трогает `50x.html`).
|
||||
|
||||
Бэкап один, перезаписывается при каждом запуске. Откатиться на конкретную
|
||||
версию надёжнее через `./deploy-cabinet.sh vX.Y.Z` (GitHub хранит все
|
||||
релизы), а не полагаться только на `.bak`.
|
||||
|
||||
## Если что-то пошло не так
|
||||
|
||||
**Пришло Telegram-сообщение «⚠️ упал»** — почти всегда конфликт merge с
|
||||
апстримом. Локально:
|
||||
```bash
|
||||
git fetch upstream main && git merge upstream/main
|
||||
# разрешить конфликт (скорее всего в месте патча Subscription.tsx)
|
||||
git add -A && git commit && git push origin main
|
||||
```
|
||||
Следующий прогон workflow снова пойдёт сам.
|
||||
|
||||
**Деплой на VPS выкатил битую сборку**:
|
||||
```bash
|
||||
rsync -a --delete cabinet-dist.bak/ cabinet-dist/ # мгновенный откат
|
||||
# либо
|
||||
./deploy-cabinet.sh vX.Y.Z # конкретный рабочий релиз
|
||||
```
|
||||
|
||||
**Security-алерт в GitHub про уязвимость** — это Dependabot alerts (без
|
||||
авто-PR). Апстрим обычно фиксит сам, фикс прилетит следующим синком. Если
|
||||
критично и срочно — можно поправить зависимость руками отдельным коммитом.
|
||||
|
||||
## Что стоит проверять периодически
|
||||
|
||||
- **Раз в 1–2 месяца — вкладка Actions.** GitHub отключает scheduled-триггер
|
||||
после ~60 дней без активности в репозитории. Один ручной `Run workflow`
|
||||
включает обратно.
|
||||
- **Бэк и фронт бота обновлять вместе.** Синк фронта и апдейт бэкенда бота —
|
||||
по-прежнему ручной процесс, специально не автоматизировали дальше деплоя.
|
||||
- **CHANGELOG апстрима перед выкаткой** — на случай breaking changes в API
|
||||
между бэкендом и фронтом.
|
||||
@@ -1,10 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Скачивает последнюю сборку из GitHub Release форка и раскатывает её
|
||||
# Скачивает сборку из GitHub Release приватного репозитория и раскатывает её
|
||||
# поверх продакшен-статики кабинета на VPS, с автоматическим бэкапом.
|
||||
#
|
||||
# Использование: ./deploy-cabinet.sh
|
||||
# Использование:
|
||||
# ./deploy-cabinet.sh — последний релиз
|
||||
# ./deploy-cabinet.sh v1.63.0 — конкретный релиз (откат на версию)
|
||||
#
|
||||
# Откат при проблемах:
|
||||
# Требует gh CLI, авторизованный токеном с правом Contents: Read-only на этот
|
||||
# репозиторий. Токен лежит отдельно от скрипта — см. TOKEN_FILE ниже.
|
||||
#
|
||||
# Откат вручную при проблемах:
|
||||
# rsync -a --delete "$DEST.bak/" "$DEST/"
|
||||
|
||||
set -euo pipefail
|
||||
@@ -12,12 +17,28 @@ set -euo pipefail
|
||||
REPO="chillpadclub/bedolaga-cabinet"
|
||||
DEST="/home/etkr4k/remnawave-bedolaga-telegram-bot/cabinet-dist"
|
||||
ASSET="cabinet-dist.tar.gz"
|
||||
TOKEN_FILE="$HOME/.cabinet-deploy-token"
|
||||
TAG="${1:-}"
|
||||
|
||||
if [ ! -f "$TOKEN_FILE" ]; then
|
||||
echo "Не найден файл токена: $TOKEN_FILE" >&2
|
||||
echo "Создайте его: echo '<токен>' > $TOKEN_FILE && chmod 600 $TOKEN_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export GH_TOKEN
|
||||
GH_TOKEN="$(cat "$TOKEN_FILE")"
|
||||
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
echo "Скачиваю последнюю сборку из $REPO..."
|
||||
curl -fsSL "https://github.com/$REPO/releases/latest/download/$ASSET" -o "$TMP/$ASSET"
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "Скачиваю последний релиз из $REPO..."
|
||||
gh release download --repo "$REPO" --pattern "$ASSET" --dir "$TMP" --clobber
|
||||
else
|
||||
echo "Скачиваю релиз $TAG из $REPO..."
|
||||
gh release download "$TAG" --repo "$REPO" --pattern "$ASSET" --dir "$TMP" --clobber
|
||||
fi
|
||||
|
||||
echo "Распаковываю..."
|
||||
mkdir -p "$TMP/dist"
|
||||
|
||||
Reference in New Issue
Block a user