From 2d465cb86a804b689c49ab6c46f4c1fff547bd5f Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 19:09:07 +0000 Subject: [PATCH 01/30] feat: add Docker image build workflow Builds and publishes multi-arch images to ghcr.io: full-cpu (latest, mutable) full-cpu- (pinned to commit) full-cuda12 (latest, mutable) full-cuda12- (pinned to commit) CPU builds are enabled; CUDA 12 builds are present but skipped by default for initial testing. --- .github/workflows/docker.yml | 224 +++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 .github/workflows/docker.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 00000000..624ae94f --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,224 @@ +# audio.cpp — Build and publish Docker images +# +# Produces multi-arch images on ghcr.io: +# full-cpu (latest, mutable) +# full-cpu- (pinned to commit, immutable) +# full-cuda12 (latest, mutable) +# full-cuda12- (pinned to commit, immutable) + +name: Publish Docker image + +on: + schedule: + - cron: '12 4 * * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }} + cancel-in-progress: true + +permissions: + packages: write + +env: + IMAGE_REPO: ${{ github.repository }} + +jobs: + # ── Shared metadata (date computed once for all jobs) ─────────────────── + metadata: + name: Metadata + runs-on: ubuntu-24.04 + outputs: + build_date: ${{ steps.date.outputs.date }} + short_sha: ${{ steps.sha.outputs.short_sha }} + steps: + - name: Get build date + id: date + run: echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_OUTPUT" + - name: Compute short SHA + id: sha + run: echo "short_sha=${GITHUB_SHA:0:8}" >> "$GITHUB_OUTPUT" + + # ── Build each arch, push by digest ──────────────────────────────────── + build: + name: ${{ matrix.tag }} (${{ matrix.platforms }}) + needs: metadata + runs-on: ${{ matrix.runs_on }} + strategy: + fail-fast: false + matrix: + include: + # ── CPU ── + - tag: cpu + dockerfile: .devops/cpu.Dockerfile + platforms: linux/amd64 + runs_on: ubuntu-24.04 + - tag: cpu + dockerfile: .devops/cpu.Dockerfile + platforms: linux/arm64 + runs_on: ubuntu-24.04-arm + # ── CUDA 12 (uncomment skip: false to enable) ── + - tag: cuda12 + dockerfile: .devops/cuda.Dockerfile + platforms: linux/amd64 + runs_on: ubuntu-24.04 + free_disk: true + cuda_version: "12.9.0" + skip: true + - tag: cuda12 + dockerfile: .devops/cuda.Dockerfile + platforms: linux/arm64 + runs_on: ubuntu-24.04-arm + free_disk: true + cuda_version: "12.9.0" + skip: true + steps: + - name: Skip when requested + if: ${{ matrix.skip == true }} + run: echo "Skipping ${{ matrix.tag }} build" + + - name: Checkout + if: ${{ matrix.skip != true }} + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + if: ${{ matrix.skip != true }} + uses: docker/setup-buildx-action@v4 + + - name: Log in to GHCR + if: ${{ matrix.skip != true }} + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Free disk space + if: ${{ matrix.skip != true && matrix.free_disk }} + uses: ggml-org/free-disk-space@v1.3.1 + with: + tool-cache: false + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: true + + - name: Build and push + id: push + if: ${{ matrix.skip != true }} + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.dockerfile }} + target: full + platforms: ${{ matrix.platforms }} + provenance: false + outputs: type=image,name=ghcr.io/${{ env.IMAGE_REPO }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true + build-args: | + BUILD_DATE=${{ needs.metadata.outputs.build_date }} + APP_VERSION=${{ github.sha }} + APP_REVISION=${{ github.sha }} + ${{ matrix.cuda_version && format('CUDA_VERSION={0}', matrix.cuda_version) || '' }} + cache-from: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.platforms }}-${{ matrix.tag }} + cache-to: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.platforms }}-${{ matrix.tag }},mode=max + + - name: Upload digest + if: ${{ matrix.skip != true }} + shell: bash + run: | + set -euo pipefail + mkdir -p /tmp/digests + arch="${{ matrix.platforms }}" + arch="${arch#linux/}" + digest="${{ steps.push.outputs.digest }}" + + if [[ "$digest" != sha256:* ]]; then + echo "::error::Invalid digest format: $digest" + exit 1 + fi + + printf '%s\n' "$digest" > "/tmp/digests/${{ matrix.tag }}-${arch}.txt" + + - name: Save digest artifact + if: ${{ matrix.skip != true }} + uses: actions/upload-artifact@v4 + with: + name: digest-${{ matrix.platforms }}-${{ matrix.tag }} + path: /tmp/digests/ + if-no-files-found: error + + # ── Merge per-arch digests into multi-arch manifests ─────────────────── + merge: + name: Merge ${{ matrix.tag }} + needs: [metadata, build] + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + tag: [cpu, cuda12] + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to GHCR + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Download digests + uses: actions/download-artifact@v4 + with: + pattern: digest-* + path: /tmp/digests + merge-multiple: true + + - name: Create manifest + shell: bash + run: | + set -euo pipefail + + repo="ghcr.io/${{ env.IMAGE_REPO }}" + sha="${{ needs.metadata.outputs.short_sha }}" + tag="${{ matrix.tag }}" + + mutable="full-${tag}" + immutable="full-${tag}-${sha}" + + # Collect per-arch digests + refs=() + for arch in amd64 arm64; do + file="/tmp/digests/${tag}-${arch}.txt" + if [ ! -f "$file" ]; then + echo " No digest for ${tag}/${arch} (skipped)" + continue + fi + digest="$(cat "$file")" + + if [[ "$digest" != sha256:* ]]; then + echo "::error::Invalid digest in ${file}: $digest" + exit 1 + fi + + refs+=("${repo}@${digest}") + done + + if [ ${#refs[@]} -eq 0 ]; then + echo "No digests found for ${tag}, skipping" + exit 0 + fi + + # Only create mutable tag when both arches are present. + if [ ${#refs[@]} -eq 1 ]; then + echo "Single arch only — skipping mutable tag ${mutable}" + echo " → ${immutable} (single arch)" + docker buildx imagetools create --tag "${repo}:${immutable}" "${refs[@]}" + else + echo " → ${mutable} (${#refs[@]} arches)" + docker buildx imagetools create --tag "${repo}:${mutable}" "${refs[@]}" + + echo " → ${immutable} (${#refs[@]} arches)" + docker buildx imagetools create --tag "${repo}:${immutable}" "${refs[@]}" + fi \ No newline at end of file From 986029ae3d1ac68c4f7d72c2f53dea5da1ac0bc2 Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 19:10:09 +0000 Subject: [PATCH 02/30] chore: add workflow_dispatch for testing --- .github/workflows/docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 624ae94f..8052a2a6 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -9,6 +9,7 @@ name: Publish Docker image on: + workflow_dispatch: # remove after testing schedule: - cron: '12 4 * * *' From 0f5784cfc228ad1a2de6313fafeb6f5ebd09feca Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 19:19:56 +0000 Subject: [PATCH 03/30] =?UTF-8?q?fix:=20replace=20slash=20in=20cache=20tag?= =?UTF-8?q?=20(linux/amd64=20=E2=86=92=20amd64)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/docker.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8052a2a6..3a657a20 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -52,15 +52,18 @@ jobs: - tag: cpu dockerfile: .devops/cpu.Dockerfile platforms: linux/amd64 + arch: amd64 runs_on: ubuntu-24.04 - tag: cpu dockerfile: .devops/cpu.Dockerfile platforms: linux/arm64 + arch: arm64 runs_on: ubuntu-24.04-arm # ── CUDA 12 (uncomment skip: false to enable) ── - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/amd64 + arch: amd64 runs_on: ubuntu-24.04 free_disk: true cuda_version: "12.9.0" @@ -68,6 +71,7 @@ jobs: - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 + arch: arm64 runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "12.9.0" @@ -121,8 +125,8 @@ jobs: APP_VERSION=${{ github.sha }} APP_REVISION=${{ github.sha }} ${{ matrix.cuda_version && format('CUDA_VERSION={0}', matrix.cuda_version) || '' }} - cache-from: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.platforms }}-${{ matrix.tag }} - cache-to: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.platforms }}-${{ matrix.tag }},mode=max + cache-from: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.arch }}-${{ matrix.tag }} + cache-to: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.arch }}-${{ matrix.tag }},mode=max - name: Upload digest if: ${{ matrix.skip != true }} From ffc67b703a8430f4e574ecfacf33bbcd29f6f7e2 Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 19:26:46 +0000 Subject: [PATCH 04/30] fix: use arch field in artifact names (avoid /) --- .github/workflows/docker.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 3a657a20..4930d711 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -134,8 +134,6 @@ jobs: run: | set -euo pipefail mkdir -p /tmp/digests - arch="${{ matrix.platforms }}" - arch="${arch#linux/}" digest="${{ steps.push.outputs.digest }}" if [[ "$digest" != sha256:* ]]; then @@ -143,13 +141,13 @@ jobs: exit 1 fi - printf '%s\n' "$digest" > "/tmp/digests/${{ matrix.tag }}-${arch}.txt" + printf '%s\n' "$digest" > "/tmp/digests/${{ matrix.tag }}-${{ matrix.arch }}.txt" - name: Save digest artifact if: ${{ matrix.skip != true }} uses: actions/upload-artifact@v4 with: - name: digest-${{ matrix.platforms }}-${{ matrix.tag }} + name: digest-${{ matrix.arch }}-${{ matrix.tag }} path: /tmp/digests/ if-no-files-found: error From 708704a63156e7b615027ae86269913cd51f0de4 Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 21:01:00 +0000 Subject: [PATCH 05/30] chore(docker): fix hardcoded URLs, add OCI annotations, strict merge - Pass IMAGE_URL and IMAGE_SOURCE via build-args instead of hardcoding them in Dockerfiles, so the labels always reflect the actual repository (works correctly for forks). - Add OCI index annotations (created, revision, url, source) to merged multi-arch manifests via imagetools create. - Make merge job strict: fail if 1/2 arch digests are missing (partial build failure), exit cleanly if 0/2 (intentionally skipped). --- .devops/cpu.Dockerfile | 4 ++-- .devops/cuda.Dockerfile | 4 ++-- .github/workflows/docker.yml | 43 ++++++++++++++++++++++++------------ 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/.devops/cpu.Dockerfile b/.devops/cpu.Dockerfile index a1a458d0..fd812c9d 100644 --- a/.devops/cpu.Dockerfile +++ b/.devops/cpu.Dockerfile @@ -58,8 +58,8 @@ FROM docker.io/ubuntu:$UBUNTU_VERSION AS base ARG BUILD_DATE=N/A ARG APP_VERSION=N/A ARG APP_REVISION=N/A -ARG IMAGE_URL=https://github.com/0xShug0/audio.cpp -ARG IMAGE_SOURCE=https://github.com/0xShug0/audio.cpp +ARG IMAGE_URL=N/A +ARG IMAGE_SOURCE=N/A LABEL org.opencontainers.image.created=$BUILD_DATE \ org.opencontainers.image.version=$APP_VERSION \ diff --git a/.devops/cuda.Dockerfile b/.devops/cuda.Dockerfile index e4aa52b8..34afdefe 100644 --- a/.devops/cuda.Dockerfile +++ b/.devops/cuda.Dockerfile @@ -63,8 +63,8 @@ FROM ${BASE_CUDA_RUN_CONTAINER} AS base ARG BUILD_DATE=N/A ARG APP_VERSION=N/A ARG APP_REVISION=N/A -ARG IMAGE_URL=https://github.com/0xShug0/audio.cpp -ARG IMAGE_SOURCE=https://github.com/0xShug0/audio.cpp +ARG IMAGE_URL=N/A +ARG IMAGE_SOURCE=N/A LABEL org.opencontainers.image.created=$BUILD_DATE \ org.opencontainers.image.version=$APP_VERSION \ diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4930d711..121f7879 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -124,6 +124,8 @@ jobs: BUILD_DATE=${{ needs.metadata.outputs.build_date }} APP_VERSION=${{ github.sha }} APP_REVISION=${{ github.sha }} + IMAGE_URL=${{ github.server_url }}/${{ github.repository }} + IMAGE_SOURCE=${{ github.server_url }}/${{ github.repository }} ${{ matrix.cuda_version && format('CUDA_VERSION={0}', matrix.cuda_version) || '' }} cache-from: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.arch }}-${{ matrix.tag }} cache-to: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.arch }}-${{ matrix.tag }},mode=max @@ -186,16 +188,20 @@ jobs: repo="ghcr.io/${{ env.IMAGE_REPO }}" sha="${{ needs.metadata.outputs.short_sha }}" tag="${{ matrix.tag }}" + build_date="${{ needs.metadata.outputs.build_date }}" + image_url="${{ github.server_url }}/${{ github.repository }}" mutable="full-${tag}" immutable="full-${tag}-${sha}" # Collect per-arch digests + expected_arches=(amd64 arm64) refs=() - for arch in amd64 arm64; do + missing=() + for arch in "${expected_arches[@]}"; do file="/tmp/digests/${tag}-${arch}.txt" if [ ! -f "$file" ]; then - echo " No digest for ${tag}/${arch} (skipped)" + missing+=("$arch") continue fi digest="$(cat "$file")" @@ -208,20 +214,29 @@ jobs: refs+=("${repo}@${digest}") done + # Zero digests → tag was intentionally skipped (skip: true), exit cleanly if [ ${#refs[@]} -eq 0 ]; then echo "No digests found for ${tag}, skipping" exit 0 fi - # Only create mutable tag when both arches are present. - if [ ${#refs[@]} -eq 1 ]; then - echo "Single arch only — skipping mutable tag ${mutable}" - echo " → ${immutable} (single arch)" - docker buildx imagetools create --tag "${repo}:${immutable}" "${refs[@]}" - else - echo " → ${mutable} (${#refs[@]} arches)" - docker buildx imagetools create --tag "${repo}:${mutable}" "${refs[@]}" - - echo " → ${immutable} (${#refs[@]} arches)" - docker buildx imagetools create --tag "${repo}:${immutable}" "${refs[@]}" - fi \ No newline at end of file + # Some but not all → a build failed; fail loudly so it's visible in CI + if [ ${#missing[@]} -gt 0 ]; then + echo "::error::Missing digests for ${tag}: ${missing[*]}" + echo " Partial failure — mutable tag may be stale" + exit 1 + fi + + # OCI annotations for the merged manifest + annotations=( + --annotation "index:org.opencontainers.image.created=${build_date}" + --annotation "index:org.opencontainers.image.revision=${{ github.sha }}" + --annotation "index:org.opencontainers.image.url=${image_url}" + --annotation "index:org.opencontainers.image.source=${image_url}" + ) + + echo " → ${mutable} (${#refs[@]} arches)" + docker buildx imagetools create "${annotations[@]}" --tag "${repo}:${mutable}" "${refs[@]}" + + echo " → ${immutable} (${#refs[@]} arches)" + docker buildx imagetools create "${annotations[@]}" --tag "${repo}:${immutable}" "${refs[@]}" From f8cf888d170bd2ee8de2bac0e7efcc1caded796e Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 23:03:02 +0200 Subject: [PATCH 06/30] enable cuda, disable cpu --- .github/workflows/docker.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 121f7879..25d2a87b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -54,12 +54,14 @@ jobs: platforms: linux/amd64 arch: amd64 runs_on: ubuntu-24.04 + skip: true - tag: cpu dockerfile: .devops/cpu.Dockerfile platforms: linux/arm64 arch: arm64 runs_on: ubuntu-24.04-arm - # ── CUDA 12 (uncomment skip: false to enable) ── + skip: true + # ── CUDA 12 ── - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/amd64 @@ -67,7 +69,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "12.9.0" - skip: true + skip: false - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -75,7 +77,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "12.9.0" - skip: true + skip: false steps: - name: Skip when requested if: ${{ matrix.skip == true }} From f6191242a200e628b4e74decfcd22a88e7735606 Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 21:41:18 +0000 Subject: [PATCH 07/30] feat: add CUDA 13.3.0 image to Docker workflow - Update default CUDA version from 12.9.0 to 12.9.2 - Add cuda13 tag (CUDA 13.3.0) for both amd64 and arm64 - Extend merge matrix to produce full-cuda13 / full-cuda13- images --- .devops/cuda.Dockerfile | 2 +- .github/workflows/docker.yml | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/.devops/cuda.Dockerfile b/.devops/cuda.Dockerfile index 34afdefe..04741e95 100644 --- a/.devops/cuda.Dockerfile +++ b/.devops/cuda.Dockerfile @@ -7,7 +7,7 @@ # [BUILD] Compile all release binaries with CUDA # ============================================================ ARG UBUNTU_VERSION=24.04 -ARG CUDA_VERSION=12.9.0 +ARG CUDA_VERSION=12.9.2 ARG BUILD_DATE=N/A ARG APP_VERSION=N/A ARG APP_REVISION=N/A diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 25d2a87b..42d4ffa9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -5,6 +5,8 @@ # full-cpu- (pinned to commit, immutable) # full-cuda12 (latest, mutable) # full-cuda12- (pinned to commit, immutable) +# full-cuda13 (latest, mutable) +# full-cuda13- (pinned to commit, immutable) name: Publish Docker image @@ -68,7 +70,7 @@ jobs: arch: amd64 runs_on: ubuntu-24.04 free_disk: true - cuda_version: "12.9.0" + cuda_version: "12.9.2" skip: false - tag: cuda12 dockerfile: .devops/cuda.Dockerfile @@ -76,7 +78,24 @@ jobs: arch: arm64 runs_on: ubuntu-24.04-arm free_disk: true - cuda_version: "12.9.0" + cuda_version: "12.9.2" + skip: false + # ── CUDA 13 ── + - tag: cuda13 + dockerfile: .devops/cuda.Dockerfile + platforms: linux/amd64 + arch: amd64 + runs_on: ubuntu-24.04 + free_disk: true + cuda_version: "13.3.0" + skip: false + - tag: cuda13 + dockerfile: .devops/cuda.Dockerfile + platforms: linux/arm64 + arch: arm64 + runs_on: ubuntu-24.04-arm + free_disk: true + cuda_version: "13.3.0" skip: false steps: - name: Skip when requested @@ -163,7 +182,7 @@ jobs: strategy: fail-fast: false matrix: - tag: [cpu, cuda12] + tag: [cpu, cuda12, cuda13] steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 From 565b9ada648b0d97ce09a17ca3c34c664f6ff32a Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 21:42:55 +0000 Subject: [PATCH 08/30] chore: add .idea/ to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 06fc54e9..0d202bdf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /build*/ /cmake-build*/ ._* +.idea/ .vs/ .vscode/ compile_commands.json From 93dcee7b17f0d26b033278b73d4325f7c4a8cfff Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 22:58:58 +0000 Subject: [PATCH 09/30] fix: cleanup docker workflow name and trigger order - Rename workflow from 'Publish Docker image' to 'Build and publish Docker images' - Move schedule trigger before workflow_dispatch (schedule first, dispatch optional) - Remove stale 'remove after testing' comment --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 42d4ffa9..ac15b3e5 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -8,12 +8,12 @@ # full-cuda13 (latest, mutable) # full-cuda13- (pinned to commit, immutable) -name: Publish Docker image +name: Build and publish Docker images on: - workflow_dispatch: # remove after testing schedule: - cron: '12 4 * * *' + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }} From fff069ba912031eb8045086744057cffafac2477 Mon Sep 17 00:00:00 2001 From: xashr Date: Sat, 11 Jul 2026 22:59:17 +0000 Subject: [PATCH 10/30] refactor: use date-based tags for immutable Docker images Replace short SHA (e.g. a1b2c3d4) with date (e.g. 20260711) for immutable Docker image tags. Immutable tags are now human-readable and sortable, e.g. full-cuda12-20260711 instead of full-cuda12-a1b2c3d4. --- .github/workflows/docker.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ac15b3e5..31f8ea7c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,11 +2,11 @@ # # Produces multi-arch images on ghcr.io: # full-cpu (latest, mutable) -# full-cpu- (pinned to commit, immutable) +# full-cpu-YYYYMMDD (pinned to date, immutable) # full-cuda12 (latest, mutable) -# full-cuda12- (pinned to commit, immutable) +# full-cuda12-YYYYMMDD (pinned to date, immutable) # full-cuda13 (latest, mutable) -# full-cuda13- (pinned to commit, immutable) +# full-cuda13-YYYYMMDD (pinned to date, immutable) name: Build and publish Docker images @@ -32,14 +32,13 @@ jobs: runs-on: ubuntu-24.04 outputs: build_date: ${{ steps.date.outputs.date }} - short_sha: ${{ steps.sha.outputs.short_sha }} + date_tag: ${{ steps.date.outputs.tag }} steps: - name: Get build date id: date - run: echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_OUTPUT" - - name: Compute short SHA - id: sha - run: echo "short_sha=${GITHUB_SHA:0:8}" >> "$GITHUB_OUTPUT" + run: | + echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_OUTPUT" + echo "tag=$(date -u +'%Y%m%d')" >> "$GITHUB_OUTPUT" # ── Build each arch, push by digest ──────────────────────────────────── build: @@ -207,13 +206,13 @@ jobs: set -euo pipefail repo="ghcr.io/${{ env.IMAGE_REPO }}" - sha="${{ needs.metadata.outputs.short_sha }}" + date_tag="${{ needs.metadata.outputs.date_tag }}" tag="${{ matrix.tag }}" build_date="${{ needs.metadata.outputs.build_date }}" image_url="${{ github.server_url }}/${{ github.repository }}" mutable="full-${tag}" - immutable="full-${tag}-${sha}" + immutable="full-${tag}-${date_tag}" # Collect per-arch digests expected_arches=(amd64 arm64) From e6e92dae4c3e581a572cf51ead241f4083d2bbc5 Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 01:26:02 +0200 Subject: [PATCH 11/30] remove healthcheck --- .devops/cpu.Dockerfile | 3 --- .devops/cuda.Dockerfile | 3 --- 2 files changed, 6 deletions(-) diff --git a/.devops/cpu.Dockerfile b/.devops/cpu.Dockerfile index fd812c9d..51eafac2 100644 --- a/.devops/cpu.Dockerfile +++ b/.devops/cpu.Dockerfile @@ -90,7 +90,4 @@ COPY --from=build /app/full /app USER ubuntu -HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=15s \ - CMD curl -f http://localhost:8080/health || exit 1 - ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/.devops/cuda.Dockerfile b/.devops/cuda.Dockerfile index 04741e95..181a8b14 100644 --- a/.devops/cuda.Dockerfile +++ b/.devops/cuda.Dockerfile @@ -95,8 +95,5 @@ COPY --from=build /app/full /app USER ubuntu -HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=15s \ - CMD curl -f http://localhost:8080/health || exit 1 - ENTRYPOINT ["/app/entrypoint.sh"] From 6239f7efd16635339bcec33baaef1308e7dcf34e Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 17:11:46 +0000 Subject: [PATCH 12/30] fix(docker): disable GGML_NATIVE for portable CPU binaries Disable ENGINE_ENABLE_NATIVE_CPU in Docker builds so the compiled binaries do not use -march=native. This prevents SIGILL crashes when running arm64 images on a different ARM CPU than the build runner (e.g. Ampere Altra CI runner vs Apple M-series). Matches the approach used by llama.cpp's Docker images. --- .devops/cpu.Dockerfile | 1 + .devops/cuda.Dockerfile | 1 + 2 files changed, 2 insertions(+) diff --git a/.devops/cpu.Dockerfile b/.devops/cpu.Dockerfile index 51eafac2..f44a1945 100644 --- a/.devops/cpu.Dockerfile +++ b/.devops/cpu.Dockerfile @@ -34,6 +34,7 @@ RUN cmake -S . -B build \ -DENGINE_ENABLE_CUDA=OFF \ -DENGINE_ENABLE_VULKAN=OFF \ -DENGINE_ENABLE_OPENMP=ON \ + -DENGINE_ENABLE_NATIVE_CPU=OFF \ -DENGINE_BUILD_EXAMPLES=OFF \ -DENGINE_BUILD_TESTS=OFF \ -DENGINE_BUILD_WARMBENCH=OFF && \ diff --git a/.devops/cuda.Dockerfile b/.devops/cuda.Dockerfile index 181a8b14..97421896 100644 --- a/.devops/cuda.Dockerfile +++ b/.devops/cuda.Dockerfile @@ -39,6 +39,7 @@ RUN cmake -S . -B build \ -DENGINE_ENABLE_CUDA_GRAPHS=ON \ -DENGINE_ENABLE_VULKAN=OFF \ -DENGINE_ENABLE_OPENMP=ON \ + -DENGINE_ENABLE_NATIVE_CPU=OFF \ -DENGINE_BUILD_EXAMPLES=OFF \ -DENGINE_BUILD_TESTS=OFF \ -DENGINE_BUILD_WARMBENCH=OFF && \ From 719c671f4950bf6588c08f50c9314b37c1624c8f Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 17:12:38 +0000 Subject: [PATCH 13/30] chore(docker): enable CPU builds, disable CUDA builds - Enable CPU image builds for amd64 and arm64 (skip: false) - Disable CUDA 12 and CUDA 13 builds (skip: true) This allows the CPU images to be published with the GGML_NATIVE fix, while CUDA builds are temporarily disabled for testing. --- .github/workflows/docker.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 31f8ea7c..9de585af 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -55,13 +55,13 @@ jobs: platforms: linux/amd64 arch: amd64 runs_on: ubuntu-24.04 - skip: true + skip: false - tag: cpu dockerfile: .devops/cpu.Dockerfile platforms: linux/arm64 arch: arm64 runs_on: ubuntu-24.04-arm - skip: true + skip: false # ── CUDA 12 ── - tag: cuda12 dockerfile: .devops/cuda.Dockerfile @@ -70,7 +70,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "12.9.2" - skip: false + skip: true - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -78,7 +78,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "12.9.2" - skip: false + skip: true # ── CUDA 13 ── - tag: cuda13 dockerfile: .devops/cuda.Dockerfile @@ -87,7 +87,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "13.3.0" - skip: false + skip: true - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -95,7 +95,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "13.3.0" - skip: false + skip: true steps: - name: Skip when requested if: ${{ matrix.skip == true }} From 416232f0bd69751732c34d7fb00638ab06e17b7c Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 17:47:06 +0000 Subject: [PATCH 14/30] ci(docker): add commit SHA to tags and skip builds with no new commits - Add 7-char commit SHA to immutable tags (full-cpu-YYYYMMDD-HHHHHHH) - Add check-commits job to skip daily builds when no new commits - Manual trigger (workflow_dispatch) always builds, bypassing the check - Rename matrix skip flag to enabled for clarity - Track last built commit via lightweight git tag last-docker-build --- .github/workflows/docker.yml | 114 +++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 26 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 9de585af..4c1d37b9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,12 +1,12 @@ # audio.cpp — Build and publish Docker images # # Produces multi-arch images on ghcr.io: -# full-cpu (latest, mutable) -# full-cpu-YYYYMMDD (pinned to date, immutable) -# full-cuda12 (latest, mutable) -# full-cuda12-YYYYMMDD (pinned to date, immutable) -# full-cuda13 (latest, mutable) -# full-cuda13-YYYYMMDD (pinned to date, immutable) +# full-cpu (latest, mutable) +# full-cpu-YYYYMMDD-HHHHHHH (pinned to date + short SHA, immutable) +# full-cuda12 (latest, mutable) +# full-cuda12-YYYYMMDD-HHHHHHH (pinned to date + short SHA, immutable) +# full-cuda13 (latest, mutable) +# full-cuda13-YYYYMMDD-HHHHHHH (pinned to date + short SHA, immutable) name: Build and publish Docker images @@ -20,19 +20,62 @@ concurrency: cancel-in-progress: true permissions: + contents: write packages: write env: IMAGE_REPO: ${{ github.repository }} jobs: + # ── Check for new commits ────────────────────────────────────────────── + check-commits: + name: Check commits + runs-on: ubuntu-24.04 + outputs: + skip_build: ${{ steps.check.outputs.skip }} + short_sha: ${{ steps.check.outputs.short_sha }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for new commits + id: check + run: | + SHORT_SHA=$(git rev-parse --short=7 HEAD) + echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT" + + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "Manual trigger — building" + echo "skip=false" >> "$GITHUB_OUTPUT" + else + LAST_TAG=$(git tag -l 'last-docker-build' | head -1) + if [[ -n "$LAST_TAG" ]]; then + LAST_SHA=$(git rev-list -1 "$LAST_TAG" 2>/dev/null || echo "") + HEAD_SHA=$(git rev-parse HEAD) + if [[ "$LAST_SHA" == "$HEAD_SHA" ]]; then + echo "No new commits since last daily build — skipping" + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "New commits found — building" + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + else + echo "No previous build tag found — building" + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + fi + # ── Shared metadata (date computed once for all jobs) ─────────────────── metadata: name: Metadata + needs: check-commits + if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ubuntu-24.04 outputs: build_date: ${{ steps.date.outputs.date }} - date_tag: ${{ steps.date.outputs.tag }} + date_tag: ${{ steps.date.outputs.tag }} steps: - name: Get build date id: date @@ -43,7 +86,8 @@ jobs: # ── Build each arch, push by digest ──────────────────────────────────── build: name: ${{ matrix.tag }} (${{ matrix.platforms }}) - needs: metadata + needs: [check-commits, metadata] + if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ${{ matrix.runs_on }} strategy: fail-fast: false @@ -55,13 +99,13 @@ jobs: platforms: linux/amd64 arch: amd64 runs_on: ubuntu-24.04 - skip: false + enabled: true - tag: cpu dockerfile: .devops/cpu.Dockerfile platforms: linux/arm64 arch: arm64 runs_on: ubuntu-24.04-arm - skip: false + enabled: true # ── CUDA 12 ── - tag: cuda12 dockerfile: .devops/cuda.Dockerfile @@ -70,7 +114,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "12.9.2" - skip: true + enabled: false - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -78,7 +122,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "12.9.2" - skip: true + enabled: false # ── CUDA 13 ── - tag: cuda13 dockerfile: .devops/cuda.Dockerfile @@ -87,7 +131,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "13.3.0" - skip: true + enabled: false - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -95,22 +139,22 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "13.3.0" - skip: true + enabled: false steps: - - name: Skip when requested - if: ${{ matrix.skip == true }} + - name: Skip when not enabled + if: ${{ matrix.enabled != true }} run: echo "Skipping ${{ matrix.tag }} build" - name: Checkout - if: ${{ matrix.skip != true }} + if: ${{ matrix.enabled == true }} uses: actions/checkout@v4 - name: Set up Docker Buildx - if: ${{ matrix.skip != true }} + if: ${{ matrix.enabled == true }} uses: docker/setup-buildx-action@v4 - name: Log in to GHCR - if: ${{ matrix.skip != true }} + if: ${{ matrix.enabled == true }} uses: docker/login-action@v4 with: registry: ghcr.io @@ -118,7 +162,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Free disk space - if: ${{ matrix.skip != true && matrix.free_disk }} + if: ${{ matrix.enabled == true && matrix.free_disk }} uses: ggml-org/free-disk-space@v1.3.1 with: tool-cache: false @@ -131,7 +175,7 @@ jobs: - name: Build and push id: push - if: ${{ matrix.skip != true }} + if: ${{ matrix.enabled == true }} uses: docker/build-push-action@v6 with: context: . @@ -151,7 +195,7 @@ jobs: cache-to: type=registry,ref=ghcr.io/${{ env.IMAGE_REPO }}:cache-${{ matrix.arch }}-${{ matrix.tag }},mode=max - name: Upload digest - if: ${{ matrix.skip != true }} + if: ${{ matrix.enabled == true }} shell: bash run: | set -euo pipefail @@ -166,7 +210,7 @@ jobs: printf '%s\n' "$digest" > "/tmp/digests/${{ matrix.tag }}-${{ matrix.arch }}.txt" - name: Save digest artifact - if: ${{ matrix.skip != true }} + if: ${{ matrix.enabled == true }} uses: actions/upload-artifact@v4 with: name: digest-${{ matrix.arch }}-${{ matrix.tag }} @@ -176,7 +220,8 @@ jobs: # ── Merge per-arch digests into multi-arch manifests ─────────────────── merge: name: Merge ${{ matrix.tag }} - needs: [metadata, build] + needs: [check-commits, metadata, build] + if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -207,12 +252,13 @@ jobs: repo="ghcr.io/${{ env.IMAGE_REPO }}" date_tag="${{ needs.metadata.outputs.date_tag }}" + short_sha="${{ needs.check-commits.outputs.short_sha }}" tag="${{ matrix.tag }}" build_date="${{ needs.metadata.outputs.build_date }}" image_url="${{ github.server_url }}/${{ github.repository }}" mutable="full-${tag}" - immutable="full-${tag}-${date_tag}" + immutable="full-${tag}-${date_tag}-${short_sha}" # Collect per-arch digests expected_arches=(amd64 arm64) @@ -234,7 +280,7 @@ jobs: refs+=("${repo}@${digest}") done - # Zero digests → tag was intentionally skipped (skip: true), exit cleanly + # Zero digests → variant was disabled, exit cleanly if [ ${#refs[@]} -eq 0 ]; then echo "No digests found for ${tag}, skipping" exit 0 @@ -260,3 +306,19 @@ jobs: echo " → ${immutable} (${#refs[@]} arches)" docker buildx imagetools create "${annotations[@]}" --tag "${repo}:${immutable}" "${refs[@]}" + + # ── Update last-docker-build tag ────────────────────────────────────── + update-tag: + name: Update last-docker-build tag + needs: [check-commits, merge] + if: ${{ needs.check-commits.outputs.skip_build != 'true' }} + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Update last-docker-build tag + run: | + set -euo pipefail + git tag -f last-docker-build HEAD + git push origin last-docker-build -f \ No newline at end of file From 9562d1e60bbd36845cd516ca5c9086d5c1638972 Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 17:47:47 +0000 Subject: [PATCH 15/30] ci(docker): temporarily schedule builds every hour for testing --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4c1d37b9..e6c8c136 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ name: Build and publish Docker images on: schedule: - - cron: '12 4 * * *' + - cron: '0 * * * *' workflow_dispatch: concurrency: From 579877f78cc9212cdcc71f140872a42d1dd2afa0 Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 18:27:01 +0000 Subject: [PATCH 16/30] ci(docker): schedule builds every 30 minutes for testing --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e6c8c136..5ca5b287 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ name: Build and publish Docker images on: schedule: - - cron: '0 * * * *' + - cron: '0,30 * * * *' workflow_dispatch: concurrency: From 56763ab5a15c5f7a7ebc97081bab09d13493836b Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 18:35:16 +0000 Subject: [PATCH 17/30] ci(docker): schedule builds at :10 and :40 past each hour --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5ca5b287..29f9dab9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ name: Build and publish Docker images on: schedule: - - cron: '0,30 * * * *' + - cron: '10,40 * * * *' workflow_dispatch: concurrency: From ce49860cc605de8a3a704f1fe30fe13147b0764b Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 18:48:08 +0000 Subject: [PATCH 18/30] ci(docker): add force_build input and revert to daily schedule - Add workflow_dispatch input 'force_build' (default: true) - When force_build=false, manual trigger respects commit check (skip if no new commits) - Revert schedule from hourly back to daily (4:12 AM UTC) --- .github/workflows/docker.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 29f9dab9..2036c04e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,8 +12,13 @@ name: Build and publish Docker images on: schedule: - - cron: '10,40 * * * *' + - cron: '12 4 * * *' workflow_dispatch: + inputs: + force_build: + description: 'Force build even if no new commits' + type: boolean + default: true concurrency: group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }} @@ -46,8 +51,8 @@ jobs: SHORT_SHA=$(git rev-parse --short=7 HEAD) echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT" - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "Manual trigger — building" + if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.force_build }}" == 'true' ]]; then + echo "Manual trigger (force_build=true) — building" echo "skip=false" >> "$GITHUB_OUTPUT" else LAST_TAG=$(git tag -l 'last-docker-build' | head -1) From 3ee7d866de6aa3f457bb811532b42bf800a503e0 Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 19:01:40 +0000 Subject: [PATCH 19/30] ci(docker): upgrade GitHub Actions to latest major versions - actions/checkout: v4 -> v5 (Node 24 runtime) - docker/build-push-action: v6 -> v7 (Node 24 runtime, ESM) - actions/upload-artifact: v4 -> v7 (Node 24 runtime, ESM) - actions/download-artifact: v4 -> v8 (Node 24 runtime, ESM) No input parameter changes needed; all changes are version label bumps on the floating major-version tags. --- .github/workflows/docker.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2036c04e..f1825df5 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -41,7 +41,7 @@ jobs: short_sha: ${{ steps.check.outputs.short_sha }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 @@ -152,7 +152,7 @@ jobs: - name: Checkout if: ${{ matrix.enabled == true }} - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Docker Buildx if: ${{ matrix.enabled == true }} @@ -181,7 +181,7 @@ jobs: - name: Build and push id: push if: ${{ matrix.enabled == true }} - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . file: ${{ matrix.dockerfile }} @@ -216,7 +216,7 @@ jobs: - name: Save digest artifact if: ${{ matrix.enabled == true }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: digest-${{ matrix.arch }}-${{ matrix.tag }} path: /tmp/digests/ @@ -244,7 +244,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Download digests - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: pattern: digest-* path: /tmp/digests @@ -320,7 +320,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Update last-docker-build tag run: | From 5d78123558f414b1a5808537b72c029270996977 Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 19:15:24 +0000 Subject: [PATCH 20/30] ci(docker): improve job display names Rename workflow jobs to use consistent verb-first naming: - Check commits -> Check for new commits - Metadata -> Generate metadata - Build variants -> Build (tag, platform) - Merge variants -> Merge (tag) - Update last-docker-build tag -> Update build tag --- .github/workflows/docker.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f1825df5..ea1dd113 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -34,7 +34,7 @@ env: jobs: # ── Check for new commits ────────────────────────────────────────────── check-commits: - name: Check commits + name: Check for new commits runs-on: ubuntu-24.04 outputs: skip_build: ${{ steps.check.outputs.skip }} @@ -74,7 +74,7 @@ jobs: # ── Shared metadata (date computed once for all jobs) ─────────────────── metadata: - name: Metadata + name: Generate metadata needs: check-commits if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ubuntu-24.04 @@ -90,7 +90,7 @@ jobs: # ── Build each arch, push by digest ──────────────────────────────────── build: - name: ${{ matrix.tag }} (${{ matrix.platforms }}) + name: Build (${{ matrix.tag }}, ${{ matrix.platforms }}) needs: [check-commits, metadata] if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ${{ matrix.runs_on }} @@ -224,7 +224,7 @@ jobs: # ── Merge per-arch digests into multi-arch manifests ─────────────────── merge: - name: Merge ${{ matrix.tag }} + name: Merge (${{ matrix.tag }}) needs: [check-commits, metadata, build] if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ubuntu-24.04 @@ -314,7 +314,7 @@ jobs: # ── Update last-docker-build tag ────────────────────────────────────── update-tag: - name: Update last-docker-build tag + name: Update build tag needs: [check-commits, merge] if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ubuntu-24.04 From 512d9f234ecb4e204bb19a8875cae056d0d77ede Mon Sep 17 00:00:00 2001 From: xashr Date: Sun, 12 Jul 2026 20:13:06 +0000 Subject: [PATCH 21/30] style: align Docker comment headers to 80-char width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace 3-line === separator style with single-line ── header style - Match comment style from docker.yml workflow - Pad all section headers to exactly 80 characters --- .devops/cpu.Dockerfile | 14 ++++---------- .devops/cuda.Dockerfile | 15 ++++----------- .github/workflows/docker.yml | 12 ++++++------ 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/.devops/cpu.Dockerfile b/.devops/cpu.Dockerfile index f44a1945..e22959e1 100644 --- a/.devops/cpu.Dockerfile +++ b/.devops/cpu.Dockerfile @@ -3,9 +3,7 @@ # Usage: # docker build -f .devops/cpu.Dockerfile -t local/audiocpp:full-cpu . -# ============================================================ -# [BUILD] Compile all release binaries -# ============================================================ +# ── BUILD: Compile all release binaries ─────────────────────────────────────── ARG UBUNTU_VERSION=24.04 ARG BUILD_DATE=N/A ARG APP_VERSION=N/A @@ -28,7 +26,7 @@ ENV CC=gcc-${GCC_VERSION} CXX=g++-${GCC_VERSION} WORKDIR /app COPY . . -# Configure +# Configure and build RUN cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DENGINE_ENABLE_CUDA=OFF \ @@ -51,9 +49,7 @@ RUN mkdir -p /app/full && \ cp .devops/entrypoint.sh /app/full/entrypoint.sh && \ chmod +x /app/full/entrypoint.sh -# ============================================================ -# [BASE] Shared runtime (OS + common libs) -# ============================================================ +# ── BASE: Shared runtime (OS + common libs) ─────────────────────────────────── FROM docker.io/ubuntu:$UBUNTU_VERSION AS base ARG BUILD_DATE=N/A @@ -82,9 +78,7 @@ RUN apt-get update && \ WORKDIR /app -# ============================================================ -# [FULL] All binaries + entrypoint.sh multiplexer -# ============================================================ +# ── FULL: All binaries + entrypoint.sh multiplexer ──────────────────────────── FROM base AS full COPY --from=build /app/full /app diff --git a/.devops/cuda.Dockerfile b/.devops/cuda.Dockerfile index 97421896..eb3112f4 100644 --- a/.devops/cuda.Dockerfile +++ b/.devops/cuda.Dockerfile @@ -3,9 +3,7 @@ # Usage: # docker build -f .devops/cuda.Dockerfile -t local/audiocpp:full-cuda . -# ============================================================ -# [BUILD] Compile all release binaries with CUDA -# ============================================================ +# ── BUILD: Compile all release binaries with CUDA ───────────────────────────── ARG UBUNTU_VERSION=24.04 ARG CUDA_VERSION=12.9.2 ARG BUILD_DATE=N/A @@ -32,7 +30,7 @@ ENV CC=gcc-${GCC_VERSION} CXX=g++-${GCC_VERSION} CUDAHOSTCXX=g++-${GCC_VERSION} WORKDIR /app COPY . . -# Configure +# Configure and build RUN cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DENGINE_ENABLE_CUDA=ON \ @@ -56,9 +54,7 @@ RUN mkdir -p /app/full && \ cp .devops/entrypoint.sh /app/full/entrypoint.sh && \ chmod +x /app/full/entrypoint.sh -# ============================================================ -# [BASE] Shared runtime (NVIDIA CUDA + common libs) -# ============================================================ +# ── BASE: Shared runtime (NVIDIA CUDA + common libs) ────────────────────────── FROM ${BASE_CUDA_RUN_CONTAINER} AS base ARG BUILD_DATE=N/A @@ -87,9 +83,7 @@ RUN apt-get update && \ WORKDIR /app -# ============================================================ -# [FULL] All binaries + entrypoint.sh multiplexer -# ============================================================ +# ── FULL: All binaries + entrypoint.sh multiplexer ──────────────────────────── FROM base AS full COPY --from=build /app/full /app @@ -97,4 +91,3 @@ COPY --from=build /app/full /app USER ubuntu ENTRYPOINT ["/app/entrypoint.sh"] - diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ea1dd113..bc8c2870 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -32,7 +32,7 @@ env: IMAGE_REPO: ${{ github.repository }} jobs: - # ── Check for new commits ────────────────────────────────────────────── + # ── Check for new commits ─────────────────────────────────────────────────── check-commits: name: Check for new commits runs-on: ubuntu-24.04 @@ -72,7 +72,7 @@ jobs: fi fi - # ── Shared metadata (date computed once for all jobs) ─────────────────── + # ── Shared metadata (date computed once for all jobs) ─────────────────────── metadata: name: Generate metadata needs: check-commits @@ -88,7 +88,7 @@ jobs: echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_OUTPUT" echo "tag=$(date -u +'%Y%m%d')" >> "$GITHUB_OUTPUT" - # ── Build each arch, push by digest ──────────────────────────────────── + # ── Build each arch, push by digest ───────────────────────────────────────── build: name: Build (${{ matrix.tag }}, ${{ matrix.platforms }}) needs: [check-commits, metadata] @@ -222,7 +222,7 @@ jobs: path: /tmp/digests/ if-no-files-found: error - # ── Merge per-arch digests into multi-arch manifests ─────────────────── + # ── Merge per-arch digests into multi-arch manifests ──────────────────────── merge: name: Merge (${{ matrix.tag }}) needs: [check-commits, metadata, build] @@ -312,7 +312,7 @@ jobs: echo " → ${immutable} (${#refs[@]} arches)" docker buildx imagetools create "${annotations[@]}" --tag "${repo}:${immutable}" "${refs[@]}" - # ── Update last-docker-build tag ────────────────────────────────────── + # ── Update last-docker-build tag ──────────────────────────────────────────── update-tag: name: Update build tag needs: [check-commits, merge] @@ -326,4 +326,4 @@ jobs: run: | set -euo pipefail git tag -f last-docker-build HEAD - git push origin last-docker-build -f \ No newline at end of file + git push origin last-docker-build -f From 6adad5ffbd887085886fd305c7b6bb4f83845079 Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 19:03:24 +0200 Subject: [PATCH 22/30] docker.yml minor change --- .github/workflows/docker.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index bc8c2870..1afcda4e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,18 +1,18 @@ # audio.cpp — Build and publish Docker images # -# Produces multi-arch images on ghcr.io: -# full-cpu (latest, mutable) -# full-cpu-YYYYMMDD-HHHHHHH (pinned to date + short SHA, immutable) -# full-cuda12 (latest, mutable) +# Produces multi-arch (amd64, arm64) images on ghcr.io: +# full-cpu (latest, mutable) +# full-cpu-YYYYMMDD-HHHHHHH (pinned to date + short SHA, immutable) +# full-cuda12 (latest, mutable) # full-cuda12-YYYYMMDD-HHHHHHH (pinned to date + short SHA, immutable) -# full-cuda13 (latest, mutable) +# full-cuda13 (latest, mutable) # full-cuda13-YYYYMMDD-HHHHHHH (pinned to date + short SHA, immutable) name: Build and publish Docker images on: schedule: - - cron: '12 4 * * *' + - cron: '22 2 * * *' workflow_dispatch: inputs: force_build: From aa5fe36e1e712b066d07aa20f5320b57d8f44bea Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 19:15:55 +0200 Subject: [PATCH 23/30] permissions, comment --- .github/workflows/docker.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1afcda4e..61aa8d02 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -11,8 +11,10 @@ name: Build and publish Docker images on: + # Runs daily at 03:21 UTC schedule: - - cron: '22 2 * * *' + - cron: '21 3 * * *' + # or when triggered manually workflow_dispatch: inputs: force_build: @@ -25,7 +27,6 @@ concurrency: cancel-in-progress: true permissions: - contents: write packages: write env: @@ -318,6 +319,8 @@ jobs: needs: [check-commits, merge] if: ${{ needs.check-commits.outputs.skip_build != 'true' }} runs-on: ubuntu-24.04 + permissions: + contents: write steps: - name: Checkout uses: actions/checkout@v5 From e5b6b7b9efdc77352499fdf2f348aa7e2e6b67fb Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 19:34:11 +0200 Subject: [PATCH 24/30] enable cuda --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 61aa8d02..a788a759 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -120,7 +120,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "12.9.2" - enabled: false + enabled: true - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -128,7 +128,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "12.9.2" - enabled: false + enabled: true # ── CUDA 13 ── - tag: cuda13 dockerfile: .devops/cuda.Dockerfile From ec94d4787d67560ad51c4016bb20df5fecead719 Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 20:25:48 +0200 Subject: [PATCH 25/30] enable cuda13 --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a788a759..786a8175 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -137,7 +137,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "13.3.0" - enabled: false + enabled: yes - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -145,7 +145,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "13.3.0" - enabled: false + enabled: yes steps: - name: Skip when not enabled if: ${{ matrix.enabled != true }} From 219d4346d55dd1a6916d5ff7b427c89b69fbab89 Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 20:45:10 +0200 Subject: [PATCH 26/30] enable cuda13 --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 786a8175..4fa8a07b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -137,7 +137,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "13.3.0" - enabled: yes + enabled: true - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -145,7 +145,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "13.3.0" - enabled: yes + enabled: true steps: - name: Skip when not enabled if: ${{ matrix.enabled != true }} From fb40ee9f03d38a1eafdd367ad1efc6da2f34fd21 Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 23:24:28 +0200 Subject: [PATCH 27/30] improve build failure handling for merge --- .github/workflows/docker.yml | 40 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4fa8a07b..c6c66e71 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -227,7 +227,10 @@ jobs: merge: name: Merge (${{ matrix.tag }}) needs: [check-commits, metadata, build] - if: ${{ needs.check-commits.outputs.skip_build != 'true' }} + # Merge will only run if there was actually a new commit to act on and + # if all build jobs succeeded. As soon as one build fails, we won't + # produce any merged images. + if: ${{ needs.check-commits.outputs.skip_build != 'true' && needs.build.result == 'success' }} runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -266,39 +269,24 @@ jobs: mutable="full-${tag}" immutable="full-${tag}-${date_tag}-${short_sha}" - # Collect per-arch digests + # Collect per-arch digests. + # Because this job is gated on needs.build.result == 'success', a missing + # digest can only mean the variant was intentionally disabled (enabled: false). expected_arches=(amd64 arm64) refs=() - missing=() for arch in "${expected_arches[@]}"; do file="/tmp/digests/${tag}-${arch}.txt" - if [ ! -f "$file" ]; then - missing+=("$arch") - continue - fi - digest="$(cat "$file")" - - if [[ "$digest" != sha256:* ]]; then - echo "::error::Invalid digest in ${file}: $digest" - exit 1 - fi - - refs+=("${repo}@${digest}") + [ -f "$file" ] || continue + refs+=("${repo}@$(cat "$file")") done - # Zero digests → variant was disabled, exit cleanly + echo "${tag}: ${#refs[@]}/${#expected_arches[@]} digests merged" + if [ ${#refs[@]} -eq 0 ]; then - echo "No digests found for ${tag}, skipping" + echo " → skipping (all variants disabled)" exit 0 fi - # Some but not all → a build failed; fail loudly so it's visible in CI - if [ ${#missing[@]} -gt 0 ]; then - echo "::error::Missing digests for ${tag}: ${missing[*]}" - echo " Partial failure — mutable tag may be stale" - exit 1 - fi - # OCI annotations for the merged manifest annotations=( --annotation "index:org.opencontainers.image.created=${build_date}" @@ -307,10 +295,10 @@ jobs: --annotation "index:org.opencontainers.image.source=${image_url}" ) - echo " → ${mutable} (${#refs[@]} arches)" + echo " → ${mutable}" docker buildx imagetools create "${annotations[@]}" --tag "${repo}:${mutable}" "${refs[@]}" - echo " → ${immutable} (${#refs[@]} arches)" + echo " → ${immutable}" docker buildx imagetools create "${annotations[@]}" --tag "${repo}:${immutable}" "${refs[@]}" # ── Update last-docker-build tag ──────────────────────────────────────────── From c9927fbb693b3a1b04191c4cef45b549c4915dbe Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 23:26:50 +0200 Subject: [PATCH 28/30] test --- .github/workflows/docker.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c6c66e71..0cda4711 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -112,7 +112,7 @@ jobs: arch: arm64 runs_on: ubuntu-24.04-arm enabled: true - # ── CUDA 12 ── + # ── CUDA 12 ── (arm64 disabled for testing) - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/amd64 @@ -128,8 +128,8 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "12.9.2" - enabled: true - # ── CUDA 13 ── + enabled: false + # ── CUDA 13 ── (disabled for testing) - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/amd64 @@ -137,7 +137,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "13.3.0" - enabled: true + enabled: false - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -145,7 +145,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "13.3.0" - enabled: true + enabled: false steps: - name: Skip when not enabled if: ${{ matrix.enabled != true }} From edcf810e1c1c21edf0d37f516573124b43dc1762 Mon Sep 17 00:00:00 2001 From: xashr Date: Mon, 13 Jul 2026 23:53:12 +0200 Subject: [PATCH 29/30] test error --- .github/workflows/docker.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0cda4711..310b8dbc 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -99,7 +99,7 @@ jobs: fail-fast: false matrix: include: - # ── CPU ── + # ── CPU ── (arm64 intentionally failing for testing) - tag: cpu dockerfile: .devops/cpu.Dockerfile platforms: linux/amd64 @@ -112,6 +112,7 @@ jobs: arch: arm64 runs_on: ubuntu-24.04-arm enabled: true + test_error: true # ── CUDA 12 ── (arm64 disabled for testing) - tag: cuda12 dockerfile: .devops/cuda.Dockerfile @@ -155,6 +156,10 @@ jobs: if: ${{ matrix.enabled == true }} uses: actions/checkout@v5 + - name: Inject test error + if: ${{ matrix.test_error == true }} + run: echo "::error::Simulated build failure for ${{ matrix.tag }}-${{ matrix.arch }}" && exit 1 + - name: Set up Docker Buildx if: ${{ matrix.enabled == true }} uses: docker/setup-buildx-action@v4 From 8ca7840f7280391333ad5debcf4444f849a10ac8 Mon Sep 17 00:00:00 2001 From: xashr Date: Tue, 14 Jul 2026 00:02:08 +0200 Subject: [PATCH 30/30] remove test code --- .github/workflows/docker.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 310b8dbc..c6c66e71 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -99,7 +99,7 @@ jobs: fail-fast: false matrix: include: - # ── CPU ── (arm64 intentionally failing for testing) + # ── CPU ── - tag: cpu dockerfile: .devops/cpu.Dockerfile platforms: linux/amd64 @@ -112,8 +112,7 @@ jobs: arch: arm64 runs_on: ubuntu-24.04-arm enabled: true - test_error: true - # ── CUDA 12 ── (arm64 disabled for testing) + # ── CUDA 12 ── - tag: cuda12 dockerfile: .devops/cuda.Dockerfile platforms: linux/amd64 @@ -129,8 +128,8 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "12.9.2" - enabled: false - # ── CUDA 13 ── (disabled for testing) + enabled: true + # ── CUDA 13 ── - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/amd64 @@ -138,7 +137,7 @@ jobs: runs_on: ubuntu-24.04 free_disk: true cuda_version: "13.3.0" - enabled: false + enabled: true - tag: cuda13 dockerfile: .devops/cuda.Dockerfile platforms: linux/arm64 @@ -146,7 +145,7 @@ jobs: runs_on: ubuntu-24.04-arm free_disk: true cuda_version: "13.3.0" - enabled: false + enabled: true steps: - name: Skip when not enabled if: ${{ matrix.enabled != true }} @@ -156,10 +155,6 @@ jobs: if: ${{ matrix.enabled == true }} uses: actions/checkout@v5 - - name: Inject test error - if: ${{ matrix.test_error == true }} - run: echo "::error::Simulated build failure for ${{ matrix.tag }}-${{ matrix.arch }}" && exit 1 - - name: Set up Docker Buildx if: ${{ matrix.enabled == true }} uses: docker/setup-buildx-action@v4