feat(phase1): rebrand to TTRPG Player and drop Git updates feed
Rename product to TTRPG Player (TTRPGPlayer / com.ttrpgplayer.app), use .ttrpg.zip for new saves while keeping .dnd.zip import, accept TTRPG- and DND- license keys on client, and remove sync-update-feed plus CI push to DndGamePlayerUpdates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+33
-500
@@ -1,519 +1,52 @@
|
||||
# Автообновление через Gitea (приватный код + публичный feed)
|
||||
# Автообновления TTRPG Player
|
||||
|
||||
Исходники остаются в **закрытом** репозитории с игрой. Файлы обновлений (`latest.yml`, установщики) лежат в **отдельном публичном** репозитории — по HTTPS их скачивает `electron-updater`.
|
||||
## Текущее состояние (фаза 1)
|
||||
|
||||
## Твой публичный репозиторий (уже есть)
|
||||
- Продукт переименован в **TTRPG Player** / **НРИ Плеер** (`productName`: `TTRPGPlayer`, `appId`: `com.ttrpgplayer.app`).
|
||||
- CI по тегу `v*` **только собирает** установщики в каталог `release/` (Win NSIS, Linux AppImage x64/arm64). Пуш в Git-репозиторий **`DndGamePlayerUpdates`** **отключён**; скрипт `scripts/sync-update-feed.mjs` удалён.
|
||||
- В `package.json` → `build.publish.url` стоит заглушка `https://updates.invalid.ttrpg/` до настройки реального хоста.
|
||||
- Секреты **`DND_UPDATE_FEED_URL`**, **`DND_UPDATES_SERVER`**, **`UPDATES_REPO`**, **`DND_UPDATES_PUSH_TOKEN`** в workflow **больше не используются** — их можно удалить из настроек репозитория.
|
||||
- Публичный репозиторий **`DndGamePlayerUpdates` на Gitea можно удалить** (история с бинарниками ~4 GiB больше не нужна).
|
||||
|
||||
- Клон: `https://git.mailib.ru/ifontosh/DndGamePlayerUpdates.git`
|
||||
- Владелец/репо для секретов: **`ifontosh/DndGamePlayerUpdates`**
|
||||
- Базовый URL feed (вшивается в сборку и должен совпадать с secret **`DND_UPDATE_FEED_URL`**):
|
||||
Клиент по-прежнему использует **electron-updater** (generic provider). Пока URL заглушка, проверка обновлений в установленной сборке завершится ошибкой сети — это ожидаемо до фазы 2.
|
||||
|
||||
**`https://git.mailib.ru/ifontosh/DndGamePlayerUpdates/raw/branch/updates/`**
|
||||
## Фаза 2 (план): статический VPS
|
||||
|
||||
Обрати внимание: слово **`branch`** в пути — это часть URL Gitea, не имя ветки. Имя ветки — в конце: **`updates`**.
|
||||
Цель: один HTTPS- origin без Git LFS и без роста репозитория.
|
||||
|
||||
В `package.json` уже указан этот же `build.publish.url` (для локального `npm run pack` и метаданных electron-builder).
|
||||
1. VPS с **nginx** (или аналог), TLS (Let's Encrypt).
|
||||
2. Каталог, например `/var/www/ttrpg-updates/`, с **фиксированными именами** файлов (без версии в имени установщика) или с semver в `latest*.yml` и прямыми URL на те же имена.
|
||||
3. CI или ручной шаг: **rsync/scp** артефактов из `release/` на сервер после тега `v*`.
|
||||
4. В приватном репозитории кода — секрет **`TTRPG_UPDATE_FEED_URL`** (со слэшем в конце), подстановка в `electron-builder` при сборке релиза.
|
||||
5. Mac: ручная выкладка `.dmg` / `latest-mac.yml` на тот же origin (см. `docs/MANUAL_MAC_UPDATE_UPLOAD.md`).
|
||||
|
||||
---
|
||||
Детали CI для VPS будут добавлены отдельным PR после выбора хоста и схемы имён файлов.
|
||||
|
||||
## Шаг 0 — репозиторий сейчас пустой (важно)
|
||||
|
||||
На странице репо написано, что **контента нет**. Пока нет **ни одного коммита**, CI не сможет сделать `git clone`.
|
||||
|
||||
Сделай так (любой способ):
|
||||
|
||||
1. На сайте открой `ifontosh/DndGamePlayerUpdates` → кнопка вроде **«Инициализировать репозиторий»** / **«Добавить файл»** → создай файл `README.md` с парой строк и закоммить **в ветку по умолчанию** (часто `main`).
|
||||
2. Либо с компьютера:
|
||||
## Локальная сборка релиза
|
||||
|
||||
```bash
|
||||
git clone https://git.mailib.ru/ifontosh/DndGamePlayerUpdates.git
|
||||
cd DndGamePlayerUpdates
|
||||
echo "# DndGamePlayer updates feed" > README.md
|
||||
git add README.md
|
||||
git commit -m "init"
|
||||
git push origin main
|
||||
npm run pack # Win (на Windows) или см. CI
|
||||
npm run pack:linux # Linux AppImage
|
||||
npm run pack:mac # macOS (на Mac)
|
||||
npm run release:info # версия и пример тега vX.Y.Z
|
||||
```
|
||||
|
||||
(Если ветка по умолчанию у тебя `master` — подставь её вместо `main`.)
|
||||
Артефакты: `TTRPGPlayer-Setup-<version>.exe`, `TTRPGPlayer-<version>-<arch>.AppImage`, и т.д. (см. `package.json` → `build`).
|
||||
|
||||
После этого репозиторий **не пустой** — workflow сможет клонировать и создать ветку **`updates`**.
|
||||
## Gitea Actions (act_runner)
|
||||
|
||||
---
|
||||
- Workflow: `.gitea/workflows/release.yml`
|
||||
- Триггер: push тега `v*`
|
||||
- Runner label: `ubuntu-22.04` (как в настройках раннера)
|
||||
|
||||
## Шаг 1 — токен для записи в публичный репозиторий
|
||||
Если job падает на Wine/NSIS — см. комментарии в workflow (сборка Win на Linux без i386).
|
||||
|
||||
Нужен **персональный токен** (PAT), с которым CI сможет **пушить** в `DndGamePlayerUpdates`.
|
||||
## Лицензия и обновления
|
||||
|
||||
В Gitea на русском обычно так (названия могут чуть отличаться в твоей теме):
|
||||
Проверка обновлений доступна только при **активной лицензии** (как и раньше). Продуктовые ключи на клиенте: **`TTRPG-…`** и устаревшие **`DND-…`**; новые ключи выдаёт сервер лицензий (отдельный репозиторий `DndGamePlayerLicenseServer` — смена префикса на сервере вне этого PR).
|
||||
|
||||
1. Вверху справа **аватар** → **Настройки** (или «Параметры»).
|
||||
2. Слева найди раздел вроде **«Приложения»** / **«Токены доступа»** / **«Токены»** (в англ. интерфейсе: **Settings → Applications → Generate New Token**).
|
||||
3. Создай новый токен:
|
||||
- имя: например `dnd-release-ci`;
|
||||
- права: достаточно доступа к репозиторию с **записью** (для пуша в `DndGamePlayerUpdates`). Если есть галочки — включи что-то вроде **«Запись в репозиторий»** / **write:repository** / полный доступ к репо.
|
||||
4. **Скопируй токен один раз** и сохрани в менеджере паролей — потом Gitea его не покажет.
|
||||
## Устаревшая схема (не использовать)
|
||||
|
||||
Этот токен пойдёт в secret **`DND_UPDATES_PUSH_TOKEN`** (см. ниже). **Не вставляй токен в код и не коммить его.**
|
||||
|
||||
> На **git.mailib.ru** имена секретов **не могут начинаться с `GITEA_`** (зарезервировано). Поэтому в workflow используются `DND_UPDATES_*`, а не `GITEA_*`.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 2 — секреты в приватном репозитории с кодом (`dnd_player`)
|
||||
|
||||
Открой **приватный** репозиторий, где лежит исходник игры (не `DndGamePlayerUpdates`).
|
||||
|
||||
Дальше (русский Gitea 1.26, ориентир по меню):
|
||||
|
||||
1. Вкладка **«Настройки»** репозитория (вверху рядом с «Код», «Задачи» — иногда шестерёнка **«Настройки»**).
|
||||
2. Слева раздел **«Секреты»** / **«Действия»** → **«Секреты»** (в англ. UI: **Settings → Actions → Secrets**). Если видишь **«Переменные»** — секреты обычно рядом; нам нужны именно **секреты** (скрытые значения).
|
||||
|
||||
Добавь **четыре** секрета (имя **точно** как в таблице — workflow их читает):
|
||||
|
||||
| Имя секрета | Что вписать в значение |
|
||||
| ------------------------ | -------------------------------------------------------------------------------------------------------- |
|
||||
| `DND_UPDATE_FEED_URL` | `https://git.mailib.ru/ifontosh/DndGamePlayerUpdates/raw/branch/updates/` (обязательно **слэш в конце**) |
|
||||
| `DND_UPDATES_SERVER` | `https://git.mailib.ru` (**без** слэша в конце) |
|
||||
| `UPDATES_REPO` | `ifontosh/DndGamePlayerUpdates` |
|
||||
| `DND_UPDATES_PUSH_TOKEN` | токен из шага 1 (одна длинная строка) |
|
||||
|
||||
Сохрани каждый секрет кнопкой вроде **«Сохранить»** / **«Добавить»**.
|
||||
|
||||
Если раньше создавал секреты `GITEA_SERVER` / `GITEA_TOKEN` — их workflow **не читает**; удали или оставь, но **обязательно** заведи новые имена из таблицы.
|
||||
|
||||
---
|
||||
|
||||
## Раннер act_runner — без этого «Всего: 0» и сборки не будет
|
||||
|
||||
Gitea **не запускает** workflow на своём процессе: нужна **отдельная машина** (VPS, сервер или **WSL2 Ubuntu** на твоём ПК), на которой крутится **[act_runner](https://docs.gitea.com/usage/actions/act-runner)** и которая видит `git.mailib.ru` по сети.
|
||||
|
||||
Пока в **«Настройки» → «Действия» → «Раннеры»** написано **«Всего: 0»**, workflow **висит в ожидании** — нечему выполнять шаги.
|
||||
|
||||
### Важно: это не тот токен, что для пуша в `DndGamePlayerUpdates`
|
||||
|
||||
| Токен | Где взять | Зачем |
|
||||
| --------------------------------------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| **Регистрация раннера** (короткая случайная строка) | **Настройки репо** → **Действия** → **Раннеры** → **Создать новый раннер** | Только для команды **`act_runner register`** (один раз на каталог с раннером) |
|
||||
| **`DND_UPDATES_PUSH_TOKEN`** (PAT) | **Аватар** → **Настройки пользователя** → токены доступа | Для CI: пуш в публичный репо обновлений (см. шаг 1 выше) |
|
||||
|
||||
Если Gitea показала **только длинную строку** — это почти наверняка **токен регистрации раннера**. URL инстанса ты знаешь сам: **`https://git.mailib.ru`** (без пути к репозиторию).
|
||||
|
||||
### Требования к машине под наш `release.yml`
|
||||
|
||||
В workflow для job **`ubuntu-22.04`** идут **`sudo apt-get`** (пакеты **`nsis`**, **`wine64`**) на **Linux**. Multiarch **i386** намеренно не включается — на Debian с репозиториями только под amd64 (nginx, sury и т.п.) установка **wine32** часто падает с «unmet dependencies». После установки **`wine64`** в CI создаётся скрипт **`/usr/local/bin/wine`** с **`exec` по полному пути** к **`wine64`** (в job у act_runner иногда пустой/урезанный `PATH`, тогда имя `wine64` без пути не находится). electron-builder проверяет именно команду **`wine`** в `PATH`. Поэтому:
|
||||
|
||||
- Нужен **Linux x86_64** (идеально **Ubuntu 22.04**), либо **WSL2** с Ubuntu 22.04 на Windows.
|
||||
- Запускать раннер на «голом» Windows с меткой `ubuntu-22.04` **бессмысленно** — шаги с `apt` не выполнятся.
|
||||
|
||||
### Шаг A — получить токен регистрации в Gitea
|
||||
|
||||
1. Открой репозиторий с кодом (**DndGamePlayer** или как он у тебя называется).
|
||||
2. **Настройки** → **Действия** → **Раннеры** → **Создать новый раннер**.
|
||||
3. Выбери тип **репозитория** (repository runner), ОС **Linux**.
|
||||
4. **Скопируй токен** (и при желании подсказку с URL инстанса, если она есть). Команду из мастера можно **не копировать**, если ниже удобнее готовая.
|
||||
|
||||
### Шаг B — скачать act_runner (бинарник)
|
||||
|
||||
Официальные сборки: **[релизы act_runner на gitea.com](https://gitea.com/gitea/act_runner/releases)**.
|
||||
|
||||
1. Открой страницу релизов и посмотри **последний стабильный** тег, например **`v1.0.2`**.
|
||||
2. В списке файлов скачай **`gitea-runner-ВЕРСИЯ-linux-amd64`** — это один исполняемый файл **без** расширения `.zip` (не путай с `darwin` / `arm64`, если у тебя обычный ПК/сервер Intel/AMD).
|
||||
|
||||
**Прямая ссылка (подставь свою версию из релиза):**
|
||||
|
||||
`https://gitea.com/gitea/act_runner/releases/download/v1.0.2/gitea-runner-1.0.2-linux-amd64`
|
||||
|
||||
В URL после `download/` идёт тег с **`v`**, в имени файла версия **без `v`**.
|
||||
|
||||
**Скачать с Linux/WSL одной командой** (замени `1.0.2` на актуальную версию с сайта):
|
||||
|
||||
```bash
|
||||
mkdir -p ~/gitea-act-runner && cd ~/gitea-act-runner
|
||||
VERSION="1.0.2"
|
||||
curl -fL -o act_runner "https://gitea.com/gitea/act_runner/releases/download/v${VERSION}/gitea-runner-${VERSION}-linux-amd64"
|
||||
chmod +x act_runner
|
||||
./act_runner --version
|
||||
```
|
||||
|
||||
Если `curl` ругается на сертификат — обнови CA или скачай тот же файл через браузер и положи в папку, затем `chmod +x`.
|
||||
|
||||
### Шаг C — регистрация (подставь свой токен)
|
||||
|
||||
В каталоге, где лежит `act_runner`, выполни **одну** команду (токен — тот, что выдала Gitea при создании раннера):
|
||||
|
||||
```bash
|
||||
cd ~/gitea-act-runner
|
||||
|
||||
./act_runner register --no-interactive \
|
||||
--instance "https://git.mailib.ru" \
|
||||
--token "ВСТАВЬ_СЮДА_ТОКЕН_ИЗ_МАСТЕРА_GITEA" \
|
||||
--name "dnd-release-runner" \
|
||||
--labels "ubuntu-22.04:host"
|
||||
```
|
||||
|
||||
Пояснения:
|
||||
|
||||
- **`--instance`** — корень твоего Gitea (**без** `/ifontosh/...`).
|
||||
- **`--labels "ubuntu-22.04:host"`** — job в **`.gitea/workflows/release.yml`** имеет `runs-on: ubuntu-22.04`, а **`:host`** означает выполнение **на самой машине**, с настоящим `apt` и Wine (см. [документацию по меткам](https://docs.gitea.com/usage/actions/act-runner#labels)). Если при регистрации оставить **дефолтные** метки с **`docker://`**, шаги тоже могут сработать, но образ другой; для предсказуемости лучше **`ubuntu-22.04:host`** на чистой Ubuntu 22.04.
|
||||
- После успешной регистрации в этой папке появится файл **`.runner`** — его не удаляй и не коммить.
|
||||
|
||||
Если Gitea пишет ошибку регистрации — часто неверный **токен** (устарел после «сброса» в UI) или выбран не тот уровень (инстанс/организация/репозиторий). Создай раннера заново и возьми **новый** токен.
|
||||
|
||||
### Шаг D — запуск вручную (для проверки)
|
||||
|
||||
В той же папке:
|
||||
|
||||
```bash
|
||||
./act_runner daemon
|
||||
```
|
||||
|
||||
Окно терминала должно остаться **открытым**. Остановка — `Ctrl+C`. Когда убедишься, что в Gitea раннер **online**, лучше перейти на **systemd** (шаг ниже).
|
||||
|
||||
### Шаг D1 — systemd: автозапуск после перезагрузки (подробно)
|
||||
|
||||
Идея: **systemd** сам поднимает `act_runner daemon` при загрузке системы и перезапускает процесс при падении. Рабочая директория должна быть **та же**, где лежат **`act_runner`** и зарегистрированный файл **`.runner`** (обычно `~/gitea-act-runner`).
|
||||
|
||||
#### 0) Подготовка
|
||||
|
||||
1. Регистрация (**шаг C**) уже выполнена, в каталоге есть **`.runner`**.
|
||||
2. Узнай **точный путь** к каталогу (systemd не понимает `~`):
|
||||
|
||||
```bash
|
||||
cd ~/gitea-act-runner && pwd
|
||||
```
|
||||
|
||||
Запомни вывод, например **`/home/ivan/gitea-act-runner`**. Имя пользователя Linux:
|
||||
|
||||
```bash
|
||||
whoami
|
||||
```
|
||||
|
||||
Дальше в примерах: **`/home/ivan/gitea-act-runner`** и пользователь **`ivan`** — замени на свои.
|
||||
|
||||
#### 1) Останови ручной запуск
|
||||
|
||||
Если где-то в терминале уже крутится `./act_runner daemon` — заверши **Ctrl+C**, иначе два процесса будут мешать друг другу.
|
||||
|
||||
#### 2) Создай unit-файл службы
|
||||
|
||||
На **VPS / обычной Ubuntu** с правами root:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/gitea-act-runner.service
|
||||
```
|
||||
|
||||
Вставь текст **целиком** (подставь свои `User`, `Group`, `WorkingDirectory`, `ExecStart`):
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Gitea Actions act_runner
|
||||
Documentation=https://docs.gitea.com/usage/actions/act-runner
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=ivan
|
||||
Group=ivan
|
||||
WorkingDirectory=/home/ivan/gitea-act-runner
|
||||
ExecStart=/home/ivan/gitea-act-runner/act_runner daemon
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
# Логи в journald (см. ниже как читать)
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Сохрани файл: в **nano** — **Ctrl+O**, Enter, **Ctrl+X**.
|
||||
|
||||
Пояснения:
|
||||
|
||||
- **`User` / `Group`** — под этим пользователем ты делал `register` и владеешь папкой (проверка: `ls -la ~/gitea-act-runner` — владелец должен совпадать).
|
||||
- **`WorkingDirectory`** — каталог с **`.runner`**; без него раннер может не найти регистрацию.
|
||||
- **`ExecStart`** — полный путь к бинарнику **`act_runner`** (тот, что скачал и сделал `chmod +x`).
|
||||
- Блок **`After=network-online.target`** — старт после сети (удобно для `git`/`npm` в CI). Если вдруг зависнет старт из‑за сетевого таргета, можно временно заменить на **`After=network.target`**.
|
||||
|
||||
Официальный пример с отдельным пользователем `act_runner` и `config.yaml`: [Start the runner with Systemd](https://docs.gitea.com/usage/actions/act-runner#start-the-runner-with-systemd) — у нас проще: один пользователь и без отдельного `config.yaml`, пока дефолты устраивают.
|
||||
|
||||
#### 3) Включи и запусти службу
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable gitea-act-runner.service
|
||||
sudo systemctl start gitea-act-runner.service
|
||||
sudo systemctl status gitea-act-runner.service
|
||||
```
|
||||
|
||||
В **`status`** должно быть **`active (running)`** зелёным. Если **`failed`** — смотри лог (шаг 5).
|
||||
|
||||
Полезные команды:
|
||||
|
||||
| Действие | Команда |
|
||||
| --------------------- | ------------------------------------------------------------- |
|
||||
| Остановить | `sudo systemctl stop gitea-act-runner` |
|
||||
| Запустить снова | `sudo systemctl start gitea-act-runner` |
|
||||
| Перезапуск | `sudo systemctl restart gitea-act-runner` |
|
||||
| Выключить автозапуск | `sudo systemctl disable gitea-act-runner` |
|
||||
| Проверка после ребута | перезагрузи машину, затем `systemctl status gitea-act-runner` |
|
||||
|
||||
#### 4) Проверка в Gitea
|
||||
|
||||
Как в **шаге E**: раннер снова **online** (иногда 10–30 секунд после `start`).
|
||||
|
||||
#### 5) Логи, если что-то не так
|
||||
|
||||
```bash
|
||||
sudo journalctl -u gitea-act-runner -e --no-pager
|
||||
```
|
||||
|
||||
В реальном времени:
|
||||
|
||||
```bash
|
||||
sudo journalctl -u gitea-act-runner -f
|
||||
```
|
||||
|
||||
Типичные ошибки: неверный **`User`** (нет прав на каталог), **`WorkingDirectory`** не тот (нет **`.runner`**), бинарник не исполняемый (`chmod +x`), или старый процесс `act_runner` ещё запущен вручную.
|
||||
|
||||
#### WSL2 (Ubuntu в Windows)
|
||||
|
||||
Если раннер стоит **внутри WSL2**:
|
||||
|
||||
1. На современных WSL **systemd уже может быть включён**. Проверка: `systemctl status` — без ошибки «running in chroot».
|
||||
2. Если `systemctl` недоступен: в файле **`/etc/wsl.conf`** внутри дистрибутива добавь блок **`[boot]`** с **`systemd=true`**, затем из **PowerShell** Windows выполни **`wsl --shutdown`**, снова зайди в Ubuntu и повтори шаги 2–3. Подробнее: [документация Microsoft про systemd в WSL](https://learn.microsoft.com/en-us/windows/wsl/systemd).
|
||||
|
||||
После **`wsl --shutdown`** раннер на WSL не работает, пока ты снова не откроешь WSL (это нормально для «домашнего» CI).
|
||||
|
||||
### Шаг E — проверка в веб-интерфейсе
|
||||
|
||||
Обнови **Настройки → Действия → Раннеры**: должен быть **1** раннер, статус **online**. У него в метках должно быть что-то вроде **`ubuntu-22.04`** (в связке с **host**).
|
||||
|
||||
### Если у тебя только Windows
|
||||
|
||||
Установи **WSL2** и дистрибутив **Ubuntu 22.04**, открой терминал Ubuntu и выполни шаги B–D **там** (это уже Linux). Файловую систему Windows из WSL видно как `/mnt/d/...`, но проще держать каталог раннера в домашнем каталоге Linux (`~/gitea-act-runner`).
|
||||
|
||||
Официальная документация: [Gitea — Act Runner](https://docs.gitea.com/usage/actions/act-runner).
|
||||
|
||||
Если раннер заводит **админ инстанса** — логика та же: раннер должен быть **online** и иметь метку, подходящую под **`runs-on`** в `release.yml` (сейчас **`ubuntu-22.04`**; при **`ubuntu-22.04:host`** в Gitea это сопоставляется с `runs-on: ubuntu-22.04`).
|
||||
|
||||
---
|
||||
|
||||
## Шаг 3 — включить Actions (если ещё не включены)
|
||||
|
||||
1. В том же **приватном** репозитории: **«Настройки»**.
|
||||
2. Раздел **«Действия»** / **«Actions»** — включи использование Actions для этого репозитория, если Gitea это спрашивает.
|
||||
3. Убедись, что в корне репозитория есть файл **`.gitea/workflows/release.yml`** (он уже в проекте `dnd_player`).
|
||||
|
||||
Бегунки Gitea должны иметь доступ в интернет (для `npm ci`, `actions/checkout` и т.д.) — это настраивает админ сервера.
|
||||
|
||||
### Метки `runs-on` (если раннер уже есть, но job не берётся)
|
||||
|
||||
- В списке раннеров посмотри **метки** у online-раннера.
|
||||
- В **`.gitea/workflows/release.yml`** в `runs-on:` должна совпадать **именно метка `ubuntu-22.04`** (Gitea сопоставляет её и с **`ubuntu-22.04:host`**, и с **`ubuntu-22.04:docker://...`** — см. [Labels](https://docs.gitea.com/usage/actions/act-runner#labels) в документации act_runner).
|
||||
- Если при регистрации указал только **`self-hosted`** — добавь **`ubuntu-22.04:host`** (или поменяй `runs-on` в workflow на твои метки и закоммить).
|
||||
|
||||
Сборка **Windows (NSIS)** и **Linux (AppImage x64 + arm64)** в CI идёт **на одном** `ubuntu-22.04`: NSIS + `wine64` для Win, `qemu-user-static` для кросс-сборки arm64 AppImage на amd64 (см. `release.yml`). **macOS** в этом job не собирается (ручная выкладка или отдельный раннер — см. `docs/MANUAL_MAC_UPDATE_UPLOAD.md`).
|
||||
|
||||
---
|
||||
|
||||
## Linux: AppImage и автообновление
|
||||
|
||||
- В ветке **`updates`** рядом с Windows лежат **`latest-linux.yml`** и файлы **`*.AppImage`** (x64 и arm64). Скрипт **`scripts/sync-update-feed.mjs`** делает **merge-копирование**: файлы других ОС в репозитории **не удаляются**, обновляются только имена, пришедшие из текущего CI-прогона.
|
||||
- **Базовый дистрибутив для бинарников:** сборка на **Ubuntu 22.04 (glibc 2.35)** — совместимость с «максимумом» настольных дистрибутивов с glibc не старее целевого; **Alpine/musl** без отдельной сборки не гарантируется.
|
||||
- **Запуск AppImage:** на части систем нужен **FUSE** (например `libfuse2` для старых форматов / документация дистрибутива). Подпись пакетов в первом варианте **не** используется (как договорённость по проекту).
|
||||
- Правила **electron-updater** в приложении те же: упакованная сборка и **активная лицензия** (`installAutoUpdater.ts`).
|
||||
- **Дифференциальное обновление** (запросы с несколькими HTTP `Range` по blockmap) на **Gitea raw** за nginx часто даёт **`400 Bad Request`** (`content-length: 18` — короткий текст ошибки); updater переходит на **полную** загрузку — обновление всё равно доходит. В коде по умолчанию **`disableDifferentialDownload: true`**, чтобы не делать лишний шаг (меньше шума в логе). Включить дифф снова: переменная **`DND_UPDATE_ENABLE_DIFFERENTIAL=1`** при запуске приложения — имеет смысл только если на сервере разрешили корректные Range / multi-range для raw.
|
||||
- Сообщения вида **`duplicated in blockmap`** в консоли — предупреждение electron-updater, на работоспособность обычно не влияют.
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4 — выпуск версии
|
||||
|
||||
1. В `package.json` версия должна совпасть с тегом (workflow при пуше тега делает `npm version` из имени тега — удобно).
|
||||
2. Закоммить все изменения в **приватный** репо, затем:
|
||||
|
||||
```bash
|
||||
git tag v1.0.1
|
||||
git push origin main
|
||||
git push origin v1.0.1
|
||||
```
|
||||
|
||||
(ветка может быть не `main` — подставь свою.)
|
||||
|
||||
3. Открой в Gitea **«Действия»** у приватного репо — должен появиться запуск **Release**. Дождись успеха job **`release`** (после появления раннера, см. раздел выше).
|
||||
|
||||
4. После успеха открой **публичный** `DndGamePlayerUpdates` → ветка **`updates`** — в корне должны появиться `latest.yml`, установщики и т.д.
|
||||
|
||||
---
|
||||
|
||||
## Контрольный чеклист
|
||||
|
||||
1. **`package.json` → `build.publish.url`** =
|
||||
`https://git.mailib.ru/ifontosh/DndGamePlayerUpdates/raw/branch/updates/`
|
||||
Совпадает с **`DND_UPDATE_FEED_URL`** (со слэшем в конце).
|
||||
2. В **DndGamePlayerUpdates** есть хотя бы один коммит (не пустой репо).
|
||||
3. В приватном репо заданы **все четыре** секрета из таблицы шага 2 (имена **не** начинаются с `GITEA_`).
|
||||
4. В репо с кодом есть **`.gitea/workflows/release.yml`**.
|
||||
5. Релиз: пуш тега `v*` → в Actions job **`release`**: сборка **Windows** + **Linux AppImage** и push feed; в публичном репо ветка **`updates`** содержит `latest.yml`, `latest-linux.yml`, установщики Windows и **`.AppImage`** для Linux (нужен online-раннер `ubuntu-22.04`, см. раздел про act_runner). Скрипт sync **не затирает** артефакты других платформ при обновлении.
|
||||
6. В приложении: обновления только **`app.isPackaged`** и при **активной лицензии** (см. `app/main/update/installAutoUpdater.ts`).
|
||||
|
||||
---
|
||||
|
||||
## Если `git push` в `updates` падает: `remote end hung up` / таймаут
|
||||
|
||||
Один коммит с **Windows + два AppImage** может быть **сотни МБ** — HTTPS-push иногда рвётся из‑за лимита буфера Git или таймаута **nginx / reverse proxy** перед Gitea. Отдельно встречается **`HTTP 500`** от Gitea/прокси на большом pack (например один `*-win.zip` ~200 MiB) — это уже **ошибка сервера** при приёме тела запроса; повторы push иногда помогают, но при стабильном 500 нужно править лимиты/таймауты на стороне Gitea и reverse proxy.
|
||||
|
||||
**В репозитории с кодом** скрипт `scripts/sync-update-feed.mjs` уже выставляет в клоне feed-репо:
|
||||
|
||||
- `http.postBuffer` **2 GiB**;
|
||||
- отключение «медленной передачи» (`http.lowSpeedLimit` / `http.lowSpeedTime`);
|
||||
- повторы **`git push`**: переменная **`DND_GIT_PUSH_RETRIES`** (по умолчанию **5**, максимум **10**), пауза **`DND_GIT_PUSH_RETRY_SLEEP_SEC`** (по умолчанию **30** с, максимум **120**). В workflow для шага sync задано **`DND_GIT_PUSH_RETRIES=8`** и **`DND_GIT_PUSH_RETRY_SLEEP_SEC=35`**.
|
||||
|
||||
Если ошибка сохраняется — на **сервере** (nginx и т.п.) проверьте, например:
|
||||
|
||||
- `client_max_body_size` — не меньше размера push (или `0` для безлимита, если политика безопасности позволяет);
|
||||
- `proxy_read_timeout` / `proxy_send_timeout` — **несколько минут** и больше для больших загрузок;
|
||||
- лимиты самого **Gitea** (`[repository.upload]`, `APP_MAX_FILE_SIZE` в зависимости от версии) — в документации вашей сборки Gitea.
|
||||
|
||||
---
|
||||
|
||||
## Линейная история в `UPDATES_REPO` (например DndGamePlayerUpdates)
|
||||
|
||||
Переписывается **только** публичный репозиторий из секрета **`UPDATES_REPO`**, ветка **`updates`**. Репозиторий с исходниками игры (**DndGamePlayer**) и его теги **не меняются**.
|
||||
|
||||
В workflow задано **`DND_UPDATES_SQUASH_HISTORY=1`**: после merge и подкладки артефактов скрипт делает **`git checkout --orphan`** и собирает историю **только текущего релиза**. Чтобы не отправлять один огромный pack (~700+ MiB) и не ловить `curl 55 Broken pipe`, загрузка идёт через **временную** ветку **`updates-upload-*`**: сначала small files, затем каждый большой файл отдельным push (порог **`DND_FEED_LARGE_FILE_BYTES`**, по умолчанию 64 MiB). Эта ветка **не заменяет** публичный feed: URL для клиентов по-прежнему **`…/raw/branch/updates/`**. `updates-upload-*` — только черновик на время job; в конце ветка **`updates`** передвигается на готовый коммит (`--force-with-lease` или первый push), временная ветка **удаляется** с remote.
|
||||
|
||||
На **сервере Gitea** старые объекты коммитов остаются «висячими», пока не отработает **сборка мусора** репозитория (настройки сервера / ручной `git gc` в bare-репо). Для пользователей приложения важны только URL **`latest*.yml`** и установщиков — они не меняются по смыслу.
|
||||
|
||||
Не запускайте **два релиза**, которые одновременно пушат feed, — возможна гонка и отказ **`--force-with-lease`**.
|
||||
|
||||
Перед подкладкой артефактов скрипт **удаляет** из корня ветки файлы вида **`DNDGamePlayer-<чужая версия>-*`** / **`DNDGamePlayer-Setup-<чужая версия>.exe`** (и связанные `.blockmap`), чтобы после `merge` не копились старые установщики (1.0.6 рядом с 1.0.14). Версия текущего релиза берётся из **`GIT_COMMIT_TAG`** (`v1.0.14` → `1.0.14`). Файлы **`latest*.yml`** перезаписываются копированием. Если в **`ARTIFACT_MAC`** нет ни одного файла сборки, **`.dmg` / `.pkg`** не удаляются — сохраняется вручную залитый mac в feed. Отключить очистку: **`DND_FEED_PRUNE_OLD_VERSIONS=0`**.
|
||||
|
||||
---
|
||||
|
||||
## Размер репозитория `DndGamePlayerUpdates` (почему ~4 GiB и как держать меньше)
|
||||
|
||||
### Почему место не возвращается само
|
||||
|
||||
При **`DND_UPDATES_SQUASH_HISTORY=1`** и **`git push --force-with-lease`** на ветке **`updates`** в истории остаётся по сути **один актуальный коммит**, но на **диске сервера** Git до **сборки мусора** продолжает хранить **недостижимые** объекты: старые коммиты, прерванные push, временные ветки **`updates-upload-*`**, старые pack-файлы. Пока не выполнен **`git gc --prune`**, размер каталога **`.git`** на Gitea может быть **сильно больше**, чем «один релиз файлов» в веб-интерфейсе.
|
||||
|
||||
### Сразу освободить место (один раз на сервере)
|
||||
|
||||
На машине Gitea найдите **bare**-репозиторий (типичный путь: `…/gitea-repositories/<владелец>/dndgameplayerupdates.git`), от имени пользователя с правами на каталог:
|
||||
|
||||
```bash
|
||||
cd /path/to/DndGamePlayerUpdates.git
|
||||
git gc --prune=now
|
||||
```
|
||||
|
||||
При очень большом накоплении мусора иногда используют **`--aggressive`** (дольше и тяжелее для CPU); чаще достаточно команды **без** него. После GC размер на диске должен приблизиться к сумме **текущих** файлов в последнем коммите.
|
||||
|
||||
В веб-интерфейсе Gitea смотрите раздел **администрирования** / **обслуживание** / **garbage collection** (названия зависят от версии): там может быть глобальный GC по всем репозиториям.
|
||||
|
||||
### Чтобы после каждого релиза снова не раздувалось
|
||||
|
||||
В **`app.ini`** Gitea включите **периодический GC репозиториев** (секция и ключи зависят от версии; ориентир — задача **`git_gc_repos`** в документации [config cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet)), например раз в **24 ч** или чаще, если релизы частые.
|
||||
|
||||
Уже включено в вашем пайплайне по смыслу: **squash** + **prune** старых имён установщиков — это уменьшает **набор файлов** в новом коммите; **физическое** освобождение на диске — задача **GC на сервере**.
|
||||
|
||||
### Можно ли «всегда не больше 1,5 GiB»
|
||||
|
||||
**Жёстко задать потолок Git не умеет.** Реальный минимум на диске ≈ размер **текущих** артефактов в ветке (два AppImage + NSIS + zip + blockmap + mac и т.д.) плюс служебные pack’и. Если один релиз по сумме бинарников уже **> 1,5 GiB**, репозиторий физически не уместится в лимит без **урезания артефактов** (например не выкладывать **`win.zip`**, если он не нужен updater’у) или без **выноса больших файлов из Git**.
|
||||
|
||||
Надёжный способ держать репо **маленьким постоянно**: в **`DndGamePlayerUpdates`** хранить только **`latest*.yml`** (и при необходимости подписи), а **`.exe` / `.AppImage` / `.zip`** выкладывать в **Gitea Releases**, **объектное хранилище** или **статический хост**, а в yml подставлять **прямые URL** туда. Тогда потребуется доработка **CI** и, при смене хоста, **`build.publish.url`** / секреты — это отдельная схема доставки, не только `git gc`.
|
||||
|
||||
---
|
||||
|
||||
## Если push отклонён: `(fetch first)` / `rejected`
|
||||
|
||||
Пока job собирает артефакты, в **`updates`** мог успеть попасть **другой** коммит (второй релиз, ручная выкладка). Скрипт `sync-update-feed.mjs` перед push (в режиме **без** squash) делает **`git fetch` + `git merge origin/updates`** (и после клона — то же в начале), плюс shallow **глубина** (`DND_UPDATES_CLONE_DEPTH`: по умолчанию **40**, при **`DND_UPDATES_SQUASH_HISTORY=1`** в скрипте по умолчанию **8**). В режиме **squash** перед финальным push merge **не** выполняется — уже смерженное дерево отправляется через временную ветку и затем публикуется force-with-lease. Не запускайте **два релиза одного и того же репо одновременно** по двум тегам — возможны конфликты merge.
|
||||
|
||||
---
|
||||
|
||||
## ENOSPC / «no space left on device» при sync
|
||||
|
||||
Частая причина: **дублирование** артефактов (`release/` → `_linux`/`_win` → временный клон в **`/tmp`**) на раннере с маленьким root. Сейчас CI **не копирует** в `_win`/`_linux`: `ARTIFACT_WIN` и `ARTIFACT_LINUX` указывают на **`release/`**, а временный клон feed создаётся под **`DND_FEED_TMP_ROOT`** (в workflow — `${{ github.workspace }}/.dnd-feed-tmp`). Скрипт по возможности делает **`rename`** файлов в клон (без второй полной копии на том же диске).
|
||||
|
||||
Если ошибка остаётся — на машине раннера нужно **освободить место** или увеличить диск / вынести workspace на больший том.
|
||||
|
||||
Перед `git clone` скрипт проверяет **свободное место на томе**, где лежит `DND_FEED_TMP_ROOT` (оценка: артефакты × 2.5 + ~1 GiB запас, минимум ~2 GiB). Если проверка мешает (редкий ложный срабатывание), можно задать **`DND_FEED_SKIP_DISK_CHECK=1`** (лучше всё же поправить диск).
|
||||
|
||||
Несколько **неудачных** `git fetch` подряд (обрыв TLS) могли раньше забивать диск частично распакованными pack-файлами; между попытками вызывается **`git gc --prune=now`**.
|
||||
|
||||
---
|
||||
|
||||
## Сбой fetch: `GnuTLS recv error` / `early EOF`
|
||||
|
||||
Сеть или TLS к серверу Gitea. Скрипт делает **несколько повторов** `git fetch` (`DND_GIT_FETCH_RETRIES`, по умолчанию **6**), между попытками — **`git gc --prune=now`**, для clone/fetch задано **`http.version=HTTP/1.1`** (иногда стабильнее за прокси). Если ветки **`updates` на сервере ещё нет**, merge **намеренно** пропускается (первый push feed); при **любой другой** ошибке fetch job **завершится ошибкой** — не будет «тихого» продолжения с последующим `ENOSPC` на `git add`.
|
||||
|
||||
При стабильных обрывах проверьте прокси/MTU/антивирус на раннере и лимиты прокси к Gitea.
|
||||
|
||||
---
|
||||
|
||||
## Поведение приложения
|
||||
|
||||
- Проверка только в **собранной** установке (`app.isPackaged`).
|
||||
- Только если **лицензия активна**.
|
||||
- Первый запрос примерно через **12 с** после старта; при смене лицензии — снова (не чаще **30 с**).
|
||||
- Для отладки можно задать переменную окружения **`DND_UPDATE_FEED_URL`** при запуске приложения (Windows / Linux / macOS) — переопределит feed.
|
||||
|
||||
Подпись кода в CI отключена: `CSC_IDENTITY_AUTO_DISCOVERY=false` (в т.ч. Linux AppImage без репозитория подписи).
|
||||
|
||||
---
|
||||
|
||||
## Локальная отладка feed
|
||||
|
||||
Запуск установленного приложения с другим URL (без пересборки): задать **`DND_UPDATE_FEED_URL`** в ярлыке или системных переменных окружения.
|
||||
|
||||
---
|
||||
|
||||
## Как сделать так, чтобы ассистент в Cursor мог «выпустить релиз»
|
||||
|
||||
У ассистента **нет своего аккаунта** на `git.mailib.ru`. Релиз = **появление тега `v*`** на нужном коммите в **приватном** репозитории с кодом → Gitea Actions собирает и пушит feed. Ниже два рабочих варианта.
|
||||
|
||||
### Вариант A — Gitea MCP (удобно из чата)
|
||||
|
||||
У тебя уже подключён MCP **user-gitea-mailib** с инструментом **`create_tag`**: по API создаётся тег на сервере (аналог `git tag` + `git push` тега).
|
||||
|
||||
**Что сделать один раз:**
|
||||
|
||||
1. В Cursor MCP для Gitea должен быть **включён и залогинен** под учёткой, у которой есть право **создавать теги** в приватном репо с `dnd_player`.
|
||||
2. Знать **`owner`** и **`repo`** этого репозитория (как в URL: `https://git.mailib.ru/OWNER/REPO`).
|
||||
|
||||
**Как просить в чате:**
|
||||
«Создай тег `v1.0.2` в репозитории `OWNER/REPO` с целевой веткой `main`» (или укажи SHA коммита). Перед этим **весь код релиза уже должен быть запушен** в эту ветку — тег вешается на последний коммит (или на явный `target`).
|
||||
|
||||
После создания тега зайди в **Действия** репозитория и проверь workflow **Release**.
|
||||
|
||||
_(Отдельно: `create_release` в MCP создаёт **запись релиза** на Gitea; сборку у тебя запускает именно **тег** и `release.yml`.)_
|
||||
|
||||
### Вариант B — команды `git` в терминале Cursor
|
||||
|
||||
Ассистент может выполнить у тебя локально:
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git tag v1.0.2 origin/main # или другая ветка / коммит
|
||||
git push origin v1.0.2
|
||||
```
|
||||
|
||||
**Что сделать один раз:**
|
||||
|
||||
1. Чтобы `git push` **не спрашивал пароль** каждый раз: настроить **учётные данные** (Windows: диспетчер учётных данных / `git credential-manager`; либо **SSH-ключ** и remote `git@git.mailib.ru:...`).
|
||||
2. Убедиться, что из того же окружения, где работает Cursor, `git push` в приватный репо уже проходил успешно.
|
||||
|
||||
Тогда в чате можно написать: «Поставь тег `v1.0.2` на `origin/main` и запушь тег» — ассистент выполнит команды в `dnd_player`.
|
||||
|
||||
### Ограничения
|
||||
|
||||
- Ассистент **не видит** твои пароли и не обходит Gitea: всё упирается в **MCP-токен** или **твои локальные git credentials**.
|
||||
- Если MCP отключён и git без настроенного доступа — релиз тегом придётся пушить **тебе** вручную (как в шаге 4 выше).
|
||||
|
||||
---
|
||||
|
||||
## Про коммит и пуш кода (не тег)
|
||||
|
||||
Закоммитить и запушить **изменения в файлах** ассистент может через те же механизмы: либо ты делаешь `git push` после правок, либо настроенный **git** / отдельный скрипт. Без доступа к remote ассистент только правит файлы в рабочей копии.
|
||||
Раньше артефакты пушились в публичный Git **`DndGamePlayerUpdates`**, ветка `updates`, URL вида
|
||||
`https://git.mailib.ru/.../DndGamePlayerUpdates/raw/branch/updates/`.
|
||||
Эта схема приводила к раздуванию репозитория, конфликтам merge, ENOSPC на раннере и HTTP 500 при `git push`. Она **снята с поддержки**.
|
||||
|
||||
Reference in New Issue
Block a user