diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8b9d6b9..266082d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -111,7 +111,8 @@ jobs: - **Сервер, контейнер, машина без монитора** — `tglock-cli-*`: то же самое, но без графического интерфейса Если Windows ругается на файл — [почему так и что с этим делать](https://github.com/by-sonic/tglock#-антивирус-ругается-smartscreen-предупреждает-virustotal-показывает-детекты). - releaseDraft: false + # Publish only after every platform, CLI and exact-commit APK is verified. + releaseDraft: true prerelease: false args: ${{ matrix.args }} @@ -162,6 +163,7 @@ jobs: - uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} + draft: true files: arm64-cli/* cli: @@ -229,5 +231,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref_name }} + draft: true prerelease: false files: ${{ matrix.asset }} diff --git a/Cargo.lock b/Cargo.lock index e1e183f..7804947 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3822,7 +3822,7 @@ dependencies = [ [[package]] name = "tglock" -version = "2.0.0-beta.14" +version = "2.0.0-beta.15" dependencies = [ "aes", "cipher", diff --git a/Cargo.toml b/Cargo.toml index aeb3377..147801b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tglock" -version = "2.0.0-beta.14" +version = "2.0.0-beta.15" edition = "2021" rust-version = "1.88" description = "Telegram unblock via local WebSocket tunnel" diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 23f341e..807fea6 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -1,38 +1,64 @@ # Как выпускать релиз -## Порядок важен +## Подготовка через PR -Токен GitHub Actions создаёт релиз **только на HEAD ветки по умолчанию**. Если тег -отстанет от `main` хотя бы на один коммит, публикация упадёт с ошибкой -`Resource not accessible by integration` — сообщение про права, хотя права в -порядке и дело в положении тега. +1. Поднять версию согласованно в шести файлах: + - `Cargo.toml` — версия пакета `tglock`; + - `Cargo.lock` — версия только пакета `tglock`, без обновления зависимостей; + - `tauri.conf.json` — версия приложения и имён установщиков; + - `package.json` — версия frontend-пакета; + - `package-lock.json` — верхняя версия и `packages[""].version`; + - `ui/main.ts` — версия копируемого диагностического отчёта. +2. Подготовить описание изменений и проверок, отдельно указав экспериментальные + платформы и непроверенные сценарии. Android получает `versionName`/`versionCode` + из конфигурации Tauri при сборке; сгенерированный `tauri.properties` не коммитится. +3. Проверить финальные изменения PR и слить его в `main` с соблюдением обязательных + проверок ветки. Дождаться зелёных проверок и Android workflow на итоговом HEAD + `main` до создания тега. APK предыдущего PR-коммита не заменяет артефакт этого + коммита: `headSha` Android run должен совпадать с коммитом будущего тега. -Отсюда единственное жёсткое правило: **тег ставится последним, и пока идёт -релиз, в `main` не пушим.** +## Тег и сборка -## Шаги +Release workflow этого репозитория допускает тег только на текущем HEAD ветки +по умолчанию. Guard сохраняет прежнюю защиту от выпуска другого коммита: +ранее расхождение тега и `main` сопровождалось ошибкой публикации +`Resource not accessible by integration`. -1. Влить в `main` всё, что должно попасть в релиз, и дождаться зелёного CI. -2. Поднять версию **в двух местах** — `Cargo.toml` и `tauri.conf.json`. Они - должны совпадать: имена файлов бандла берутся из `tauri.conf.json`. -3. Закоммитить подъём версии и запушить в `main`. -4. Убедиться, что больше ничего не уедет: `git ls-remote origin refs/heads/main` - должен совпасть с локальным `git rev-parse HEAD`. -5. Поставить аннотированный тег на этот же коммит и запушить его: +1. Сверить `git ls-remote origin refs/heads/main` и локальный + `git rev-parse HEAD` после перехода на финальный коммит `main`. +2. Убедиться, что выбранная версия и тег ещё не существуют, затем поставить + аннотированный тег на этот коммит: ```bash git tag -a v2.0.0-beta.N -m "TGLock 2.0.0-beta.N" git push origin v2.0.0-beta.N ``` -6. **Ничего не пушить в `main`, пока сборка не закончится.** Правки README, - документации, чего угодно — после публикации релиза. +3. Пока релиз собирается, не добавлять коммиты в `main`. Guard проверяет HEAD + в начале работы и не устраняет гонку после проверки. +4. Дождаться **всех** jobs Release. Workflow создаёт **draft** и сохраняет его + черновиком при загрузке GUI, CLI и ARM64. Частично загруженный выпуск не должен + становиться общедоступным до проверок. -## Проверить, что выпустили +Ручной `workflow_dispatch` запускайте на релизном теге, а не на ветке: часть +загрузчиков использует `github.ref_name` как имя релиза. -Зелёный workflow — это ещё не доказательство. В бетах 2 и 3 сборка была зелёной, -а в приложение попадал headless-бинарь вместо графического. Поэтому проверяем -содержимое, а не имя файла: +## Проверка артефактов и публикация + +Зелёный workflow сам по себе недостаточен. В бетах 2 и 3 в GUI-бандл попадал +headless-бинарь, поэтому проверяются содержимое и происхождение: + +- Windows: GUI `.exe` и `tglock-cli-x86_64-pc-windows-msvc.exe`. +- macOS: универсальные `.dmg`, `.app.tar.gz` и CLI. +- Linux x64: `.AppImage`, `.deb` и CLI. +- ARM64 Linux: `tglock-cli-aarch64-unknown-linux-musl` и его `.sha256`; + workflow проверяет ELF без динамических зависимостей и запуск бинаря. +- Android: скачать ARM64 debug APK из успешного Android run с `headSha`, + совпадающим с коммитом тега. Сохранить имя с версией и явной пометкой + `android-arm64-debug`, прикрепить APK к тому же draft. Указать экспериментальный + статус и ограничения debug-подписи из [ANDROID.md](ANDROID.md). + +Пример проверки скачанного macOS-бандла: ```bash gh release download vX.Y.Z --repo by-sonic/tglock -p 'TGLock_universal.app.tar.gz' -D /tmp/check @@ -40,35 +66,35 @@ tar -xzf /tmp/check/TGLock_universal.app.tar.gz -C /tmp/check python scripts/verify_bundle_binary.py /tmp/check/TGLock.app/Contents/MacOS/tglock ``` -Скрипт ищет внутри бинаря маркеры GUI (`ipc.localhost`, `wry`) и маркеры CLI -(`allow-direct`, `secret-file`) и ругается, если в бандле оказался не тот. +Проверьте версию скачанного CLI и хотя бы один реальный протокольный обмен +через него по [LIVE_PROBE.md](LIVE_PROBE.md). Зафиксируйте, какие платформы +исполнены локально, а какие проверены CI. Секрет локального прокси в заметки и +публичные артефакты не включается. -## Если публикация всё-таки упала с `Resource not accessible by integration` +Когда набор файлов полон, подписи/контрольные суммы и версии сверены, а release +notes готовы, опубликуйте draft. Например: -Значит, тег разошёлся с `main`. Сверьте: +```bash +gh release edit vX.Y.Z --repo by-sonic/tglock --draft=false --notes-file release-notes.md +``` + +Исторически `v2.0.0-beta.*` в этом репозитории публикуются с `prerelease=false`; +workflow сохраняет эту настройку. После публикации проверьте публичную страницу +релиза, ссылки скачивания и список файлов. Краткий пост об обновлении должен +ссылаться на опубликованный релиз и отделять проверенные исправления от +экспериментальных платформ. + +## Если сборка или публикация упала + +Сначала прочитайте ошибку и сверяйте коммит тега, `main`, workflow run и версии. +Не делайте вывод о причине только из текста `Resource not accessible by +integration`: он может относиться и к правам токена. ```bash git ls-remote origin refs/heads/main 'refs/tags/vX.Y.Z^{}' ``` -Если SHA разные — переставьте тег на HEAD и запушьте заново: - -```bash -git tag -d vX.Y.Z -git push origin :refs/tags/vX.Y.Z -git tag -a vX.Y.Z -m "TGLock X.Y.Z" -git push origin vX.Y.Z -``` - -Перезапускать упавший workflow бесполезно: он возьмёт тот же отставший тег и -упадёт снова. - -## Что защищает автоматически - -Первым шагом релиза идёт задача `guard`: она сверяет тег с HEAD ветки по -умолчанию и валится за секунды, не запуская сборки. Она ловит тег, поставленный -на старый коммит. - -Она **не** ловит гонку: если запушить в `main` уже после её прохождения, но до -конца сборки, публикация упадёт. Ровно так утонул первый заход v2.0.0-beta.8. -От этого защищает только правило из первого раздела. +Если это ошибка инфраструктуры, повторите упавшие jobs на том же коммите. +Если нужна правка исходников, внесите её через PR и выберите новую версию для +нового тега. Опубликованные теги и бинарные артефакты не заменяйте: пользователи +должны иметь возможность воспроизвести уже выпущенную версию. diff --git a/package-lock.json b/package-lock.json index ffe01b0..b5603f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tglock-ui", - "version": "2.0.0-beta.14", + "version": "2.0.0-beta.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tglock-ui", - "version": "2.0.0-beta.14", + "version": "2.0.0-beta.15", "dependencies": { "@tauri-apps/api": "^2.8.0" }, diff --git a/package.json b/package.json index c7b9c49..f582150 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "tglock-ui", "private": true, - "version": "2.0.0-beta.14", + "version": "2.0.0-beta.15", "type": "module", "scripts": { "test:worker": "node --experimental-vm-modules --test worker/tglock-worker.test.js", diff --git a/tauri.conf.json b/tauri.conf.json index fabab9f..f818063 100644 --- a/tauri.conf.json +++ b/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "TGLock", - "version": "2.0.0-beta.14", + "version": "2.0.0-beta.15", "identifier": "com.bysonic.tglock", "mainBinaryName": "tglock", "build": { diff --git a/ui/main.ts b/ui/main.ts index 360e999..5e5bde8 100644 --- a/ui/main.ts +++ b/ui/main.ts @@ -451,7 +451,7 @@ async function copyDiagnostics(): Promise { // Public reports exclude proxy links, worker domains and free-form logs. const report = { application: "TGLock", - version: "2.0.0-beta.14", + version: "2.0.0-beta.15", running: status.running, activeConnections: status.activeConnections, tunnels: status.tunnels,