Skip to content

Commit 42a8db3

Browse files
localai-botmudler
andauthored
ci(image): publish missing :latest-* and :v<X>-* singleton image tags (#9812)
* ci(image): wire singleton merges + `--` artifact separator Closes the same singletons gap on the LocalAI server image workflow that PR #9781 closed for backends. The user observed it as missing :latest-gpu-nvidia-cuda-12 etc. on quay.io/go-skynet/local-ai — the build matrix has six single-arch entries with no corresponding merge step, so their per-arch digests push (push-by-digest=true) and never get tagged: - -gpu-hipblas (hipblas-jobs) - -gpu-nvidia-cuda-12 (core-image-build) - -gpu-nvidia-cuda-13 (core-image-build) - -gpu-intel (core-image-build) - -nvidia-l4t-arm64 (gh-runner) - -nvidia-l4t-arm64-cuda-13 (gh-runner) Only :latest, :v<X>, :latest-gpu-vulkan and :v<X>-gpu-vulkan were actually being published before this commit (the two multiarch suffixes that had merge jobs). Changes: 1. image.yml: add six new merge jobs, one per single-arch entry. Each `needs:` only its parent build job (matching the existing pattern for core-image-merge / gpu-vulkan-image-merge). 2. image_build.yml: switch artifact name to `digests-localai<suffix>--<platform-tag-or-"single">`. The `--` separator anchors the merge-side glob so a singleton tag-suffix doesn't over-match a longer suffix that shares its prefix (-nvidia-l4t-arm64 vs -nvidia-l4t-arm64-cuda-13). Same convention as backend_build.yml's fix. 3. image_merge.yml: update the download pattern to match. Next master push or tag release should produce :latest-gpu-hipblas, :latest-gpu-nvidia-cuda-12, :latest-gpu-nvidia-cuda-13, :latest-gpu-intel, :latest-nvidia-l4t-arm64, :latest-nvidia-l4t-arm64-cuda-13 (and their :v<X>-* equivalents) for the first time on the post-#9781 workflow. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * ci(image): add !cancelled() guard to all 8 image merge jobs Parity pass with backend.yml's merge jobs (8521af1). Without !cancelled(), GHA's default `needs:` cascade skips the merge when ANY matrix cell of the parent build job fails or is cancelled — so a single flaky leg would suppress publication of every other tag-suffix's manifest list. Same fix the backend got after v4.2.1 showed 2 failed singlearch builds cascade-skip 199 singlearch merge entries. Applied to all 8 image merges: - core-image-merge - gpu-vulkan-image-merge - gpu-nvidia-cuda-12-image-merge (added in e5300f1) - gpu-nvidia-cuda-13-image-merge (added in e5300f1) - gpu-intel-image-merge (added in e5300f1) - gpu-hipblas-image-merge (added in e5300f1) - nvidia-l4t-arm64-image-merge (added in e5300f1) - nvidia-l4t-arm64-cuda-13-image-merge (added in e5300f1) Build jobs (hipblas-jobs, core-image-build, gh-runner) are intentionally NOT changed — they have no upstream `needs:` to cascade- skip from. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
1 parent 0353d3b commit 42a8db3

3 files changed

Lines changed: 100 additions & 5 deletions

File tree

.github/workflows/image.yml

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@
151151
ubuntu-codename: 'noble'
152152

153153
core-image-merge:
154-
if: github.repository == 'mudler/LocalAI'
154+
# !cancelled(): without it, GHA's default `needs:` cascade skips the
155+
# merge whenever any matrix cell of the parent build fails or is
156+
# cancelled. Same fix as backend.yml's merge jobs — we still want to
157+
# publish the manifest list for tag-suffixes whose legs all succeeded.
158+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
155159
needs: core-image-build
156160
uses: ./.github/workflows/image_merge.yml
157161
with:
@@ -164,7 +168,7 @@
164168
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
165169

166170
gpu-vulkan-image-merge:
167-
if: github.repository == 'mudler/LocalAI'
171+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
168172
needs: core-image-build
169173
uses: ./.github/workflows/image_merge.yml
170174
with:
@@ -175,7 +179,91 @@
175179
dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }}
176180
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
177181
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
178-
182+
183+
# Single-arch server-image merges. Same conceptual fix as the backend
184+
# singletons in PR #9781: image_build.yml pushes by canonical digest
185+
# only, so without a downstream merge step there's no tag for consumers
186+
# (no :latest-gpu-nvidia-cuda-12, no :v<X>-gpu-nvidia-cuda-12, etc.).
187+
# Each merge job needs only its parent build matrix and is filtered by
188+
# tag-suffix in image_merge.yml's artifact-download pattern.
189+
gpu-nvidia-cuda-12-image-merge:
190+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
191+
needs: core-image-build
192+
uses: ./.github/workflows/image_merge.yml
193+
with:
194+
tag-latest: 'auto'
195+
tag-suffix: '-gpu-nvidia-cuda-12'
196+
secrets:
197+
dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }}
198+
dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }}
199+
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
200+
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
201+
202+
gpu-nvidia-cuda-13-image-merge:
203+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
204+
needs: core-image-build
205+
uses: ./.github/workflows/image_merge.yml
206+
with:
207+
tag-latest: 'auto'
208+
tag-suffix: '-gpu-nvidia-cuda-13'
209+
secrets:
210+
dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }}
211+
dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }}
212+
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
213+
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
214+
215+
gpu-intel-image-merge:
216+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
217+
needs: core-image-build
218+
uses: ./.github/workflows/image_merge.yml
219+
with:
220+
tag-latest: 'auto'
221+
tag-suffix: '-gpu-intel'
222+
secrets:
223+
dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }}
224+
dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }}
225+
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
226+
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
227+
228+
gpu-hipblas-image-merge:
229+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
230+
needs: hipblas-jobs
231+
uses: ./.github/workflows/image_merge.yml
232+
with:
233+
tag-latest: 'auto'
234+
tag-suffix: '-gpu-hipblas'
235+
secrets:
236+
dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }}
237+
dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }}
238+
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
239+
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
240+
241+
nvidia-l4t-arm64-image-merge:
242+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
243+
needs: gh-runner
244+
uses: ./.github/workflows/image_merge.yml
245+
with:
246+
tag-latest: 'auto'
247+
tag-suffix: '-nvidia-l4t-arm64'
248+
secrets:
249+
dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }}
250+
dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }}
251+
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
252+
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
253+
254+
nvidia-l4t-arm64-cuda-13-image-merge:
255+
if: ${{ !cancelled() && github.repository == 'mudler/LocalAI' }}
256+
needs: gh-runner
257+
uses: ./.github/workflows/image_merge.yml
258+
with:
259+
tag-latest: 'auto'
260+
tag-suffix: '-nvidia-l4t-arm64-cuda-13'
261+
secrets:
262+
dockerUsername: ${{ secrets.DOCKERHUB_USERNAME }}
263+
dockerPassword: ${{ secrets.DOCKERHUB_PASSWORD }}
264+
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
265+
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
266+
179267
gh-runner:
180268
if: github.repository == 'mudler/LocalAI'
181269
uses: ./.github/workflows/image_build.yml

