mirror of
https://github.com/by-sonic/tglock.git
synced 2026-09-05 18:16:09 +03:00
ci: страж тега на HEAD и записанный порядок выпуска (#41)
Первый заход v2.0.0-beta.8 собрался на всех трёх платформах и упал на публикации с «Resource not accessible by integration». Сообщение про права уводит не туда: права были ровно те же, что у beta.7 (Contents: write), tauri-action тот же коммит, правил на теги нет. Настоящая причина — положение тега. Токен Actions создаёт релиз только на HEAD ветки по умолчанию. Тег поставили на chore(release), следом дописали коммит в main, и к моменту вызова API тег отстал на один коммит. Задача guard сверяет тег с HEAD и валится за секунды до сборок, вместо загадочного 403 через восемь минут. Она ловит тег на старом коммите, но не ловит гонку «запушили в main во время сборки» — то есть ровно тот случай, который и произошёл. Поэтому главная защита не в ней, а в порядке действий, записанном в docs/RELEASING.md: тег ставится последним, во время релиза в main не пушим. Логика стража прогнана на обеих ветках на реальных SHA этого репозитория. Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>
This commit is contained in:
@@ -9,7 +9,40 @@ permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
# Токен Actions умеет создавать релиз только на HEAD ветки по умолчанию. Если
|
||||
# тег отстал хоть на один коммит, GitHub отвечает «Resource not accessible by
|
||||
# integration» — сообщение про права, хотя права в порядке и дело в положении
|
||||
# тега. Так утонул v2.0.0-beta.8: тег поставили, следом дописали коммит в main,
|
||||
# и три сборки по восемь минут закончились загадочным 403.
|
||||
#
|
||||
# Проверка занимает секунды и идёт до сборок. Но она НЕ закрывает гонку: если
|
||||
# запушить в main уже после её прохождения, публикация всё равно упадёт — как и
|
||||
# случилось с beta.8. Единственная настоящая защита — порядок действий: тег
|
||||
# ставится последним, и пока идёт релиз, в main не пушим.
|
||||
guard:
|
||||
name: Тег должен стоять на HEAD
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Сверить тег с веткой по умолчанию
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
branch=$(gh api "repos/$GITHUB_REPOSITORY" -q .default_branch)
|
||||
head=$(gh api "repos/$GITHUB_REPOSITORY/commits/$branch" -q .sha)
|
||||
if [ "$head" = "$GITHUB_SHA" ]; then
|
||||
echo "$GITHUB_REF_NAME и $branch указывают на $head — собираем."
|
||||
exit 0
|
||||
fi
|
||||
echo "::error::$GITHUB_REF_NAME стоит на $GITHUB_SHA, а $branch — на $head. Публикация упадёт с 403, потому что токен Actions создаёт релиз только на HEAD ветки по умолчанию."
|
||||
echo "Переставьте тег и запушьте заново:"
|
||||
echo " git tag -d $GITHUB_REF_NAME"
|
||||
echo " git push origin :refs/tags/$GITHUB_REF_NAME"
|
||||
echo " git tag -a $GITHUB_REF_NAME $head -m 'TGLock ...'"
|
||||
echo " git push origin $GITHUB_REF_NAME"
|
||||
exit 1
|
||||
|
||||
publish:
|
||||
needs: guard
|
||||
name: Build ${{ matrix.platform }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# Как выпускать релиз
|
||||
|
||||
## Порядок важен
|
||||
|
||||
Токен GitHub Actions создаёт релиз **только на HEAD ветки по умолчанию**. Если тег
|
||||
отстанет от `main` хотя бы на один коммит, публикация упадёт с ошибкой
|
||||
`Resource not accessible by integration` — сообщение про права, хотя права в
|
||||
порядке и дело в положении тега.
|
||||
|
||||
Отсюда единственное жёсткое правило: **тег ставится последним, и пока идёт
|
||||
релиз, в `main` не пушим.**
|
||||
|
||||
## Шаги
|
||||
|
||||
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. Поставить аннотированный тег на этот же коммит и запушить его:
|
||||
|
||||
```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,
|
||||
документации, чего угодно — после публикации релиза.
|
||||
|
||||
## Проверить, что выпустили
|
||||
|
||||
Зелёный workflow — это ещё не доказательство. В бетах 2 и 3 сборка была зелёной,
|
||||
а в приложение попадал headless-бинарь вместо графического. Поэтому проверяем
|
||||
содержимое, а не имя файла:
|
||||
|
||||
```bash
|
||||
gh release download vX.Y.Z --repo by-sonic/tglock -p 'TGLock_universal.app.tar.gz' -D /tmp/check
|
||||
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`) и ругается, если в бандле оказался не тот.
|
||||
|
||||
## Если публикация всё-таки упала с `Resource not accessible by integration`
|
||||
|
||||
Значит, тег разошёлся с `main`. Сверьте:
|
||||
|
||||
```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 <sha ветки main> -m "TGLock X.Y.Z"
|
||||
git push origin vX.Y.Z
|
||||
```
|
||||
|
||||
Перезапускать упавший workflow бесполезно: он возьмёт тот же отставший тег и
|
||||
упадёт снова.
|
||||
|
||||
## Что защищает автоматически
|
||||
|
||||
Первым шагом релиза идёт задача `guard`: она сверяет тег с HEAD ветки по
|
||||
умолчанию и валится за секунды, не запуская сборки. Она ловит тег, поставленный
|
||||
на старый коммит.
|
||||
|
||||
Она **не** ловит гонку: если запушить в `main` уже после её прохождения, но до
|
||||
конца сборки, публикация упадёт. Ровно так утонул первый заход v2.0.0-beta.8.
|
||||
От этого защищает только правило из первого раздела.
|
||||
Reference in New Issue
Block a user