From 24115b4ce6cddf2f65a2d41b5ce65d07df7023b5 Mon Sep 17 00:00:00 2001 From: galeon Date: Fri, 23 Oct 2026 10:45:27 +0300 Subject: [PATCH] release workflow fixes Signed-off-by: galeon --- .gitea/workflows/release.yml | 76 ++++++++++++++++++++++++++++-------- doc/build-and-release.md | 14 +++++-- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 39560ba..b89fe75 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -1,10 +1,18 @@ name: release +# master -> релиз v<версия>, если такого ещё нет +# rc -> пре-релиз v<версия>-rcN, N — следующий свободный номер +# тег vX.Y.Z -> релиз, тег vX.Y.Z-rcN -> пре-релиз +# ручной запуск -> только сборки, файлы остаются артефактами прогона on: push: + branches: [master, rc] tags: ["v*"] workflow_dispatch: +concurrency: + group: release-${{ github.ref }} + env: API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }} @@ -14,31 +22,63 @@ jobs: outputs: version: ${{ steps.meta.outputs.version }} tag: ${{ steps.meta.outputs.tag }} + skip: ${{ steps.meta.outputs.skip }} release_id: ${{ steps.release.outputs.id }} steps: - uses: actions/checkout@v4 - id: meta - name: Версия из CMakeLists.txt и сверка с тегом + name: Версия из CMakeLists.txt, тег и тип релиза + env: + TOKEN: ${{ secrets.RELEASE_TOKEN }} run: | version=$(sed -nE 's/^project\(BiLauncher VERSION ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CMakeLists.txt) [ -n "$version" ] || { echo "Не нашёл project(BiLauncher VERSION ...)"; exit 1; } - tag="" - if [ "${GITHUB_REF_TYPE}" = "tag" ]; then - tag="${GITHUB_REF_NAME}" - base="${tag#v}"; base="${base%%-*}" - if [ "$base" != "$version" ]; then - echo "Тег $tag не совпадает с версией $version в CMakeLists.txt"; exit 1 - fi - version="${tag#v}" - fi + + # Теги релизов, включая черновики (токену с правом записи API отдаёт и их) + release_tags=$(curl -fsS -H "Authorization: token $TOKEN" "$API/releases?limit=50" \ + | python3 -c 'import json,sys; [print(r["tag_name"]) for r in json.load(sys.stdin)]') + has_release() { printf '%s\n' "$release_tags" | grep -xF "$1" > /dev/null; } + # У черновика тега в git ещё нет, поэтому смотрим и в git, и в релизы + known() { + git ls-remote --tags origin | sed -E 's#.*refs/tags/##; s/\^\{\}$//' + printf '%s\n' "$release_tags" + } + + tag=""; skip=false + case "${GITHUB_REF_TYPE}:${GITHUB_REF_NAME}" in + tag:*) + tag="${GITHUB_REF_NAME}" + base="${tag#v}"; base="${base%%-*}" + if [ "$base" != "$version" ]; then + echo "Тег $tag не совпадает с версией $version в CMakeLists.txt"; exit 1 + fi + # Тег мог создать сам релиз из прогона по ветке — тогда второй раз не собираем + if has_release "$tag"; then + echo "Релиз $tag уже есть"; skip=true + fi + ;; + branch:master) + tag="v$version" + if known | grep -xF "$tag" > /dev/null; then + echo "Релиз $tag уже есть, поднимите версию в CMakeLists.txt"; skip=true + fi + ;; + branch:rc) + n=$(known | sed -nE "s/^v${version//./\\.}-rc([0-9]+)\$/\1/p" | sort -n | tail -1) + tag="v$version-rc$(( ${n:-0} + 1 ))" + ;; + esac + [ -n "$tag" ] && version="${tag#v}" + echo "version=$version" >> "$GITHUB_OUTPUT" echo "tag=$tag" >> "$GITHUB_OUTPUT" - echo "Версия: $version, тег: ${tag:-нет}" + echo "skip=$skip" >> "$GITHUB_OUTPUT" + echo "Версия: $version, тег: ${tag:-нет}, пропуск: $skip" - id: release name: Черновик релиза - if: steps.meta.outputs.tag != '' + if: steps.meta.outputs.tag != '' && steps.meta.outputs.skip != 'true' env: TOKEN: ${{ secrets.RELEASE_TOKEN }} TAG: ${{ steps.meta.outputs.tag }} @@ -47,17 +87,19 @@ jobs: notes=$(awk -v v="$base" ' /^## \[/ { if (on) exit; if (index($0, "[" v "]")) { on=1; next } } on' CHANGELOG.md) - prerelease=false; case "$TAG" in *-*) prerelease=true;; esac - body=$(python3 -c 'import json,sys; print(json.dumps({"tag_name":sys.argv[1],"name":"BiLauncher "+sys.argv[1],"body":sys.argv[2],"draft":True,"prerelease":sys.argv[3]=="true"}))' \ - "$TAG" "$notes" "$prerelease") + prerelease=false; case "$TAG" in *-rc*) prerelease=true;; esac + # target_commitish: у новой ветки тег появится на этом коммите при публикации + body=$(python3 -c 'import json,sys; print(json.dumps({"tag_name":sys.argv[1],"target_commitish":sys.argv[4],"name":"BiLauncher "+sys.argv[1],"body":sys.argv[2],"draft":True,"prerelease":sys.argv[3]=="true"}))' \ + "$TAG" "$notes" "$prerelease" "$GITHUB_SHA") id=$(curl -fsS -X POST "$API/releases" \ -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ -d "$body" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])') echo "id=$id" >> "$GITHUB_OUTPUT" - echo "Создан черновик релиза $TAG (id $id)" + echo "Создан черновик $([ "$prerelease" = true ] && echo пре-)релиза $TAG (id $id)" build-linux: needs: create-release + if: needs.create-release.outputs.skip != 'true' runs-on: linux env: VERSION: ${{ needs.create-release.outputs.version }} @@ -111,6 +153,7 @@ jobs: build-windows: needs: create-release + if: needs.create-release.outputs.skip != 'true' runs-on: windows env: VERSION: ${{ needs.create-release.outputs.version }} @@ -181,6 +224,7 @@ jobs: build-macos: needs: create-release + if: needs.create-release.outputs.skip != 'true' runs-on: macos env: VERSION: ${{ needs.create-release.outputs.version }} diff --git a/doc/build-and-release.md b/doc/build-and-release.md index 3277e0b..f820730 100644 --- a/doc/build-and-release.md +++ b/doc/build-and-release.md @@ -110,14 +110,22 @@ QML-модуль собирается в `/qml/BiLauncher` (`OUTPUT_DIREC поэтому этот шаг на совести выпускающего. См. [testing.md](testing.md). 1. Поднять версию в `project(BiLauncher VERSION ...)` в `CMakeLists.txt`. 2. Добавить в `CHANGELOG.md` раздел `## [x.y.z] — дата`. Его текст станет описанием релиза. -3. Закоммитить и запушить тег `vx.y.z`. Для предрелиза — `vx.y.z-rc1` (всё после дефиса делает - релиз pre-release). +3. Запустить релиз одним из способов: + - **Пуш в `master`** — полноценный релиз `vx.y.z`. Если релиз или тег с этой версией уже есть, + прогон ничего не собирает: сначала поднимите версию. + - **Пуш в `rc`** — пре-релиз `vx.y.z-rcN`, где `N` — следующий свободный номер для этой версии + (`rc1`, `rc2`, ...). + - **Тег `vx.y.z`** — полноценный релиз, **тег `vx.y.z-rcN`** — пре-релиз. Пре-релизом + становится только тег с суффиксом `-rc`, любой другой суффикс даёт обычный релиз. Если тег не совпадает с версией в `CMakeLists.txt` (без учёта суффикса), прогон сразу падает. +Для веток тег создаёт сам Gitea при публикации релиза, на коммите прогона. Этот тег снова +запускает `release.yml`, но прогон видит, что релиз уже есть, и ничего не собирает. + ### Что происходит -1. **create-release** (Linux) — сверяет тег с версией, вырезает раздел из `CHANGELOG.md` и +1. **create-release** (Linux) — определяет тег (из пуша тега или по ветке), сверяет его с версией, вырезает раздел из `CHANGELOG.md` и создаёт **черновик** релиза. 2. Параллельно три сборки, каждая прикладывает свои файлы к черновику: - **Linux**: `BiLauncher--x86_64.AppImage` и `BiLauncher--linux-x86_64.tar.gz`. Сборка