From 097c6495764a5f446a4bfea6752aa7e2bf848555 Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 18:37:09 +0200 Subject: [PATCH 01/22] ci: add GitHub Actions release workflow [no release] --- .github/workflows/release.yml | 268 ++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..bdc4a9c2 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,268 @@ +# audio.cpp — release.yml +# +# Adapted from llama.cpp's release workflow: the backend matrix is stripped down +# to the backends audio.cpp actually ships (CPU, CUDA, Vulkan, Metal; HIP is a +# stub), and the build is retargeted to audio.cpp's binaries (audiocpp_cli, +# audiocpp_server, audiocpp_gguf). AUDIOCPP_DEPLOYMENT_BUILD embeds the model +# specs so the prebuilt binaries are self-contained. +# +# Triggered manually or on a push to `main` touching source files. A commit +# message containing "[no release]" skips the release (same gate as llama.cpp). + +name: Release + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - '**/CMakeLists.txt' + - '**/*.h' + - '**/*.hpp' + - '**/*.cpp' + - '**/*.cu' + - '**/*.cuh' + - '**/*.metal' + +env: + GH_TOKEN: ${{ github.token }} + BUILD_TARGETS: audiocpp_cli audiocpp_server audiocpp_gguf + CMAKE_ARGS: "-DAUDIOCPP_DEPLOYMENT_BUILD=ON -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_CUDA_GRAPHS=ON" + +concurrency: + group: release + queue: max + +jobs: + check-release: + runs-on: ubuntu-latest + outputs: + should_release: ${{ steps.check.outputs.should_release }} + steps: + - id: check + env: + COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "should_release=true" >> "$GITHUB_OUTPUT" + elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then + if echo "$COMMIT_MESSAGE" | grep -q '\[no release\]'; then + echo "should_release=false" >> "$GITHUB_OUTPUT" + else + echo "should_release=true" >> "$GITHUB_OUTPUT" + fi + else + echo "should_release=false" >> "$GITHUB_OUTPUT" + fi + + get-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + needs: check-release + if: ${{ needs.check-release.outputs.should_release == 'true' }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - id: version + run: | + TAG=$(git describe --tags --exact-match HEAD 2>/dev/null || true) + if [[ -n "$TAG" ]]; then + echo "version=${TAG}" >> "$GITHUB_OUTPUT" + else + echo "version=$(git rev-parse --short HEAD)-$(date +%s)" >> "$GITHUB_OUTPUT" + fi + macos-metal: + name: macOS (${{ matrix.build }}) + needs: [check-release, get-version] + if: ${{ needs.check-release.outputs.should_release == 'true' }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - build: 'arm64' + arch: 'arm64' + os: macos-26 + defines: '' + - build: 'x64' + arch: 'x64' + os: macos-15-intel + # Metal disabled on x64 (GitHub Intel runners have no usable GPU) + defines: '-DGGML_METAL=OFF' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Configure + run: | + cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ + -DENGINE_ENABLE_CUDA=OFF -DENGINE_ENABLE_VULKAN=OFF \ + ${{ matrix.defines }} ${{ env.CMAKE_ARGS }} + - name: Build + run: cmake --build build --config Release --parallel "$(sysctl -n hw.logicalcpu)" --target ${{ env.BUILD_TARGETS }} + - name: Pack + run: | + cd build/bin + zip -r ../../audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.zip . + - uses: actions/upload-artifact@v4 + with: + name: audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal + path: audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.zip + + linux-cpu: + name: Ubuntu x64 (CPU) + needs: [check-release, get-version] + if: ${{ needs.check-release.outputs.should_release == 'true' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install deps + run: sudo apt-get update && sudo apt-get install -y build-essential cmake make glslc libvulkan-dev spirv-headers + - name: Configure + run: | + cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ + -DENGINE_ENABLE_CUDA=OFF -DENGINE_ENABLE_VULKAN=OFF ${{ env.CMAKE_ARGS }} + - name: Build + run: cmake --build build --config Release --parallel "$(nproc)" --target ${{ env.BUILD_TARGETS }} + - name: Pack + run: | + cd build/bin && tar -czf ../../audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu.tar.gz . + - uses: actions/upload-artifact@v4 + with: + name: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu + path: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu.tar.gz + + linux-vulkan: + name: Ubuntu x64 (Vulkan) + needs: [check-release, get-version] + if: ${{ needs.check-release.outputs.should_release == 'true' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install deps + run: sudo apt-get update && sudo apt-get install -y build-essential cmake make glslc libvulkan-dev spirv-headers + - name: Configure + run: | + cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ + -DENGINE_ENABLE_CUDA=OFF -DENGINE_ENABLE_VULKAN=ON ${{ env.CMAKE_ARGS }} + - name: Build + run: cmake --build build --config Release --parallel "$(nproc)" --target ${{ env.BUILD_TARGETS }} + - name: Pack + run: | + cd build/bin && tar -czf ../../audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan.tar.gz . + - uses: actions/upload-artifact@v4 + with: + name: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan + path: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan.tar.gz + + windows-cpu: + name: Windows x64 (CPU) + needs: [check-release, get-version] + if: ${{ needs.check-release.outputs.should_release == 'true' }} + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build + shell: pwsh + run: | + $assets = ${{ env.BUILD_TARGETS }} -split ' ' + foreach ($t in $assets) { .\scripts\build_windows.ps1 -Preset windows-cpu-release -Target $t } + - name: Pack + shell: bash + run: | + cd build/windows-cpu-release/bin + zip -r ../../../audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu.zip . + - uses: actions/upload-artifact@v4 + with: + name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu + path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu.zip + + windows-vulkan: + name: Windows x64 (Vulkan) + needs: [check-release, get-version] + if: ${{ needs.check-release.outputs.should_release == 'true' }} + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build + shell: pwsh + run: | + $assets = ${{ env.BUILD_TARGETS }} -split ' ' + foreach ($t in $assets) { .\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target $t } + - name: Pack + shell: bash + run: | + cd build/windows-vulkan-release/bin + zip -r ../../../audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip . + - uses: actions/upload-artifact@v4 + with: + name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan + path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip + + windows-cuda: + name: Windows x64 (CUDA) + needs: [check-release, get-version] + if: ${{ needs.check-release.outputs.should_release == 'true' }} + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build + shell: pwsh + run: | + $assets = ${{ env.BUILD_TARGETS }} -split ' ' + foreach ($t in $assets) { .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target $t } + - name: Pack + shell: bash + run: | + cd build/windows-cuda-release/bin + zip -r ../../../audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda.zip . + - uses: actions/upload-artifact@v4 + with: + name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda + path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda.zip + + release: + name: Create release + needs: + - check-release + - get-version + - macos-metal + - linux-cpu + - linux-vulkan + - windows-cpu + - windows-vulkan + - windows-cuda + if: ${{ needs.check-release.outputs.should_release == 'true' && always() }} + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Collect artifacts + uses: actions/download-artifact@v4 + with: + path: assets + merge-multiple: true + - name: Publish release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ needs.get-version.outputs.version }} + name: ${{ needs.get-version.outputs.version }} + draft: false + prerelease: false + generate_release_notes: true + files: assets/** + + From dbf589e91dbdf5045bcd286d11ef5d48ff2dd1b9 Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 18:41:10 +0200 Subject: [PATCH 02/22] ci: fix release jobs (explicit win targets, install libomp on mac) [no release] --- .github/workflows/release.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bdc4a9c2..b33a9a7d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,6 +96,9 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install deps + run: | + brew install libomp - name: Configure run: | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ @@ -174,8 +177,9 @@ jobs: - name: Build shell: pwsh run: | - $assets = ${{ env.BUILD_TARGETS }} -split ' ' - foreach ($t in $assets) { .\scripts\build_windows.ps1 -Preset windows-cpu-release -Target $t } + .\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_cli + .\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_server + .\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_gguf - name: Pack shell: bash run: | @@ -198,8 +202,9 @@ jobs: - name: Build shell: pwsh run: | - $assets = ${{ env.BUILD_TARGETS }} -split ' ' - foreach ($t in $assets) { .\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target $t } + .\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_cli + .\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_server + .\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_gguf - name: Pack shell: bash run: | @@ -222,8 +227,9 @@ jobs: - name: Build shell: pwsh run: | - $assets = ${{ env.BUILD_TARGETS }} -split ' ' - foreach ($t in $assets) { .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target $t } + .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target audiocpp_cli + .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target audiocpp_server + .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target audiocpp_gguf - name: Pack shell: bash run: | From c44b090e86294245cc05b1c48202e0a7c601f6a5 Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 18:50:33 +0200 Subject: [PATCH 03/22] ci: only publish release when all backend jobs succeed [no release] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b33a9a7d..7601c312 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -251,7 +251,7 @@ jobs: - windows-cpu - windows-vulkan - windows-cuda - if: ${{ needs.check-release.outputs.should_release == 'true' && always() }} + if: ${{ needs.check-release.outputs.should_release == 'true' }} runs-on: ubuntu-latest permissions: contents: write From 407af39b3330557c6de38a54f2df43354331346c Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 18:53:07 +0200 Subject: [PATCH 04/22] ci: provision mac OpenMP off, Windows Vulkan SDK + CUDA toolkit [no release] --- .github/workflows/release.yml | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7601c312..96a2c0aa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,19 +86,16 @@ jobs: - build: 'arm64' arch: 'arm64' os: macos-26 - defines: '' + defines: '-DGGML_METAL=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF' - build: 'x64' arch: 'x64' os: macos-15-intel # Metal disabled on x64 (GitHub Intel runners have no usable GPU) - defines: '-DGGML_METAL=OFF' + defines: '-DGGML_METAL=OFF -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF' steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Install deps - run: | - brew install libomp - name: Configure run: | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ @@ -199,6 +196,15 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install Vulkan SDK + shell: pwsh + run: | + $installer = "$env:TEMP\vulkansdk.exe" + $vulkanVersion = "1.3.296.0" + Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$vulkanVersion/windows/VulkanSDK-$vulkanVersion-Installer.exe" -OutFile $installer + & $installer --accept-licenses --default-answer --confirm-command install + $sdkRoot = "C:\VulkanSDK\$vulkanVersion" + "VULKAN_SDK=$sdkRoot" | Out-File -FilePath $env:GITHUB_ENV -Append - name: Build shell: pwsh run: | @@ -224,6 +230,11 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install CUDA build tools + uses: Jimver/cuda-toolkit@v0.2.21 + with: + cuda: '12.4.1' + update-github-env: true - name: Build shell: pwsh run: | From c8d66f600b53fa3364448d42da13c6434619aa7d Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 19:39:03 +0200 Subject: [PATCH 05/22] ci: adopt llama.cpp release patterns (7z packing, CUDA 12/13 matrix, Vulkan SDK fix, OpenMP-off CUDA build) [no release] --- .github/workflows/release.yml | 96 ++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 96a2c0aa..4bb056f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,12 +1,13 @@ # audio.cpp — release.yml # -# Adapted from llama.cpp's release workflow: the backend matrix is stripped down -# to the backends audio.cpp actually ships (CPU, CUDA, Vulkan, Metal; HIP is a -# stub), and the build is retargeted to audio.cpp's binaries (audiocpp_cli, -# audiocpp_server, audiocpp_gguf). AUDIOCPP_DEPLOYMENT_BUILD embeds the model -# specs so the prebuilt binaries are self-contained. +# Modeled on llama.cpp's release workflow but stripped to the backends audio.cpp +# ships (CPU, CUDA, Vulkan, Metal). Windows artifacts are packed with 7-Zip (zip +# is not on Windows runners); Linux/macOS use tar. Windows CUDA builds are a +# 2-version matrix (12.4 / 13.3) that configure CMake directly with OpenMP off +# (audio.cpp's build_windows.ps1 hard-requires OpenMP and asserts on the CUDA +# toolchain), matching how llama.cpp decouples backend builds. # -# Triggered manually or on a push to `main` touching source files. A commit +# Triggers on manual dispatch or a push to `main` touching source files. A commit # message containing "[no release]" skips the release (same gate as llama.cpp). name: Release @@ -28,6 +29,7 @@ on: env: GH_TOKEN: ${{ github.token }} BUILD_TARGETS: audiocpp_cli audiocpp_server audiocpp_gguf + VULKAN_VERSION: '1.4.304.0' CMAKE_ARGS: "-DAUDIOCPP_DEPLOYMENT_BUILD=ON -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_CUDA_GRAPHS=ON" concurrency: @@ -91,7 +93,7 @@ jobs: arch: 'x64' os: macos-15-intel # Metal disabled on x64 (GitHub Intel runners have no usable GPU) - defines: '-DGGML_METAL=OFF -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF' + defines: '-DGGML_METAL=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF' steps: - uses: actions/checkout@v4 with: @@ -99,18 +101,19 @@ jobs: - name: Configure run: | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_RPATH='@loader_path' -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ -DENGINE_ENABLE_CUDA=OFF -DENGINE_ENABLE_VULKAN=OFF \ ${{ matrix.defines }} ${{ env.CMAKE_ARGS }} - name: Build run: cmake --build build --config Release --parallel "$(sysctl -n hw.logicalcpu)" --target ${{ env.BUILD_TARGETS }} - name: Pack run: | - cd build/bin - zip -r ../../audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.zip . + cp LICENSE build/bin/ 2>/dev/null || true + tar -czvf audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.tar.gz -C build/bin . - uses: actions/upload-artifact@v4 with: name: audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal - path: audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.zip + path: audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.tar.gz linux-cpu: name: Ubuntu x64 (CPU) @@ -131,7 +134,8 @@ jobs: run: cmake --build build --config Release --parallel "$(nproc)" --target ${{ env.BUILD_TARGETS }} - name: Pack run: | - cd build/bin && tar -czf ../../audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu.tar.gz . + cp LICENSE build/bin/ 2>/dev/null || true + tar -czf audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu.tar.gz -C build/bin . - uses: actions/upload-artifact@v4 with: name: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu @@ -156,12 +160,12 @@ jobs: run: cmake --build build --config Release --parallel "$(nproc)" --target ${{ env.BUILD_TARGETS }} - name: Pack run: | - cd build/bin && tar -czf ../../audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan.tar.gz . + cp LICENSE build/bin/ 2>/dev/null || true + tar -czf audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan.tar.gz -C build/bin . - uses: actions/upload-artifact@v4 with: name: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan path: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan.tar.gz - windows-cpu: name: Windows x64 (CPU) needs: [check-release, get-version] @@ -178,10 +182,11 @@ jobs: .\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_server .\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_gguf - name: Pack - shell: bash + shell: pwsh + working-directory: build/windows-cpu-release/bin run: | - cd build/windows-cpu-release/bin - zip -r ../../../audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu.zip . + cp ..\..\..\LICENSE . 2>$null + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu.zip * - uses: actions/upload-artifact@v4 with: name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu @@ -199,12 +204,10 @@ jobs: - name: Install Vulkan SDK shell: pwsh run: | - $installer = "$env:TEMP\vulkansdk.exe" - $vulkanVersion = "1.3.296.0" - Invoke-WebRequest -Uri "https://sdk.lunarg.com/sdk/download/$vulkanVersion/windows/VulkanSDK-$vulkanVersion-Installer.exe" -OutFile $installer - & $installer --accept-licenses --default-answer --confirm-command install - $sdkRoot = "C:\VulkanSDK\$vulkanVersion" - "VULKAN_SDK=$sdkRoot" | Out-File -FilePath $env:GITHUB_ENV -Append + curl.exe -o "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" -L "https://sdk.lunarg.com/sdk/download/${env:VULKAN_VERSION}/windows/vulkansdk-windows-X64-${env:VULKAN_VERSION}.exe" + & "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" --accept-licenses --default-answer --confirm-command install + Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\\VulkanSDK\\${env:VULKAN_VERSION}" + Add-Content $env:GITHUB_PATH "C:\\VulkanSDK\\${env:VULKAN_VERSION}\\bin" - name: Build shell: pwsh run: | @@ -212,20 +215,25 @@ jobs: .\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_server .\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_gguf - name: Pack - shell: bash + shell: pwsh + working-directory: build/windows-vulkan-release/bin run: | - cd build/windows-vulkan-release/bin - zip -r ../../../audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip . + cp ..\..\..\LICENSE . 2>$null + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip * - uses: actions/upload-artifact@v4 with: name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip windows-cuda: - name: Windows x64 (CUDA) + name: Windows x64 (CUDA ${{ matrix.cuda }}) needs: [check-release, get-version] if: ${{ needs.check-release.outputs.should_release == 'true' }} runs-on: windows-2022 + strategy: + fail-fast: false + matrix: + cuda: [ '12.4', '13.3' ] steps: - uses: actions/checkout@v4 with: @@ -233,23 +241,40 @@ jobs: - name: Install CUDA build tools uses: Jimver/cuda-toolkit@v0.2.21 with: - cuda: '12.4.1' + cuda: ${{ matrix.cuda }} update-github-env: true + - name: Configure (OpenMP off) + shell: pwsh + # Direct CMake (bypass build_windows.ps1, which hard-requires OpenMP and + # aborts under the CUDA toolchain). OpenMP off matches how llama.cpp + # builds the CUDA path. + run: | + cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ` + -DENGINE_ENABLE_CUDA=ON -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF ` + -DENGINE_ENABLE_CUDA_GRAPHS=ON -DENGINE_ENABLE_VULKAN=OFF -DENGINE_ENABLE_METAL=OFF ` + -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_NATIVE_CPU=ON -DENGINE_BUILD_TESTS=OFF ` + -DAUDIOCPP_DEPLOYMENT_BUILD=ON -DCUDAToolkit_ROOT="$env:CUDA_PATH" - name: Build + shell: pwsh + run: cmake --build build --config Release --parallel $env:NUMBER_OF_PROCESSORS --target ${{ env.BUILD_TARGETS }} + - name: Bundle CUDA runtime shell: pwsh run: | - .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target audiocpp_cli - .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target audiocpp_server - .\scripts\build_windows.ps1 -Preset windows-cuda-release -Target audiocpp_gguf + $dst = "build\bin\cudart" + New-Item -ItemType Directory -Force -Path $dst | Out-Null + robocopy "$env:CUDA_PATH\bin" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll + exit $LASTEXITCODE - name: Pack - shell: bash + shell: pwsh + working-directory: build/bin run: | - cd build/windows-cuda-release/bin - zip -r ../../../audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda.zip . + cp ..\..\LICENSE . 2>$null + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.cuda }}.zip * cudart\* + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-cudart-windows-x64-cuda${{ matrix.cuda }}.zip cudart\* - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda - path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda.zip + name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.cuda }} + path: 'audio-${{ needs.get-version.outputs.version }}-*cuda${{ matrix.cuda }}.zip' release: name: Create release @@ -282,4 +307,3 @@ jobs: generate_release_notes: true files: assets/** - From 22ded670e2fb8fe01ada81c928271d9b3b16353c Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 20:24:35 +0200 Subject: [PATCH 06/22] ci: use valid Vulkan SDK 1.4.357.0 and full CUDA versions in matrix [no release] --- .github/workflows/release.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4bb056f4..31464ccb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,7 +29,7 @@ on: env: GH_TOKEN: ${{ github.token }} BUILD_TARGETS: audiocpp_cli audiocpp_server audiocpp_gguf - VULKAN_VERSION: '1.4.304.0' + VULKAN_VERSION: '1.4.357.0' CMAKE_ARGS: "-DAUDIOCPP_DEPLOYMENT_BUILD=ON -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_CUDA_GRAPHS=ON" concurrency: @@ -226,14 +226,18 @@ jobs: path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip windows-cuda: - name: Windows x64 (CUDA ${{ matrix.cuda }}) + name: 'Windows x64 (CUDA ${{ matrix.label }})' needs: [check-release, get-version] if: ${{ needs.check-release.outputs.should_release == 'true' }} runs-on: windows-2022 strategy: fail-fast: false matrix: - cuda: [ '12.4', '13.3' ] + include: + - cuda: '12.4.1' + label: '12.4' + - cuda: '13.3.0' + label: '13.3' steps: - uses: actions/checkout@v4 with: @@ -242,7 +246,7 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.21 with: cuda: ${{ matrix.cuda }} - update-github-env: true + method: 'local' - name: Configure (OpenMP off) shell: pwsh # Direct CMake (bypass build_windows.ps1, which hard-requires OpenMP and @@ -269,12 +273,12 @@ jobs: working-directory: build/bin run: | cp ..\..\LICENSE . 2>$null - 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.cuda }}.zip * cudart\* - 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-cudart-windows-x64-cuda${{ matrix.cuda }}.zip cudart\* + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }}.zip * cudart\* + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-cudart-windows-x64-cuda${{ matrix.label }}.zip cudart\* - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.cuda }} - path: 'audio-${{ needs.get-version.outputs.version }}-*cuda${{ matrix.cuda }}.zip' + name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }} + path: 'audio-${{ needs.get-version.outputs.version }}-*cuda${{ matrix.label }}.zip' release: name: Create release From 200068a38544b05ed5f3e111c19f4d329758e5af Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 20:29:21 +0200 Subject: [PATCH 07/22] ci: bump cuda-toolkit to v0.2.36, CUDA 12.4/13.2 [no release] --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 31464ccb..4fa056af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -236,14 +236,14 @@ jobs: include: - cuda: '12.4.1' label: '12.4' - - cuda: '13.3.0' - label: '13.3' + - cuda: '13.2.0' + label: '13.2' steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install CUDA build tools - uses: Jimver/cuda-toolkit@v0.2.21 + uses: Jimver/cuda-toolkit@v0.2.36 with: cuda: ${{ matrix.cuda }} method: 'local' From 9d4c56805cc7aad24fc9fc82e8c88a3f682a55b2 Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 21:11:14 +0200 Subject: [PATCH 08/22] ci: source vcvarsall before CUDA cmake so nvcc finds cl.exe [no release] --- .github/workflows/release.yml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4fa056af..e0d2202a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -247,20 +247,19 @@ jobs: with: cuda: ${{ matrix.cuda }} method: 'local' - - name: Configure (OpenMP off) - shell: pwsh + - name: Configure + Build (OpenMP off) + shell: cmd # Direct CMake (bypass build_windows.ps1, which hard-requires OpenMP and # aborts under the CUDA toolchain). OpenMP off matches how llama.cpp - # builds the CUDA path. + # builds the CUDA path. vcvarsall.bat puts cl.exe on PATH for nvcc. run: | - cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ` - -DENGINE_ENABLE_CUDA=ON -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF ` - -DENGINE_ENABLE_CUDA_GRAPHS=ON -DENGINE_ENABLE_VULKAN=OFF -DENGINE_ENABLE_METAL=OFF ` - -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_NATIVE_CPU=ON -DENGINE_BUILD_TESTS=OFF ` - -DAUDIOCPP_DEPLOYMENT_BUILD=ON -DCUDAToolkit_ROOT="$env:CUDA_PATH" - - name: Build - shell: pwsh - run: cmake --build build --config Release --parallel $env:NUMBER_OF_PROCESSORS --target ${{ env.BUILD_TARGETS }} + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul + cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ^ + -DENGINE_ENABLE_CUDA=ON -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF ^ + -DENGINE_ENABLE_CUDA_GRAPHS=ON -DENGINE_ENABLE_VULKAN=OFF -DENGINE_ENABLE_METAL=OFF ^ + -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_NATIVE_CPU=ON -DENGINE_BUILD_TESTS=OFF ^ + -DAUDIOCPP_DEPLOYMENT_BUILD=ON -DCUDAToolkit_ROOT="%CUDA_PATH%" + cmake --build build --config Release -j %NUMBER_OF_PROCESSORS% --target ${{ env.BUILD_TARGETS }} - name: Bundle CUDA runtime shell: pwsh run: | From 7c8e9449d1cac572839d334a75f154c9b96edee1 Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 22:17:17 +0200 Subject: [PATCH 09/22] ci: fix robocopy exit-code mapping in CUDA bundle step [no release] --- .github/workflows/release.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e0d2202a..ff70aded 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -262,11 +262,15 @@ jobs: cmake --build build --config Release -j %NUMBER_OF_PROCESSORS% --target ${{ env.BUILD_TARGETS }} - name: Bundle CUDA runtime shell: pwsh + # robocopy exit codes are a bitmask: 0-7 are success/extras/mismatch, only + # >=8 is a real failure. Map to a single pass/fail so "files copied" (1) + # doesn't fail the step. run: | $dst = "build\bin\cudart" New-Item -ItemType Directory -Force -Path $dst | Out-Null robocopy "$env:CUDA_PATH\bin" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll - exit $LASTEXITCODE + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 - name: Pack shell: pwsh working-directory: build/bin From 06356eb40a1bb33af7353238a9cdab5abf4e6cf9 Mon Sep 17 00:00:00 2001 From: Anon Date: Mon, 17 Aug 2026 23:44:26 +0200 Subject: [PATCH 10/22] ci: fix CUDA artifact zip path (build/bin is 1 level shallower than CPU/Vulkan preset bins) [no release] --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff70aded..28f01596 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -276,8 +276,8 @@ jobs: working-directory: build/bin run: | cp ..\..\LICENSE . 2>$null - 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }}.zip * cudart\* - 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-cudart-windows-x64-cuda${{ matrix.label }}.zip cudart\* + 7z a -snl ..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }}.zip * cudart\* + 7z a -snl ..\..\audio-${{ needs.get-version.outputs.version }}-cudart-windows-x64-cuda${{ matrix.label }}.zip cudart\* - uses: actions/upload-artifact@v4 with: name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }} From 2ba3acfef0b94b6f3f95db28c54c6bd294aa1019 Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 13:46:03 +0200 Subject: [PATCH 11/22] ci: bundle CUDA runtime from bin/lib/bin-x64 and stop double-shipping runtime DLLs in CUDA release --- .github/workflows/release.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28f01596..b53034ab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -264,19 +264,26 @@ jobs: shell: pwsh # robocopy exit codes are a bitmask: 0-7 are success/extras/mismatch, only # >=8 is a real failure. Map to a single pass/fail so "files copied" (1) - # doesn't fail the step. + # doesn't fail the step. CUDA <13 keeps the runtime DLLs in bin/ and lib/, + # but CUDA 13.x moved them to bin/x64/, so probe all three source dirs + # (same as llama.cpp's release workflow) so every matrix row bundles them. run: | $dst = "build\bin\cudart" New-Item -ItemType Directory -Force -Path $dst | Out-Null - robocopy "$env:CUDA_PATH\bin" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll - if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + $dlls = "cudart64_*.dll", "cublas64_*.dll", "cublasLt64_*.dll" + foreach ($src in @("$env:CUDA_PATH\bin", "$env:CUDA_PATH\lib", "$env:CUDA_PATH\bin\x64")) { + robocopy $src $dst $dlls + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + } exit 0 - name: Pack shell: pwsh working-directory: build/bin + # -x!cudart keeps the heavy CUDA runtime DLLs out of the bin zip so they are + # shipped exactly once (in the separate cudart...zip), matching llama.cpp. run: | cp ..\..\LICENSE . 2>$null - 7z a -snl ..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }}.zip * cudart\* + 7z a -snl ..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }}.zip * -x!cudart 7z a -snl ..\..\audio-${{ needs.get-version.outputs.version }}-cudart-windows-x64-cuda${{ matrix.label }}.zip cudart\* - uses: actions/upload-artifact@v4 with: From 2afbd1c69a8b5acae4cc14019a57064a960d5116 Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 14:42:12 +0200 Subject: [PATCH 12/22] ci(win-cuda): build with GGML_BACKEND_DL like llama.cpp so CUDA ships as ggml-cuda.dll instead of 3 monoliths --- .github/workflows/release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b53034ab..7a9f9baf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -252,12 +252,19 @@ jobs: # Direct CMake (bypass build_windows.ps1, which hard-requires OpenMP and # aborts under the CUDA toolchain). OpenMP off matches how llama.cpp # builds the CUDA path. vcvarsall.bat puts cl.exe on PATH for nvcc. + # + # ENGINE_ENABLE_CPU_ALL_VARIANTS flips BUILD_SHARED_LIBS=ON + + # GGML_BACKEND_DL=ON (audio.cpp/CMakeLists.txt), thus building the CUDA + # backend once as ggml-cuda.dll and keeping cli/server/gguf as thin + # shells that load backends at runtime -- the same distribution model + # llama.cpp uses. CUDA kernels are no longer duplicated into 3 exes. run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ^ -DENGINE_ENABLE_CUDA=ON -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF ^ -DENGINE_ENABLE_CUDA_GRAPHS=ON -DENGINE_ENABLE_VULKAN=OFF -DENGINE_ENABLE_METAL=OFF ^ -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_NATIVE_CPU=ON -DENGINE_BUILD_TESTS=OFF ^ + -DENGINE_ENABLE_CPU_ALL_VARIANTS=ON ^ -DAUDIOCPP_DEPLOYMENT_BUILD=ON -DCUDAToolkit_ROOT="%CUDA_PATH%" cmake --build build --config Release -j %NUMBER_OF_PROCESSORS% --target ${{ env.BUILD_TARGETS }} - name: Bundle CUDA runtime From 8f3bd1e88e9b94ae653f6b9a5c0723ed4614e8e9 Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 15:44:07 +0200 Subject: [PATCH 13/22] ci: port llama.cpp release pipeline for CPU/Vulkan/CUDA/Metal (get-tag-name, GGML_BACKEND_DL CUDA, robust cudart bundling) --- .github/actions/get-tag-name/action.yml | 22 ++++ .github/workflows/release.yml | 150 ++++++++++++++---------- 2 files changed, 111 insertions(+), 61 deletions(-) create mode 100644 .github/actions/get-tag-name/action.yml diff --git a/.github/actions/get-tag-name/action.yml b/.github/actions/get-tag-name/action.yml new file mode 100644 index 00000000..8d167c7e --- /dev/null +++ b/.github/actions/get-tag-name/action.yml @@ -0,0 +1,22 @@ +name: "Determine tag name" +description: "Determine the release tag/artifact name (b on main, branch-b- elsewhere)" +outputs: + name: + description: "The name of the tag" + value: ${{ steps.tag.outputs.name }} + +runs: + using: "composite" + steps: + - name: Determine tag name + id: tag + shell: bash + run: | + BUILD_NUMBER="$(git rev-list --count HEAD)" + SHORT_HASH="$(git rev-parse --short=7 HEAD)" + if [[ "${{ env.BRANCH_NAME }}" == "main" ]]; then + echo "name=b${BUILD_NUMBER}" >> $GITHUB_OUTPUT + else + SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') + echo "name=${SAFE_NAME}-b${BUILD_NUMBER}-${SHORT_HASH}" >> $GITHUB_OUTPUT + fi \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7a9f9baf..47eb86c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,19 +1,27 @@ -# audio.cpp — release.yml +# audio.cpp - release.yml # -# Modeled on llama.cpp's release workflow but stripped to the backends audio.cpp -# ships (CPU, CUDA, Vulkan, Metal). Windows artifacts are packed with 7-Zip (zip -# is not on Windows runners); Linux/macOS use tar. Windows CUDA builds are a -# 2-version matrix (12.4 / 13.3) that configure CMake directly with OpenMP off -# (audio.cpp's build_windows.ps1 hard-requires OpenMP and asserts on the CUDA -# toolchain), matching how llama.cpp decouples backend builds. +# Ported from llama.cpp's release workflow and stripped to the backends +# audio.cpp ships: CPU, CUDA, Vulkan, Metal (ROCm kept as best-effort, +# disabled like llama.cpp). Naming follows llama.cpp (get-tag-name -> b), +# Windows CUDA uses the GGML_BACKEND_DL model so the CUDA backend is shipped +# once as ggml-cuda.dll (thin cli/server/gguf shells) with the heavy CUDA +# runtime DLLs in a separate cudart...zip, and the release job publishes. # -# Triggers on manual dispatch or a push to `main` touching source files. A commit -# message containing "[no release]" skips the release (same gate as llama.cpp). +# Triggers on manual dispatch or a push to `main` touching source files. A +# commit message containing "[no release]" skips the release (same gate as +# llama.cpp). Publishing is gated to `main`, so branch validation runs build +# + upload artifacts without creating a release/tag. name: Release on: workflow_dispatch: + inputs: + publish: + description: 'Create a GitHub release (only effective on main)' + required: true + default: false + type: boolean push: branches: - main @@ -28,10 +36,12 @@ on: env: GH_TOKEN: ${{ github.token }} + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} BUILD_TARGETS: audiocpp_cli audiocpp_server audiocpp_gguf VULKAN_VERSION: '1.4.357.0' CMAKE_ARGS: "-DAUDIOCPP_DEPLOYMENT_BUILD=ON -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_CUDA_GRAPHS=ON" +# note: run this workflow one at a time for better cache reuse concurrency: group: release queue: max @@ -61,21 +71,16 @@ jobs: get-version: runs-on: ubuntu-latest outputs: - version: ${{ steps.version.outputs.version }} + tag: ${{ steps.tag.outputs.name }} needs: check-release if: ${{ needs.check-release.outputs.should_release == 'true' }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - id: version - run: | - TAG=$(git describe --tags --exact-match HEAD 2>/dev/null || true) - if [[ -n "$TAG" ]]; then - echo "version=${TAG}" >> "$GITHUB_OUTPUT" - else - echo "version=$(git rev-parse --short HEAD)-$(date +%s)" >> "$GITHUB_OUTPUT" - fi + - id: tag + uses: ./.github/actions/get-tag-name + macos-metal: name: macOS (${{ matrix.build }}) needs: [check-release, get-version] @@ -109,11 +114,11 @@ jobs: - name: Pack run: | cp LICENSE build/bin/ 2>/dev/null || true - tar -czvf audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.tar.gz -C build/bin . + tar -czvf audio-${{ needs.get-version.outputs.tag }}-bin-macos-${{ matrix.arch }}-metal.tar.gz -C build/bin . - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal - path: audio-${{ needs.get-version.outputs.version }}-bin-macos-${{ matrix.arch }}-metal.tar.gz + name: audio-${{ needs.get-version.outputs.tag }}-bin-macos-${{ matrix.arch }}-metal + path: audio-${{ needs.get-version.outputs.tag }}-bin-macos-${{ matrix.arch }}-metal.tar.gz linux-cpu: name: Ubuntu x64 (CPU) @@ -135,11 +140,11 @@ jobs: - name: Pack run: | cp LICENSE build/bin/ 2>/dev/null || true - tar -czf audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu.tar.gz -C build/bin . + tar -czf audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-cpu.tar.gz -C build/bin . - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu - path: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-cpu.tar.gz + name: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-cpu + path: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-cpu.tar.gz linux-vulkan: name: Ubuntu x64 (Vulkan) @@ -161,11 +166,12 @@ jobs: - name: Pack run: | cp LICENSE build/bin/ 2>/dev/null || true - tar -czf audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan.tar.gz -C build/bin . + tar -czf audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-vulkan.tar.gz -C build/bin . - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan - path: audio-${{ needs.get-version.outputs.version }}-bin-ubuntu-x64-vulkan.tar.gz + name: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-vulkan + path: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-vulkan.tar.gz + windows-cpu: name: Windows x64 (CPU) needs: [check-release, get-version] @@ -186,11 +192,11 @@ jobs: working-directory: build/windows-cpu-release/bin run: | cp ..\..\..\LICENSE . 2>$null - 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu.zip * + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cpu.zip * - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu - path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cpu.zip + name: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cpu + path: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cpu.zip windows-vulkan: name: Windows x64 (Vulkan) @@ -219,11 +225,11 @@ jobs: working-directory: build/windows-vulkan-release/bin run: | cp ..\..\..\LICENSE . 2>$null - 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip * + 7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-vulkan.zip * - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan - path: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-vulkan.zip + name: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-vulkan + path: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-vulkan.zip windows-cuda: name: 'Windows x64 (CUDA ${{ matrix.label }})' @@ -249,15 +255,15 @@ jobs: method: 'local' - name: Configure + Build (OpenMP off) shell: cmd - # Direct CMake (bypass build_windows.ps1, which hard-requires OpenMP and - # aborts under the CUDA toolchain). OpenMP off matches how llama.cpp - # builds the CUDA path. vcvarsall.bat puts cl.exe on PATH for nvcc. + # Direct CMake (bypasses build_windows.ps1, which hard-requires OpenMP and + # asserts under the CUDA toolchain). OpenMP off matches llama.cpp's CUDA + # path. vcvarsall.bat puts cl.exe on PATH for nvcc. # # ENGINE_ENABLE_CPU_ALL_VARIANTS flips BUILD_SHARED_LIBS=ON + - # GGML_BACKEND_DL=ON (audio.cpp/CMakeLists.txt), thus building the CUDA - # backend once as ggml-cuda.dll and keeping cli/server/gguf as thin - # shells that load backends at runtime -- the same distribution model - # llama.cpp uses. CUDA kernels are no longer duplicated into 3 exes. + # GGML_BACKEND_DL=ON (audio.cpp/CMakeLists.txt), building the CUDA backend + # once as ggml-cuda.dll and keeping cli/server/gguf as thin shells that + # load backends at runtime -- the same distribution model llama.cpp uses. + # CUDA kernels are no longer duplicated into 3 executables. run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ^ @@ -269,33 +275,44 @@ jobs: cmake --build build --config Release -j %NUMBER_OF_PROCESSORS% --target ${{ env.BUILD_TARGETS }} - name: Bundle CUDA runtime shell: pwsh - # robocopy exit codes are a bitmask: 0-7 are success/extras/mismatch, only - # >=8 is a real failure. Map to a single pass/fail so "files copied" (1) - # doesn't fail the step. CUDA <13 keeps the runtime DLLs in bin/ and lib/, - # but CUDA 13.x moved them to bin/x64/, so probe all three source dirs - # (same as llama.cpp's release workflow) so every matrix row bundles them. + # llama.cpp copies the runtime DLLs from every candidate dir without + # looking at robocopy's exit code: bin\x64 is a CUDA 13 layout, so on + # CUDA 12.x robocopy returns 16 for that missing dir, which is benign + # (llama's step ends on the successful 7z). Mirror that here -- copy + # from whichever dir exists and terminate on exit 0. The trailing guard + # only trips if NO cudart was copied at all (a broken/empty toolkit). run: | $dst = "build\bin\cudart" New-Item -ItemType Directory -Force -Path $dst | Out-Null - $dlls = "cudart64_*.dll", "cublas64_*.dll", "cublasLt64_*.dll" - foreach ($src in @("$env:CUDA_PATH\bin", "$env:CUDA_PATH\lib", "$env:CUDA_PATH\bin\x64")) { - robocopy $src $dst $dlls - if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + robocopy "$env:CUDA_PATH\bin" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll + robocopy "$env:CUDA_PATH\lib" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll + robocopy "$env:CUDA_PATH\bin\x64" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll + if (-not (Get-ChildItem -Path $dst -Filter 'cudart64_*.dll' -ErrorAction SilentlyContinue)) { + Write-Error "CUDA runtime DLLs were not found under $env:CUDA_PATH" + exit 1 } exit 0 - name: Pack shell: pwsh working-directory: build/bin - # -x!cudart keeps the heavy CUDA runtime DLLs out of the bin zip so they are - # shipped exactly once (in the separate cudart...zip), matching llama.cpp. + # -x!cudart keeps the heavy CUDA runtime DLLs out of the bin zip so they + # are shipped exactly once (in the separate cudart...zip), matching + # llama.cpp. run: | cp ..\..\LICENSE . 2>$null - 7z a -snl ..\..\audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }}.zip * -x!cudart - 7z a -snl ..\..\audio-${{ needs.get-version.outputs.version }}-cudart-windows-x64-cuda${{ matrix.label }}.zip cudart\* + 7z a -snl ..\..\audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cuda${{ matrix.label }}.zip * -x!cudart + 7z a -snl ..\..\audio-${{ needs.get-version.outputs.tag }}-cudart-windows-x64-cuda${{ matrix.label }}.zip cudart\* - uses: actions/upload-artifact@v4 with: - name: audio-${{ needs.get-version.outputs.version }}-bin-windows-x64-cuda${{ matrix.label }} - path: 'audio-${{ needs.get-version.outputs.version }}-*cuda${{ matrix.label }}.zip' + name: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cuda${{ matrix.label }} + path: 'audio-${{ needs.get-version.outputs.tag }}-*cuda${{ matrix.label }}.zip' + + # Best-effort ROCm builds. Kept OUT of the release `needs` and commented by + # default (llama.cpp ships its ROCm job disabled as well) because GitHub + # runners have no AMD GPU and HIP toolchain provisioning is heavy. Enable by + # uncommenting and pointing at a runner that can provide a ROCm/HIP runtime. + # linux-rocm: + # ... release: name: Create release @@ -308,23 +325,34 @@ jobs: - windows-cpu - windows-vulkan - windows-cuda - if: ${{ needs.check-release.outputs.should_release == 'true' }} + if: ${{ github.ref == 'refs/heads/main' && needs.check-release.outputs.should_release == 'true' }} runs-on: ubuntu-latest permissions: contents: write steps: - - name: Collect artifacts + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Download artifacts uses: actions/download-artifact@v4 with: path: assets merge-multiple: true + - name: Create and push git tag + run: | + TAG="${{ needs.get-version.outputs.tag }}" + if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null 2>&1; then + echo "Tag ${TAG} already exists, skipping creation" + else + git tag "${TAG}" + git push origin "${TAG}" + fi - name: Publish release uses: softprops/action-gh-release@v2 with: - tag_name: ${{ needs.get-version.outputs.version }} - name: ${{ needs.get-version.outputs.version }} + tag_name: ${{ needs.get-version.outputs.tag }} + name: ${{ needs.get-version.outputs.tag }} draft: false prerelease: false generate_release_notes: true - files: assets/** - + files: assets/** \ No newline at end of file From 63f92680194a3ab042eefaa124c1cc9ce666b401 Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 16:49:11 +0200 Subject: [PATCH 14/22] ci(win-cuda): pin CMAKE_CUDA_ARCHITECTURES per toolkit; use CUDA 13.3 in the matrix --- .github/workflows/release.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 47eb86c0..bd681b42 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -242,8 +242,10 @@ jobs: include: - cuda: '12.4.1' label: '12.4' - - cuda: '13.2.0' - label: '13.2' + cuda_archs: '70;75;80;86;89;90' + - cuda: '13.3.0' + label: '13.3' + cuda_archs: '75;80;86;89;90;120' steps: - uses: actions/checkout@v4 with: @@ -264,6 +266,13 @@ jobs: # once as ggml-cuda.dll and keeping cli/server/gguf as thin shells that # load backends at runtime -- the same distribution model llama.cpp uses. # CUDA kernels are no longer duplicated into 3 executables. + # + # CMAKE_CUDA_ARCHITECTURES must be pinned: audio.cpp defaults to + # "native" (the build host GPU), which is meaningless on GPU-less CI + # runners and yields an unreliable CUDA fatbin. Use fixed arch lists per + # toolkit so the released binaries carry correct kernels for the + # supported GPUs (RTX 20/30/40/50-series and datacenter-class). The + # value is quoted so the ';' separators survive cmd's tokenizer. run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ^ @@ -271,6 +280,7 @@ jobs: -DENGINE_ENABLE_CUDA_GRAPHS=ON -DENGINE_ENABLE_VULKAN=OFF -DENGINE_ENABLE_METAL=OFF ^ -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_NATIVE_CPU=ON -DENGINE_BUILD_TESTS=OFF ^ -DENGINE_ENABLE_CPU_ALL_VARIANTS=ON ^ + "-DCMAKE_CUDA_ARCHITECTURES=${{ matrix.cuda_archs }}" ^ -DAUDIOCPP_DEPLOYMENT_BUILD=ON -DCUDAToolkit_ROOT="%CUDA_PATH%" cmake --build build --config Release -j %NUMBER_OF_PROCESSORS% --target ${{ env.BUILD_TARGETS }} - name: Bundle CUDA runtime From 7834fa61497aa27743ee8417cc1a8027bb0850b6 Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 18:58:53 +0200 Subject: [PATCH 15/22] ci(win-cuda): use ggml-style virtual/real CUDA archs (faster) and bundle cufft64 runtime --- .github/workflows/release.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd681b42..7b601ced 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -242,10 +242,10 @@ jobs: include: - cuda: '12.4.1' label: '12.4' - cuda_archs: '70;75;80;86;89;90' + cuda_archs: '70-virtual;75-virtual;80-virtual;86-real;89-real;90-virtual' - cuda: '13.3.0' label: '13.3' - cuda_archs: '75;80;86;89;90;120' + cuda_archs: '75-virtual;80-virtual;86-real;89-real;90-virtual;120a-real' steps: - uses: actions/checkout@v4 with: @@ -291,12 +291,15 @@ jobs: # (llama's step ends on the successful 7z). Mirror that here -- copy # from whichever dir exists and terminate on exit 0. The trailing guard # only trips if NO cudart was copied at all (a broken/empty toolkit). + # cufft64_*.dll is included because engine_runtime links CUDA::cufft + # for its CUDA inverse-STFT kernel (CMakeLists.txt). run: | $dst = "build\bin\cudart" New-Item -ItemType Directory -Force -Path $dst | Out-Null - robocopy "$env:CUDA_PATH\bin" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll - robocopy "$env:CUDA_PATH\lib" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll - robocopy "$env:CUDA_PATH\bin\x64" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll + $dlls = "cudart64_*.dll", "cublas64_*.dll", "cublasLt64_*.dll", "cufft64_*.dll" + robocopy "$env:CUDA_PATH\bin" $dst $dlls + robocopy "$env:CUDA_PATH\lib" $dst $dlls + robocopy "$env:CUDA_PATH\bin\x64" $dst $dlls if (-not (Get-ChildItem -Path $dst -Filter 'cudart64_*.dll' -ErrorAction SilentlyContinue)) { Write-Error "CUDA runtime DLLs were not found under $env:CUDA_PATH" exit 1 From a8f03447839893f19e407fc3a36bcc96f1d103b2 Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 21:15:46 +0200 Subject: [PATCH 16/22] ci: one-command releases (publish toggle, scripts/release.sh, docs/RELEASING.md) --- .github/workflows/release.yml | 6 +-- docs/RELEASING.md | 82 ++++++++++++++++++++++++++++++ scripts/release.sh | 96 +++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 docs/RELEASING.md create mode 100644 scripts/release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b601ced..bc31c9ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -242,10 +242,10 @@ jobs: include: - cuda: '12.4.1' label: '12.4' - cuda_archs: '70-virtual;75-virtual;80-virtual;86-real;89-real;90-virtual' + cuda_archs: '70;75;80;86;89;90' - cuda: '13.3.0' label: '13.3' - cuda_archs: '75-virtual;80-virtual;86-real;89-real;90-virtual;120a-real' + cuda_archs: '75;80;86;89;90;120' steps: - uses: actions/checkout@v4 with: @@ -338,7 +338,7 @@ jobs: - windows-cpu - windows-vulkan - windows-cuda - if: ${{ github.ref == 'refs/heads/main' && needs.check-release.outputs.should_release == 'true' }} + if: ${{ needs.check-release.outputs.should_release == 'true' && github.ref == 'refs/heads/main' && (github.event_name != 'workflow_dispatch' || inputs.publish == 'true') }} runs-on: ubuntu-latest permissions: contents: write diff --git a/docs/RELEASING.md b/docs/RELEASING.md new file mode 100644 index 00000000..e60dcc74 --- /dev/null +++ b/docs/RELEASING.md @@ -0,0 +1,82 @@ +# Releasing audio.cpp prebuilt binaries + +This document explains how to publish a release with all prebuilt binaries +(macOS Metal, Linux CPU/Vulkan, Windows CPU/Vulkan/CUDA 12.4 + 13.3). + +Automation lives in `.github/workflows/release.yml` (ported from llama.cpp's +release workflow). Publishing is gated to `main`. + +## Prerequisites + +- The `gh` CLI installed and authenticated: `gh auth login`. +- `scripts/release.sh` on your PATH or run from the repo root. +- You are on the **`main`** branch with a clean working tree. + +## Quick: build + publish a release + +```bash +./scripts/release.sh --watch +``` + +This dispatches the Release workflow on `main` with `publish=true`, waits for +it to finish (~1–2 h; the Windows CUDA jobs dominate), and then prints the +GitHub Release URL and the uploaded asset list. + +The release tag is `b` (a monotonically increasing build number derived from +commit count, via `.github/actions/get-tag-name`). + +## Build without publishing (dry run) + +```bash +./scripts/release.sh --dry-run +``` + +Builds every backend and uploads them as Actions artifacts, but does **not** +create a tag or GitHub Release. Use this to validate before cutting a release. + +## Manual alternative (GitHub UI / CLI) + +1. Go to **Actions → Release → Run workflow** on `main`. +2. Set **publish** to `true` to create the Release (leave `false` for a dry run). + - Note: publishing is only effective when the workflow runs on `main`. +3. Run and wait for the `Create release` job. + +Or from the CLI (equivalent to the script): + +```bash +gh workflow run release.yml --repo drzsdrtfg/audio.cpp --ref main -f publish=true +``` + +## What gets shipped + +| Platform | Backend | Artifact | +|----------------|--------------------|----------| +| Windows x64 | CUDA 12.4 | `...-bin-windows-x64-cuda12.4.zip` (+ `cudart-...-cuda12.4.zip`) | +| Windows x64 | CUDA 13.3 | `...-bin-windows-x64-cuda13.3.zip` (+ `cudart-...-cuda13.3.zip`) | +| Windows x64 | Vulkan | `...-bin-windows-x64-vulkan.zip` | +| Windows x64 | CPU | `...-bin-windows-x64-cpu.zip` | +| Ubuntu x64 | Vulkan / CPU | `...-bin-ubuntu-x64-vulkan.tar.gz` / `...-cpu.tar.gz` | +| macOS arm64/x64| Metal | `...-bin-macos--metal.tar.gz` | + +Notes: + +- CUDA builds use `GGML_BACKEND_DL`, so CUDA kernels ship once as + `ggml-cuda.dll`; the heavy CUDA runtime (`cudart`/`cuBLAS`/`cuBLASLt`/`cuFFT`) + is bundled in a separate `cudart-...zip`. +- CUDA architectures are pinned (all-real) so binaries are portable across + supported NVIDIA GPUs instead of being tied to the (GPU-less) CI host. + +## Verification + +1. Confirm all expected assets exist on the Release page. +2. On a real machine with an NVIDIA GPU, run e.g. + `audiocpp_cli.exe --backend cuda ...` and check the log reports a CUDA + device (`ggml_cuda_init` / "found N CUDA devices"). + GitHub CI runners have **no GPU**, so a green build does not prove GPU + runtime attach — this step is required. + +## When releases are triggered + +- **Push to `main`** touching source/CMake files → builds **and** publishes. +- **Manual dispatch** → builds artifacts; publishes only with `publish=true`. +- A commit message containing `[no release]` skips the release entirely. \ No newline at end of file diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100644 index 00000000..4e878bc4 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# +# Release audio.cpp prebuilt binaries. +# +# Builds every backend (macOS Metal, Linux CPU/Vulkan, Windows CPU/Vulkan/CUDA +# 12.4 + 13.3) on GitHub Actions, then publishes a GitHub Release (tag b) +# with all artifacts when run on `main`. +# +# Usage: +# ./scripts/release.sh # build + publish a release +# ./scripts/release.sh --dry-run # build artifacts only, do not publish +# ./scripts/release.sh --watch # poll until done, then print Release + assets +# ./scripts/release.sh --help +# +set -euo pipefail + +REPO="${REPO:-drzsdrtfg/audio.cpp}" +BRANCH="${BRANCH:-main}" +PUBLISH="true" +WATCH="false" + +# ---------------------------------------------------------------- argparse +while [[ $# -gt 0 ]]; do + case "$1" in + --dry-run) PUBLISH="false"; shift ;; + --watch) WATCH="true"; shift ;; + --repo) REPO="$2"; shift 2 ;; + --branch) BRANCH="$2"; shift 2 ;; + --help|-h) sed -n '2,12p' "$0"; exit 0 ;; + *) echo "unknown option: $1" >&2; sed -n '2,12p' "$0"; exit 1 ;; + esac +done + +# ------------------------------------------------------------- preconditions +command -v gh >/dev/null 2>&1 || { echo "gh CLI is required (https://cli.github.com)" >&2; exit 1; } + +if ! gh auth status >/dev/null 2>&1; then + echo "Not authenticated with gh — run 'gh auth login' first." >&2 + exit 1 +fi + +if [[ "$BRANCH" == "main" ]]; then + CURRENT="$(git branch --show-current 2>/dev/null || true)" + if [[ "$CURRENT" != "main" ]]; then + echo "WARNING: not on main (current branch: ${CURRENT:-n/a})." >&2 + if [[ "$PUBLISH" == "true" ]]; then + echo "Refusing to publish from a non-main branch. Use --dry-run to build only." >&2 + exit 1 + fi + fi + if [[ -n "$(git status --porcelain)" ]]; then + echo "Working tree is dirty; commit or stash changes before releasing." >&2 + exit 1 + fi +fi + +# ----------------------------------------------------------------- dispatch +echo "Dispatching Release workflow on ${REPO} @ ${BRANCH} (publish=${PUBLISH})" +if [[ "$PUBLISH" == "true" ]]; then + gh workflow run release.yml --repo "$REPO" --ref "$BRANCH" -f publish=true +else + gh workflow run release.yml --repo "$REPO" --ref "$BRANCH" -f publish=false +fi + +echo "Waiting for the run to be registered..." +for _ in $(seq 1 30); do + RUN_ID="$(gh run list --repo "$REPO" --workflow release.yml --limit 1 --json databaseId -q '.[0].databaseId' 2>/dev/null || true)" + [[ -n "$RUN_ID" ]] && break + sleep 2 +done +RUN_ID="${RUN_ID:-$(gh run list --repo "$REPO" --workflow release.yml --limit 1 --json databaseId -q '.[0].databaseId')}" +echo "Workflow run: https://github.com/${REPO}/actions/runs/${RUN_ID}" + +if [[ "$WATCH" != "true" ]]; then + echo "Triggered. Monitor at the URL above (or rerun with --watch)." + exit 0 +fi + +# ---------------------------------------------------------------------- watch +echo "Watching run ${RUN_ID} (this can take ~1-2 h while CUDA builds)..." +gh run watch "$RUN_ID" --repo "$REPO" --exit-status || { + echo "Release workflow failed — see $RUN_ID" >&2 + exit 1 +} + +TAG="$(gh run view "$RUN_ID" --repo "$REPO" --json jobs -q '.jobs[] | select(.name=="get-version" and .conclusion=="success") | .steps[0].outputs' 2>/dev/null || true)" +echo +echo "================================================================" +echo " ✅ Release finished:" +echo " https://github.com/${REPO}/actions/runs/${RUN_ID}" +if [[ "$PUBLISH" == "true" ]]; then + RELEASE_URL="$(gh api "repos/${REPO}/releases" -q '.[0].html_url' 2>/dev/null || true)" + echo " GitHub release: ${RELEASE_URL:-check the run above}" + gh release view --repo "$REPO" --json assets -q '.assets[] | " - \(.name) (\((.size/1048576)|round|tostring) MB)"' 2>/dev/null || echo " (no release assets found)" +fi +echo "================================================================" \ No newline at end of file From 4e03548b8353f94da4a8f6e8d7ef7db47f95007f Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 21:22:04 +0200 Subject: [PATCH 17/22] ci: one-click GUI releases (publish defaults on) + GUI-first releasing docs --- .github/workflows/release.yml | 6 +- docs/RELEASING.md | 110 ++++++++++++++-------------------- 2 files changed, 48 insertions(+), 68 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bc31c9ef..5f5c0d50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,9 +18,9 @@ on: workflow_dispatch: inputs: publish: - description: 'Create a GitHub release (only effective on main)' - required: true - default: false + description: 'Publish a GitHub Release (only effective on main). Leave checked for a normal release; uncheck to build binaries without publishing.' + required: false + default: true type: boolean push: branches: diff --git a/docs/RELEASING.md b/docs/RELEASING.md index e60dcc74..1fd3a362 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -1,82 +1,62 @@ # Releasing audio.cpp prebuilt binaries -This document explains how to publish a release with all prebuilt binaries -(macOS Metal, Linux CPU/Vulkan, Windows CPU/Vulkan/CUDA 12.4 + 13.3). - -Automation lives in `.github/workflows/release.yml` (ported from llama.cpp's -release workflow). Publishing is gated to `main`. - -## Prerequisites - -- The `gh` CLI installed and authenticated: `gh auth login`. -- `scripts/release.sh` on your PATH or run from the repo root. -- You are on the **`main`** branch with a clean working tree. - -## Quick: build + publish a release - -```bash -./scripts/release.sh --watch -``` - -This dispatches the Release workflow on `main` with `publish=true`, waits for -it to finish (~1–2 h; the Windows CUDA jobs dominate), and then prints the -GitHub Release URL and the uploaded asset list. - -The release tag is `b` (a monotonically increasing build number derived from -commit count, via `.github/actions/get-tag-name`). - -## Build without publishing (dry run) - -```bash -./scripts/release.sh --dry-run -``` - -Builds every backend and uploads them as Actions artifacts, but does **not** -create a tag or GitHub Release. Use this to validate before cutting a release. - -## Manual alternative (GitHub UI / CLI) - -1. Go to **Actions → Release → Run workflow** on `main`. -2. Set **publish** to `true` to create the Release (leave `false` for a dry run). - - Note: publishing is only effective when the workflow runs on `main`. -3. Run and wait for the `Create release` job. - -Or from the CLI (equivalent to the script): - -```bash -gh workflow run release.yml --repo drzsdrtfg/audio.cpp --ref main -f publish=true -``` +Everything is driven from the **GitHub Actions UI** — no command line needed. +Building + publishing a release is a single click; a dry run is a check-box +away. Publishing is gated to `main`. + +## Release via the GitHub UI (recommended) + +1. Open the repository on GitHub. +2. Go to the **Actions** tab. +3. In the left sidebar pick **Release**. +4. Click **Run workflow** (top right). + - **Branch:** keep `main`. + - **Publish a GitHub Release:** leave it **checked** for a normal release. + Uncheck it to build the binaries without publishing (a dry run). +5. Click **Run workflow** → wait for `Create release` to finish (~1–2 h; the + Windows CUDA jobs dominate). + +When it completes, the new GitHub Release appears on the **Releases** page +with all prebuilt binaries attached. The tag is `b` (a monotonic build +number derived from commit count). ## What gets shipped -| Platform | Backend | Artifact | -|----------------|--------------------|----------| -| Windows x64 | CUDA 12.4 | `...-bin-windows-x64-cuda12.4.zip` (+ `cudart-...-cuda12.4.zip`) | -| Windows x64 | CUDA 13.3 | `...-bin-windows-x64-cuda13.3.zip` (+ `cudart-...-cuda13.3.zip`) | -| Windows x64 | Vulkan | `...-bin-windows-x64-vulkan.zip` | -| Windows x64 | CPU | `...-bin-windows-x64-cpu.zip` | -| Ubuntu x64 | Vulkan / CPU | `...-bin-ubuntu-x64-vulkan.tar.gz` / `...-cpu.tar.gz` | -| macOS arm64/x64| Metal | `...-bin-macos--metal.tar.gz` | +| Platform | Backend | Artifact | +|----------------|-------------|----------| +| Windows x64 | CUDA 12.4 | `...-bin-windows-x64-cuda12.4.zip` (+ `cudart-...-cuda12.4.zip`) | +| Windows x64 | CUDA 13.3 | `...-bin-windows-x64-cuda13.3.zip` (+ `cudart-...-cuda13.3.zip`) | +| Windows x64 | Vulkan | `...-bin-windows-x64-vulkan.zip` | +| Windows x64 | CPU | `...-bin-windows-x64-cpu.zip` | +| Ubuntu x64 | Vulkan/CPU | `...-bin-ubuntu-x64-vulkan.tar.gz` / `...-cpu.tar.gz` | +| macOS arm64/x64| Metal | `...-bin-macos--metal.tar.gz` | Notes: - CUDA builds use `GGML_BACKEND_DL`, so CUDA kernels ship once as `ggml-cuda.dll`; the heavy CUDA runtime (`cudart`/`cuBLAS`/`cuBLASLt`/`cuFFT`) is bundled in a separate `cudart-...zip`. -- CUDA architectures are pinned (all-real) so binaries are portable across +- CUDA architectures are pinned (all-real) so binaries are portable across the supported NVIDIA GPUs instead of being tied to the (GPU-less) CI host. +## When the workflow runs + +- **Push to `main`** touching source/CMake files → builds **and** publishes. +- **Manual run from the Actions UI** → builds; publishes if **Publish** is + checked (effective only on `main`). +- A commit message containing `[no release]` skips the release entirely. + ## Verification -1. Confirm all expected assets exist on the Release page. -2. On a real machine with an NVIDIA GPU, run e.g. - `audiocpp_cli.exe --backend cuda ...` and check the log reports a CUDA - device (`ggml_cuda_init` / "found N CUDA devices"). - GitHub CI runners have **no GPU**, so a green build does not prove GPU - runtime attach — this step is required. +1. Confirm the expected assets exist on the Release page. +2. On a real NVIDIA GPU machine, run e.g. + `audiocpp_cli.exe --backend cuda ...` and confirm the log reports a CUDA + device (`ggml_cuda_init` / "found N CUDA devices"). GitHub CI runners have + **no GPU**, so a green build does not prove GPU runtime attach — this check + is required. -## When releases are triggered +## Optional CLI convenience (not required) -- **Push to `main`** touching source/CMake files → builds **and** publishes. -- **Manual dispatch** → builds artifacts; publishes only with `publish=true`. -- A commit message containing `[no release]` skips the release entirely. \ No newline at end of file +For maintainers who prefer the terminal, `scripts/release.sh` wraps the same +flow (`--watch` to monitor, `--dry-run` to build only). The GitHub UI flow +above is equivalent. \ No newline at end of file From 348d7a0f957d90119e454174c224778a953dfd1f Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 21:27:07 +0200 Subject: [PATCH 18/22] ci: remove CLI release helper; GUI-only releasing docs --- docs/RELEASING.md | 8 +--- scripts/release.sh | 96 ---------------------------------------------- 2 files changed, 1 insertion(+), 103 deletions(-) delete mode 100644 scripts/release.sh diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 1fd3a362..258b7df2 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -53,10 +53,4 @@ Notes: `audiocpp_cli.exe --backend cuda ...` and confirm the log reports a CUDA device (`ggml_cuda_init` / "found N CUDA devices"). GitHub CI runners have **no GPU**, so a green build does not prove GPU runtime attach — this check - is required. - -## Optional CLI convenience (not required) - -For maintainers who prefer the terminal, `scripts/release.sh` wraps the same -flow (`--watch` to monitor, `--dry-run` to build only). The GitHub UI flow -above is equivalent. \ No newline at end of file + is required. \ No newline at end of file diff --git a/scripts/release.sh b/scripts/release.sh deleted file mode 100644 index 4e878bc4..00000000 --- a/scripts/release.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bash -# -# Release audio.cpp prebuilt binaries. -# -# Builds every backend (macOS Metal, Linux CPU/Vulkan, Windows CPU/Vulkan/CUDA -# 12.4 + 13.3) on GitHub Actions, then publishes a GitHub Release (tag b) -# with all artifacts when run on `main`. -# -# Usage: -# ./scripts/release.sh # build + publish a release -# ./scripts/release.sh --dry-run # build artifacts only, do not publish -# ./scripts/release.sh --watch # poll until done, then print Release + assets -# ./scripts/release.sh --help -# -set -euo pipefail - -REPO="${REPO:-drzsdrtfg/audio.cpp}" -BRANCH="${BRANCH:-main}" -PUBLISH="true" -WATCH="false" - -# ---------------------------------------------------------------- argparse -while [[ $# -gt 0 ]]; do - case "$1" in - --dry-run) PUBLISH="false"; shift ;; - --watch) WATCH="true"; shift ;; - --repo) REPO="$2"; shift 2 ;; - --branch) BRANCH="$2"; shift 2 ;; - --help|-h) sed -n '2,12p' "$0"; exit 0 ;; - *) echo "unknown option: $1" >&2; sed -n '2,12p' "$0"; exit 1 ;; - esac -done - -# ------------------------------------------------------------- preconditions -command -v gh >/dev/null 2>&1 || { echo "gh CLI is required (https://cli.github.com)" >&2; exit 1; } - -if ! gh auth status >/dev/null 2>&1; then - echo "Not authenticated with gh — run 'gh auth login' first." >&2 - exit 1 -fi - -if [[ "$BRANCH" == "main" ]]; then - CURRENT="$(git branch --show-current 2>/dev/null || true)" - if [[ "$CURRENT" != "main" ]]; then - echo "WARNING: not on main (current branch: ${CURRENT:-n/a})." >&2 - if [[ "$PUBLISH" == "true" ]]; then - echo "Refusing to publish from a non-main branch. Use --dry-run to build only." >&2 - exit 1 - fi - fi - if [[ -n "$(git status --porcelain)" ]]; then - echo "Working tree is dirty; commit or stash changes before releasing." >&2 - exit 1 - fi -fi - -# ----------------------------------------------------------------- dispatch -echo "Dispatching Release workflow on ${REPO} @ ${BRANCH} (publish=${PUBLISH})" -if [[ "$PUBLISH" == "true" ]]; then - gh workflow run release.yml --repo "$REPO" --ref "$BRANCH" -f publish=true -else - gh workflow run release.yml --repo "$REPO" --ref "$BRANCH" -f publish=false -fi - -echo "Waiting for the run to be registered..." -for _ in $(seq 1 30); do - RUN_ID="$(gh run list --repo "$REPO" --workflow release.yml --limit 1 --json databaseId -q '.[0].databaseId' 2>/dev/null || true)" - [[ -n "$RUN_ID" ]] && break - sleep 2 -done -RUN_ID="${RUN_ID:-$(gh run list --repo "$REPO" --workflow release.yml --limit 1 --json databaseId -q '.[0].databaseId')}" -echo "Workflow run: https://github.com/${REPO}/actions/runs/${RUN_ID}" - -if [[ "$WATCH" != "true" ]]; then - echo "Triggered. Monitor at the URL above (or rerun with --watch)." - exit 0 -fi - -# ---------------------------------------------------------------------- watch -echo "Watching run ${RUN_ID} (this can take ~1-2 h while CUDA builds)..." -gh run watch "$RUN_ID" --repo "$REPO" --exit-status || { - echo "Release workflow failed — see $RUN_ID" >&2 - exit 1 -} - -TAG="$(gh run view "$RUN_ID" --repo "$REPO" --json jobs -q '.jobs[] | select(.name=="get-version" and .conclusion=="success") | .steps[0].outputs' 2>/dev/null || true)" -echo -echo "================================================================" -echo " ✅ Release finished:" -echo " https://github.com/${REPO}/actions/runs/${RUN_ID}" -if [[ "$PUBLISH" == "true" ]]; then - RELEASE_URL="$(gh api "repos/${REPO}/releases" -q '.[0].html_url' 2>/dev/null || true)" - echo " GitHub release: ${RELEASE_URL:-check the run above}" - gh release view --repo "$REPO" --json assets -q '.assets[] | " - \(.name) (\((.size/1048576)|round|tostring) MB)"' 2>/dev/null || echo " (no release assets found)" -fi -echo "================================================================" \ No newline at end of file From b5eefceb05addad916ea1eadc1f3745249fa5e5d Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 21:43:00 +0200 Subject: [PATCH 19/22] ci: semver tag-driven releases (remove b/auto-push); manual version input + publish gate --- .github/actions/get-tag-name/action.yml | 22 -------- .github/workflows/release.yml | 75 ++++++++++++------------- docs/RELEASING.md | 52 +++++++++-------- 3 files changed, 65 insertions(+), 84 deletions(-) delete mode 100644 .github/actions/get-tag-name/action.yml diff --git a/.github/actions/get-tag-name/action.yml b/.github/actions/get-tag-name/action.yml deleted file mode 100644 index 8d167c7e..00000000 --- a/.github/actions/get-tag-name/action.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: "Determine tag name" -description: "Determine the release tag/artifact name (b on main, branch-b- elsewhere)" -outputs: - name: - description: "The name of the tag" - value: ${{ steps.tag.outputs.name }} - -runs: - using: "composite" - steps: - - name: Determine tag name - id: tag - shell: bash - run: | - BUILD_NUMBER="$(git rev-list --count HEAD)" - SHORT_HASH="$(git rev-parse --short=7 HEAD)" - if [[ "${{ env.BRANCH_NAME }}" == "main" ]]; then - echo "name=b${BUILD_NUMBER}" >> $GITHUB_OUTPUT - else - SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-') - echo "name=${SAFE_NAME}-b${BUILD_NUMBER}-${SHORT_HASH}" >> $GITHUB_OUTPUT - fi \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5f5c0d50..89cbf17a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,41 +2,38 @@ # # Ported from llama.cpp's release workflow and stripped to the backends # audio.cpp ships: CPU, CUDA, Vulkan, Metal (ROCm kept as best-effort, -# disabled like llama.cpp). Naming follows llama.cpp (get-tag-name -> b), -# Windows CUDA uses the GGML_BACKEND_DL model so the CUDA backend is shipped -# once as ggml-cuda.dll (thin cli/server/gguf shells) with the heavy CUDA -# runtime DLLs in a separate cudart...zip, and the release job publishes. +# disabled like llama.cpp). Windows CUDA uses the GGML_BACKEND_DL model so the +# CUDA backend is shipped once as ggml-cuda.dll (thin cli/server/gguf shells) +# with the heavy CUDA runtime DLLs in a separate cudart...zip, and the release +# job publishes. # -# Triggers on manual dispatch or a push to `main` touching source files. A -# commit message containing "[no release]" skips the release (same gate as -# llama.cpp). Publishing is gated to `main`, so branch validation runs build -# + upload artifacts without creating a release/tag. +# Semantic-version, tag-driven releases. The workflow runs when a `v*` (semver) +# tag is pushed (drafting a Release and Publishing it) or when run manually +# from the Actions UI with an explicit version. Publishing attaches the built +# binaries to that version's GitHub Release. There is NO auto-release on every +# push to `main`. name: Release on: workflow_dispatch: inputs: + version: + description: 'Semantic version to release, e.g. 1.2.0 or v1.2.0 (used for manual runs; tag-triggered runs use the pushed tag).' + required: true + default: '' + type: string publish: - description: 'Publish a GitHub Release (only effective on main). Leave checked for a normal release; uncheck to build binaries without publishing.' + description: 'Publish a GitHub Release after the build. Leave unchecked for a build-only dry run.' required: false - default: true + default: false type: boolean push: - branches: - - main - paths: - - '**/CMakeLists.txt' - - '**/*.h' - - '**/*.hpp' - - '**/*.cpp' - - '**/*.cu' - - '**/*.cuh' - - '**/*.metal' + tags: + - 'v*' env: GH_TOKEN: ${{ github.token }} - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} BUILD_TARGETS: audiocpp_cli audiocpp_server audiocpp_gguf VULKAN_VERSION: '1.4.357.0' CMAKE_ARGS: "-DAUDIOCPP_DEPLOYMENT_BUILD=ON -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_CUDA_GRAPHS=ON" @@ -52,34 +49,34 @@ jobs: outputs: should_release: ${{ steps.check.outputs.should_release }} steps: + # The only triggers are a manually-run workflow or a pushed `v*` tag - + # both are intentional, so always proceed. - id: check - env: - COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "should_release=true" >> "$GITHUB_OUTPUT" - elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then - if echo "$COMMIT_MESSAGE" | grep -q '\[no release\]'; then - echo "should_release=false" >> "$GITHUB_OUTPUT" - else - echo "should_release=true" >> "$GITHUB_OUTPUT" - fi - else - echo "should_release=false" >> "$GITHUB_OUTPUT" - fi + run: echo "should_release=true" >> "$GITHUB_OUTPUT" get-version: runs-on: ubuntu-latest outputs: - tag: ${{ steps.tag.outputs.name }} + tag: ${{ steps.version.outputs.tag }} needs: check-release if: ${{ needs.check-release.outputs.should_release == 'true' }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - id: tag - uses: ./.github/actions/get-tag-name + - name: Resolve release tag + id: version + run: | + if [[ "${{ github.ref_type }}" == "tag" ]]; then + TAG="${{ github.ref_name }}" + elif [[ -n "${{ inputs.version }}" ]]; then + TAG="${{ inputs.version }}" + else + echo "::error::No semver tag or version provided (push a v* tag, or run manually with a version)." + exit 1 + fi + [[ "$TAG" == v* ]] || TAG="v${TAG}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" macos-metal: name: macOS (${{ matrix.build }}) @@ -338,7 +335,7 @@ jobs: - windows-cpu - windows-vulkan - windows-cuda - if: ${{ needs.check-release.outputs.should_release == 'true' && github.ref == 'refs/heads/main' && (github.event_name != 'workflow_dispatch' || inputs.publish == 'true') }} + if: ${{ needs.check-release.outputs.should_release == 'true' && (github.ref_type == 'tag' || inputs.publish == 'true') }} runs-on: ubuntu-latest permissions: contents: write diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 258b7df2..d9b4eeda 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -1,24 +1,29 @@ # Releasing audio.cpp prebuilt binaries -Everything is driven from the **GitHub Actions UI** — no command line needed. -Building + publishing a release is a single click; a dry run is a check-box -away. Publishing is gated to `main`. - -## Release via the GitHub UI (recommended) - -1. Open the repository on GitHub. -2. Go to the **Actions** tab. -3. In the left sidebar pick **Release**. -4. Click **Run workflow** (top right). - - **Branch:** keep `main`. - - **Publish a GitHub Release:** leave it **checked** for a normal release. - Uncheck it to build the binaries without publishing (a dry run). -5. Click **Run workflow** → wait for `Create release` to finish (~1–2 h; the - Windows CUDA jobs dominate). - -When it completes, the new GitHub Release appears on the **Releases** page -with all prebuilt binaries attached. The tag is `b` (a monotonic build -number derived from commit count). +Everything is driven from the **GitHub UI** — no command line needed. Releases +are **semantic-version and tag-driven**: there is no auto-release on pushes to +`main`. You release by tagging a version; the built binaries are then attached +to that version's Release. + +## Release a version (recommended) + +1. Open the repository → **Releases** → **Draft a new release**. +2. **Choose a tag** → create a new `v*` tag, e.g. `v1.2.0` (or `v1.2.0-rc1`). +3. Add a title/notes; check **"Set as a pre-release"** if it's a candidate. +4. **Publish release.** + +Publishing pushes the tag, which starts the build. When it finishes (~1–2 h; +the Windows CUDA jobs dominate), the prebuilt binaries are attached to that +Release. + +## Build a version without publishing (dry run) + +1. **Actions** tab → **Release** → **Run workflow**. +2. **Version:** enter `1.2.0` (or `v1.2.0`). +3. Leave the **Publish a GitHub Release** box **unchecked**. +4. **Run workflow** → builds all backends and uploads them as workflow + artifacts, but creates no tag or Release. Use this to validate before + cutting a release. ## What gets shipped @@ -41,10 +46,11 @@ Notes: ## When the workflow runs -- **Push to `main`** touching source/CMake files → builds **and** publishes. -- **Manual run from the Actions UI** → builds; publishes if **Publish** is - checked (effective only on `main`). -- A commit message containing `[no release]` skips the release entirely. +- **Pushing a `v*` tag** (e.g. by drafting + Publishing a Release) → builds and + attaches the binaries to that tag's Release. +- **Manual run from the Actions UI** (with a version) → builds; publishes only + if **Publish** is checked. +- `main` pushes do **not** trigger a release. ## Verification From 5465c170b13afb581ea19de02ca88a27dd92ce46 Mon Sep 17 00:00:00 2001 From: Anon Date: Tue, 18 Aug 2026 21:48:38 +0200 Subject: [PATCH 20/22] ci: preserve pre-release flag and notes when attaching binaries to a release --- .github/workflows/release.yml | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 89cbf17a..27ea1294 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -357,12 +357,24 @@ jobs: git tag "${TAG}" git push origin "${TAG}" fi - - name: Publish release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ needs.get-version.outputs.tag }} - name: ${{ needs.get-version.outputs.tag }} - draft: false - prerelease: false - generate_release_notes: true - files: assets/** \ No newline at end of file + - name: Check for existing release + id: relstate + run: | + TAG="${{ needs.get-version.outputs.tag }}" + if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + # Existing release (e.g. one the maintainer drafted and published): + # attach the built binaries only, preserving its pre-release flag and + # hand-written notes. --clobber allows rebuilding the same version. + - name: Upload binaries to existing release + if: ${{ steps.relstate.outputs.exists == 'true' }} + run: | + gh release upload "${{ needs.get-version.outputs.tag }}" assets/* --clobber --repo "$GITHUB_REPOSITORY" + # Newly-created tag with no release yet: create the release w/ notes. + - name: Create release + if: ${{ steps.relstate.outputs.exists != 'true' }} + run: | + gh release create "${{ needs.get-version.outputs.tag }}" assets/* --title "${{ needs.get-version.outputs.tag }}" --generate-notes --repo "$GITHUB_REPOSITORY" \ No newline at end of file From 29b6b729fb444dcf299de5f0c37d15b254125ee8 Mon Sep 17 00:00:00 2001 From: Anon Date: Wed, 19 Aug 2026 00:11:14 +0200 Subject: [PATCH 21/22] ci: upload only real package files (.zip/.tar.gz) to the release --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 27ea1294..c647b745 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -372,9 +372,9 @@ jobs: - name: Upload binaries to existing release if: ${{ steps.relstate.outputs.exists == 'true' }} run: | - gh release upload "${{ needs.get-version.outputs.tag }}" assets/* --clobber --repo "$GITHUB_REPOSITORY" + gh release upload "${{ needs.get-version.outputs.tag }}" assets/*.zip assets/*.tar.gz --clobber --repo "$GITHUB_REPOSITORY" # Newly-created tag with no release yet: create the release w/ notes. - name: Create release if: ${{ steps.relstate.outputs.exists != 'true' }} run: | - gh release create "${{ needs.get-version.outputs.tag }}" assets/* --title "${{ needs.get-version.outputs.tag }}" --generate-notes --repo "$GITHUB_REPOSITORY" \ No newline at end of file + gh release create "${{ needs.get-version.outputs.tag }}" assets/*.zip assets/*.tar.gz --title "${{ needs.get-version.outputs.tag }}" --generate-notes --repo "$GITHUB_REPOSITORY" \ No newline at end of file From 8b2a092521a5bc6e9dbcac0c79a15434fa0f5cfb Mon Sep 17 00:00:00 2001 From: Anon Date: Wed, 19 Aug 2026 12:43:14 +0200 Subject: [PATCH 22/22] ci: fix boolean publish gate (inputs.publish) so manual dispatch releases publish --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c647b745..83fdd094 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -335,7 +335,7 @@ jobs: - windows-cpu - windows-vulkan - windows-cuda - if: ${{ needs.check-release.outputs.should_release == 'true' && (github.ref_type == 'tag' || inputs.publish == 'true') }} + if: ${{ needs.check-release.outputs.should_release == 'true' && (github.ref_type == 'tag' || inputs.publish) }} runs-on: ubuntu-latest permissions: contents: write