.github/workflows/image_build.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ jobs:
202202
if: github.event_name != 'pull_request'
203203
uses: actions/upload-artifact@v7
204204
with:
205-
name: digests-localai${{ inputs.tag-suffix == '' && '-core' || inputs.tag-suffix }}-${{ inputs.platform-tag }}
205+
# `--` separator + 'single' placeholder for empty platform-tag —
206+
# same pattern as backend_build.yml. Prevents prefix collisions
207+
# in the merge-side glob (e.g. -nvidia-l4t-arm64 is a prefix of
208+
# -nvidia-l4t-arm64-cuda-13).
209+
name: digests-localai${{ inputs.tag-suffix == '' && '-core' || inputs.tag-suffix }}--${{ inputs.platform-tag || 'single' }}
206210
path: /tmp/digests/*
207211
if-no-files-found: error
208212
retention-days: 1

.github/workflows/image_merge.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ jobs:
4545
- name: Download digests
4646
uses: actions/download-artifact@v8
4747
with:
48-
pattern: digests-localai${{ inputs.tag-suffix == '' && '-core' || inputs.tag-suffix }}-*
48+
# `--` separator anchors the glob so we don't over-match sibling
49+
# tag-suffixes (e.g. -nvidia-l4t-arm64 vs -nvidia-l4t-arm64-cuda-13).
50+
# Must stay in sync with image_build.yml's upload-artifact name.
51+
pattern: digests-localai${{ inputs.tag-suffix == '' && '-core' || inputs.tag-suffix }}--*
4952
merge-multiple: true
5053
path: /tmp/digests
5154

0 commit comments

Comments
 (0)