From 56ca4262d793dae0d04ed9fb1dbf508c4ce8cc3e Mon Sep 17 00:00:00 2001 From: Ezra Maccabee Date: Mon, 27 Jul 2026 10:15:28 +0300 Subject: [PATCH] ci: migrate to Forgejo Actions and stabilize pipelines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Configured self-hosted runner with docker-in-docker support - Disabled GHA cache backend for buildx to prevent timeouts - Unified CI execution via just module (ci.just) - Downgraded artifact actions to v3 for Forgejo compatibility ci: path fixes №3 --- .forgejo/workflows/ci.yml | 108 +++++++++++ .forgejo/workflows/release.yml | 167 ++++++++++++++++ .github/workflows/ci.yml | 108 ----------- .github/workflows/release.yml | 338 --------------------------------- 4 files changed, 275 insertions(+), 446 deletions(-) create mode 100644 .forgejo/workflows/ci.yml create mode 100644 .forgejo/workflows/release.yml delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/release.yml diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..45ed73f --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,108 @@ +name: CI + +on: + push: + branches: + - dev + - main + pull_request: + workflow_dispatch: + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build in devcontainer + runs-on: ubuntu-latest + timeout-minutes: 90 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Build devcontainer image + uses: docker/build-push-action@v7 + with: + context: . + file: .devcontainer/Dockerfile + tags: tft-devcontainer-ci:latest + load: true + + - name: Show tool versions in container + run: | + docker run --rm --user root \ + --volumes-from $(cat /etc/hostname) \ + -w "$GITHUB_WORKSPACE" \ + tft-devcontainer-ci:latest \ + bash -lc 'just --version && cmake --version && ninja --version && arm-none-eabi-gcc --version | head -n 1 && uv --version' + + - name: Sync tools and Run CI build + run: | + docker run --rm --user root \ + --volumes-from $(cat /etc/hostname) \ + -w "$GITHUB_WORKSPACE" \ + tft-devcontainer-ci:latest \ + bash -lc 'cd tools/host && uv sync && cd ../.. && just ci::build' + + - name: Upload build directory + if: always() + uses: actions/upload-artifact@v3 + with: + name: build-tree + path: build/ + if-no-files-found: warn + retention-days: 7 + + test: + name: Host tests in devcontainer + runs-on: ubuntu-latest + timeout-minutes: 90 + needs: build + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Build devcontainer image + uses: docker/build-push-action@v7 + with: + context: . + file: .devcontainer/Dockerfile + tags: tft-devcontainer-ci:latest + load: true + + - name: Download build directory artifact + uses: actions/download-artifact@v3 + with: + name: build-tree + path: build/ + + - name: Sync tools and Run host tests + run: | + docker run --rm --user root \ + --volumes-from $(cat /etc/hostname) \ + -w "$GITHUB_WORKSPACE" \ + tft-devcontainer-ci:latest \ + bash -lc 'cd tools/host && uv sync && cd ../.. && just ci::test' + + - name: Upload test logs and build directory + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-artifacts + path: | + build/ + if-no-files-found: warn + retention-days: 7 diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml new file mode 100644 index 0000000..dcd7ec8 --- /dev/null +++ b/.forgejo/workflows/release.yml @@ -0,0 +1,167 @@ +name: Release + +on: + push: + tags: + - "tui-v*" + - "firmware-v*" + - "bootloader-v*" + workflow_dispatch: + inputs: + release_type: + description: "Тестовый прогон без публикации (job publish-* не запускается вне push тега)" + type: choice + options: + - tui + - firmware + - bootloader + default: tui + +concurrency: + group: release-${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + +jobs: + firmware: + name: Build firmware_test HAB (Debug) + bootloader HAB (Release) + runs-on: ubuntu-latest + timeout-minutes: 90 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Build devcontainer image + uses: docker/build-push-action@v7 + with: + context: . + file: .devcontainer/Dockerfile + tags: tft-devcontainer-ci:latest + load: true + + - name: Проверить, что тег совпадает с версией в CMakeLists.txt + if: startsWith(github.ref, 'refs/tags/firmware-v') + run: | + tag_version="${GITHUB_REF_NAME#firmware-v}" + file_version=$(grep -m1 -oE 'VERSION [0-9]+\.[0-9]+\.[0-9]+' firmware/test/CMakeLists.txt | awk '{print $2}') + if [[ "$tag_version" != "$file_version" ]]; then + echo "::error::Тег ${GITHUB_REF_NAME} (версия ${tag_version}) не совпадает с VERSION в firmware/test/CMakeLists.txt (${file_version})" + exit 1 + fi + echo " ✅ Версия тега совпадает с CMakeLists.txt: ${file_version}" + + - name: Sync tools and Собрать firmware_test HAB (Debug) + run: | + docker run --rm --user root \ + --volumes-from $(cat /etc/hostname) \ + -w "$GITHUB_WORKSPACE" \ + tft-devcontainer-ci:latest \ + bash -lc 'cd tools/host && uv sync && cd ../.. && just build::hab-firmware-test-debug' + + - name: Upload firmware_test_hab.bin + uses: actions/upload-artifact@v3 + with: + name: firmware-hab-debug + path: build/Debug/firmware_test_hab.bin + if-no-files-found: error + retention-days: 14 + + - name: Проверить, что тег совпадает с версией в CMakeLists.txt (bootloader) + if: startsWith(github.ref, 'refs/tags/bootloader-v') + run: | + tag_version="${GITHUB_REF_NAME#bootloader-v}" + file_version=$(grep -m1 -oE 'VERSION [0-9]+\.[0-9]+\.[0-9]+' firmware/bootloader/CMakeLists.txt | awk '{print $2}') + if [[ "$tag_version" != "$file_version" ]]; then + echo "::error::Тег ${GITHUB_REF_NAME} (версия ${tag_version}) не совпадает с VERSION в firmware/bootloader/CMakeLists.txt (${file_version})" + exit 1 + fi + echo " ✅ Версия тега совпадает с CMakeLists.txt: ${file_version}" + + - name: Sync tools and Собрать bootloader HAB (Release) + run: | + docker run --rm --user root \ + --volumes-from $(cat /etc/hostname) \ + -w "$GITHUB_WORKSPACE" \ + tft-devcontainer-ci:latest \ + bash -lc 'cd tools/host && uv sync && cd ../.. && just build::hab-bootloader-release' + + - name: Upload bootloader_hab.bin + uses: actions/upload-artifact@v3 + with: + name: bootloader-hab-release + path: build/Release/bootloader_hab.bin + if-no-files-found: error + retention-days: 14 + + publish-firmware: + name: Publish firmware release + needs: firmware + if: startsWith(github.ref, 'refs/tags/firmware-v') + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download firmware_test_hab.bin + uses: actions/download-artifact@v3 + with: + name: firmware-hab-debug + path: release-assets/ + + - name: Create Forgejo Release + uses: softprops/action-gh-release@v2 + with: + files: release-assets/firmware_test_hab.bin + name: "firmware_test ${{ github.ref_name }}" + generate_release_notes: true + + publish-bootloader: + name: Publish bootloader release + needs: firmware + if: startsWith(github.ref, 'refs/tags/bootloader-v') + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download bootloader_hab.bin + uses: actions/download-artifact@v3 + with: + name: bootloader-hab-release + path: release-assets/ + + - name: Create Forgejo Release + uses: softprops/action-gh-release@v2 + with: + files: release-assets/bootloader_hab.bin + name: "bootloader ${{ github.ref_name }}" + body: "⚠️ HAB-подпись — ТЕСТОВЫЙ ключ (dev/pre-series, HAB Open). Не production. Реальная SRK-церемония — firmware/bootloader/SIGNING_CEREMONY.md." + + # ========================================================================= + # Секция сборки TUI временно отключена. + # Для ее работы необходимо зарегистрировать агенты forgejo-runner + # нативно (не в Docker) на машинах с macOS и Windows с соответствующими тегами. + # ========================================================================= + + # service-tui-macos: + # name: Package service-tui (macOS) + # ... + + # service-tui-windows: + # name: Package service-tui (Windows) + # ... + + # publish-tui: + # name: Publish service-tui release + # ... diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 92d7d0c..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,108 +0,0 @@ -name: CI - -on: - push: - branches: - - dev - - main - pull_request: - workflow_dispatch: - -concurrency: - group: ci-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - name: Build in devcontainer - runs-on: ubuntu-latest - timeout-minutes: 90 - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Build devcontainer image with cache - uses: docker/build-push-action@v7 - with: - context: . - file: .devcontainer/Dockerfile - tags: tft-devcontainer-ci:latest - load: true - cache-from: type=gha,scope=tft-devcontainer - cache-to: type=gha,mode=max,scope=tft-devcontainer - - - name: Show tool versions in container - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace tft-devcontainer-ci:latest bash -lc 'just --version && cmake --version && ninja --version && arm-none-eabi-gcc --version | head -n 1 && uv --version' - - - name: Sync host Python tools inside container - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace tft-devcontainer-ci:latest bash -lc 'cd tools/host && uv sync' - - - name: Run CI build inside container - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace tft-devcontainer-ci:latest bash -lc 'just ci::build' - - - name: Upload build directory - if: always() - uses: actions/upload-artifact@v4 - with: - name: build-tree - path: build/ - if-no-files-found: warn - retention-days: 7 - - test: - name: Host tests in devcontainer - runs-on: ubuntu-latest - timeout-minutes: 90 - needs: build - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Build devcontainer image with cache - uses: docker/build-push-action@v7 - with: - context: . - file: .devcontainer/Dockerfile - tags: tft-devcontainer-ci:latest - load: true - cache-from: type=gha,scope=tft-devcontainer - cache-to: type=gha,mode=max,scope=tft-devcontainer - - - name: Download build directory artifact - uses: actions/download-artifact@v4 - with: - name: build-tree - path: build/ - - - name: Sync host Python tools inside container - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace tft-devcontainer-ci:latest bash -lc 'cd tools/host && uv sync' - - - name: Run host tests inside container - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace tft-devcontainer-ci:latest bash -lc 'just ci::test' - - - name: Upload test logs and build directory - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-artifacts - path: | - build/ - if-no-files-found: warn - retention-days: 7 \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 4fc1b48..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,338 +0,0 @@ -name: Release - -# Раздельные теги (bootloader — Фаза 5, firmware/bootloader/PLAN.md): -# firmware_test, bootloader и service-tui версионируются и релизятся -# независимо друг от друга. -# firmware-vX.Y.Z → publish-firmware (только firmware_test_hab.bin, Debug) -# bootloader-vX.Y.Z → publish-bootloader (только bootloader_hab.bin, Release, -# подписан ТЕСТОВЫМ HAB-ключом — см. -# firmware/bootloader/SIGNING_CEREMONY.md) -# tui-vX.Y.Z → publish-tui (service-tui-vX.Y.Z-{macos,windows}.zip) -# HAB firmware_test/bootloader, вшиваемые в TUI-бандл, всегда собираются заново -# из текущего HEAD тега tui-v*, а не берутся из отдельных релизов — так проще -# и не тянет зависимость на чужой GitHub Release. -on: - push: - tags: - - "tui-v*" - - "firmware-v*" - - "bootloader-v*" - workflow_dispatch: - inputs: - release_type: - description: "Тестовый прогон без публикации (job publish-* не запускается вне push тега)" - type: choice - options: - - tui - - firmware - - bootloader - default: tui - -concurrency: - group: release-${{ github.workflow }}-${{ github.ref }} - -permissions: - contents: write - -jobs: - # ───────────────────────────────────────────────────────────────────────── - # firmware — собирает HAB Debug firmware_test И HAB Release bootloader. - # Нужна как для standalone firmware-/bootloader-релизов, так и для вшивания - # обоих образов в TUI-бандл (package-tui, Фаза 5) — выполняется всегда. - # ───────────────────────────────────────────────────────────────────────── - firmware: - name: Build firmware_test HAB (Debug) + bootloader HAB (Release) - runs-on: ubuntu-latest - timeout-minutes: 90 - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Build devcontainer image with cache - uses: docker/build-push-action@v7 - with: - context: . - file: .devcontainer/Dockerfile - tags: tft-devcontainer-ci:latest - load: true - cache-from: type=gha,scope=tft-devcontainer - cache-to: type=gha,mode=max,scope=tft-devcontainer - - - name: Sync host Python tools inside container - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace \ - tft-devcontainer-ci:latest bash -lc 'cd tools/host && uv sync' - - - name: Проверить, что тег совпадает с версией в CMakeLists.txt - if: startsWith(github.ref, 'refs/tags/firmware-v') - run: | - tag_version="${GITHUB_REF_NAME#firmware-v}" - file_version=$(grep -m1 -oE 'VERSION [0-9]+\.[0-9]+\.[0-9]+' firmware/test/CMakeLists.txt | awk '{print $2}') - if [[ "$tag_version" != "$file_version" ]]; then - echo "::error::Тег ${GITHUB_REF_NAME} (версия ${tag_version}) не совпадает с VERSION в firmware/test/CMakeLists.txt (${file_version})" - exit 1 - fi - echo " ✅ Версия тега совпадает с CMakeLists.txt: ${file_version}" - - - name: Собрать firmware_test HAB (Debug) - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace \ - tft-devcontainer-ci:latest bash -lc 'just build::hab-firmware-test-debug' - - - name: Upload firmware_test_hab.bin - uses: actions/upload-artifact@v4 - with: - name: firmware-hab-debug - path: build/Debug/firmware_test_hab.bin - if-no-files-found: error - retention-days: 14 - - - name: Проверить, что тег совпадает с версией в CMakeLists.txt (bootloader) - if: startsWith(github.ref, 'refs/tags/bootloader-v') - run: | - tag_version="${GITHUB_REF_NAME#bootloader-v}" - file_version=$(grep -m1 -oE 'VERSION [0-9]+\.[0-9]+\.[0-9]+' firmware/bootloader/CMakeLists.txt | awk '{print $2}') - if [[ "$tag_version" != "$file_version" ]]; then - echo "::error::Тег ${GITHUB_REF_NAME} (версия ${tag_version}) не совпадает с VERSION в firmware/bootloader/CMakeLists.txt (${file_version})" - exit 1 - fi - echo " ✅ Версия тега совпадает с CMakeLists.txt: ${file_version}" - - - name: Собрать bootloader HAB (Release) - run: | - docker run --rm --user root -v "$GITHUB_WORKSPACE":/workspace -w /workspace \ - tft-devcontainer-ci:latest bash -lc 'just build::hab-bootloader-release' - - - name: Upload bootloader_hab.bin - uses: actions/upload-artifact@v4 - with: - name: bootloader-hab-release - path: build/Release/bootloader_hab.bin - if-no-files-found: error - retention-days: 14 - - # ───────────────────────────────────────────────────────────────────────── - # publish-firmware — только на тег firmware-v*, отдельный standalone-релиз - # HAB-образа (для tools/host/flash_usb.py и ручной прошивки, не через TUI). - # ───────────────────────────────────────────────────────────────────────── - publish-firmware: - name: Publish firmware release - needs: firmware - if: startsWith(github.ref, 'refs/tags/firmware-v') - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download firmware_test_hab.bin - uses: actions/download-artifact@v4 - with: - name: firmware-hab-debug - path: release-assets/ - - - name: Create GitHub Release - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release create "${GITHUB_REF_NAME}" \ - release-assets/firmware_test_hab.bin \ - --title "firmware_test ${GITHUB_REF_NAME#firmware-v}" \ - --generate-notes - - # ───────────────────────────────────────────────────────────────────────── - # publish-bootloader — только на тег bootloader-v*, отдельный standalone- - # релиз HAB-образа (для tools/host/flash_usb.py / SWD, не через TUI). - # ⚠️ Подписан ТЕСТОВЫМ HAB-ключом (dev/pre-series, HAB Open чип всё равно - # загрузит и unsigned) — реальная SRK-церемония не проведена, см. - # firmware/bootloader/SIGNING_CEREMONY.md. Явно проговорено в release notes, - # чтобы этот asset не приняли за production-подписанный постфактум. - # ───────────────────────────────────────────────────────────────────────── - publish-bootloader: - name: Publish bootloader release - needs: firmware - if: startsWith(github.ref, 'refs/tags/bootloader-v') - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download bootloader_hab.bin - uses: actions/download-artifact@v4 - with: - name: bootloader-hab-release - path: release-assets/ - - - name: Create GitHub Release - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release create "${GITHUB_REF_NAME}" \ - release-assets/bootloader_hab.bin \ - --title "bootloader ${GITHUB_REF_NAME#bootloader-v}" \ - --notes "⚠️ HAB-подпись — ТЕСТОВЫЙ ключ (dev/pre-series, HAB Open). Не production. Реальная SRK-церемония — firmware/bootloader/SIGNING_CEREMONY.md." - - # ───────────────────────────────────────────────────────────────────────── - # service-tui-{macos,windows} — упаковка PyInstaller-бандла с вшитым HAB - # из job firmware. Запускается на тег tui-v* и на workflow_dispatch с - # release_type=tui (для тестового прогона без публикации). - # ───────────────────────────────────────────────────────────────────────── - service-tui-macos: - name: Package service-tui (macOS) - needs: firmware - if: startsWith(github.ref, 'refs/tags/tui-v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.release_type == 'tui') - runs-on: macos-latest - timeout-minutes: 30 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install uv - uses: astral-sh/setup-uv@v8.3.2 # без плавающего major-тега начиная с v8 (upstream security policy) — пин точной версии, обновлять периодически - - - name: Install just - uses: extractions/setup-just@v4 - - - name: Download firmware_test_hab.bin - uses: actions/download-artifact@v4 - with: - name: firmware-hab-debug - path: build/Debug/ - - - name: Download bootloader_hab.bin - uses: actions/download-artifact@v4 - with: - name: bootloader-hab-release - path: build/Release/ - - - name: Проверить, что тег совпадает с версией в pyproject.toml - if: startsWith(github.ref, 'refs/tags/tui-v') - run: | - tag_version="${GITHUB_REF_NAME#tui-v}" - file_version=$(grep -m1 '^version' tools/service_tui/pyproject.toml | sed -E 's/.*"(.+)".*/\1/') - if [[ "$tag_version" != "$file_version" ]]; then - echo "::error::Тег ${GITHUB_REF_NAME} (версия ${tag_version}) не совпадает с version в tools/service_tui/pyproject.toml (${file_version})" - exit 1 - fi - echo " ✅ Версия тега совпадает с pyproject.toml: ${file_version}" - - - name: Собрать зависимости и упаковать бандл - run: | - just host::service-setup - just host::package-tui - - - name: Заархивировать бандл - working-directory: tools/service_tui/dist - run: | - name=$(ls -d service-tui-v*-macos) - zip -r "${name}.zip" "${name}" - - - name: Upload bundle - uses: actions/upload-artifact@v4 - with: - name: service-tui-macos - path: tools/service_tui/dist/service-tui-v*-macos.zip - if-no-files-found: error - retention-days: 14 - - service-tui-windows: - name: Package service-tui (Windows) - needs: firmware - if: startsWith(github.ref, 'refs/tags/tui-v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.release_type == 'tui') - runs-on: windows-latest - timeout-minutes: 30 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install uv - uses: astral-sh/setup-uv@v8.3.2 # без плавающего major-тега начиная с v8 (upstream security policy) — пин точной версии, обновлять периодически - - - name: Install just - uses: extractions/setup-just@v4 - - - name: Download firmware_test_hab.bin - uses: actions/download-artifact@v4 - with: - name: firmware-hab-debug - path: build/Debug/ - - - name: Download bootloader_hab.bin - uses: actions/download-artifact@v4 - with: - name: bootloader-hab-release - path: build/Release/ - - - name: Проверить, что тег совпадает с версией в pyproject.toml - if: startsWith(github.ref, 'refs/tags/tui-v') - shell: bash - run: | - tag_version="${GITHUB_REF_NAME#tui-v}" - file_version=$(grep -m1 '^version' tools/service_tui/pyproject.toml | sed -E 's/.*"(.+)".*/\1/') - if [[ "$tag_version" != "$file_version" ]]; then - echo "::error::Тег ${GITHUB_REF_NAME} (версия ${tag_version}) не совпадает с version в tools/service_tui/pyproject.toml (${file_version})" - exit 1 - fi - echo " ✅ Версия тега совпадает с pyproject.toml: ${file_version}" - - - name: Собрать зависимости и упаковать бандл - shell: bash - run: | - just host::service-setup - just host::package-tui - - - name: Заархивировать бандл - working-directory: tools/service_tui/dist - shell: pwsh - run: | - $name = (Get-ChildItem -Directory -Filter "service-tui-v*-windows").Name - Compress-Archive -Path $name -DestinationPath "$name.zip" - - - name: Upload bundle - uses: actions/upload-artifact@v4 - with: - name: service-tui-windows - path: tools/service_tui/dist/service-tui-v*-windows.zip - if-no-files-found: error - retention-days: 14 - - # ───────────────────────────────────────────────────────────────────────── - # publish-tui — только на тег tui-v*, релиз с обоими zip-бандлами. - # ───────────────────────────────────────────────────────────────────────── - publish-tui: - name: Publish service-tui release - needs: [service-tui-macos, service-tui-windows] - if: startsWith(github.ref, 'refs/tags/tui-v') - runs-on: ubuntu-latest - timeout-minutes: 15 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download bundles - uses: actions/download-artifact@v4 - with: - pattern: service-tui-* - path: release-assets/ - merge-multiple: true - - - name: Create GitHub Release - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release create "${GITHUB_REF_NAME}" \ - release-assets/*.zip \ - --title "service-tui ${GITHUB_REF_NAME#tui-v}" \ - --generate-notes