mirror of
https://github.com/mudler/LocalAI.git
synced 2026-05-17 04:56:52 -04:00
ci: tag every backend digest, including singletons
backend_build.yml pushes by canonical digest only (push-by-digest=true, no tags applied at build time). User-facing tagging happens in backend_merge.yml's `imagetools create` step. Before this commit, scripts/changed-backends.js emitted a merge entry only for tag-suffixes with 2+ legs, so every single-arch backend (CUDA/ROCm/Intel Python images, vLLM, sglang, transformers, diffusers, ...) pushed its digest untagged and stayed that way until quay's GC reaped it. Symptom: tag releases shipped multi-arch backends tagged correctly, but no v<X>-gpu-nvidia-cuda-12-vllm (or any singleton variant) ever appeared in the registry. Changes: - scripts/changed-backends.js drops the `group.length < 2` skip and emits two merge matrices, one per arch class, so each downstream merge job can `needs:` only its corresponding build matrix. - backend.yml splits backend-merge-jobs into multiarch and singlearch variants. The split preserves PR #9746's fix: slow singlearch CUDA builds (~6h) must not gate multiarch merges, or quay's GC reaps the multiarch per-arch digests before they're tagged. - backend_pr.yml mirrors the split. - backend_build.yml renames the digest artifact from `digests<suffix>-<platform-tag>` to `digests<suffix>--<platform-tag-or-"single">`. The `--` separator prevents the merge-side glob from over-matching sibling backends whose tag-suffix is a prefix of ours (e.g. -cpu-vllm vs -cpu-vllm-omni, -cpu-mlx vs -cpu-mlx-audio); the `single` placeholder keeps the name well-formed when platform-tag is empty. - backend_merge.yml updates the download pattern to match. Verified locally: a tag-push event now expands to 36 multiarch merge entries (= 72 builds / 2 legs) and 199 singlearch merge entries (one per singleton, including -gpu-nvidia-cuda-12-vllm at index 24). Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
@@ -128,11 +128,15 @@ async function getChangedFilesForPush(event) {
|
||||
return res.data.files.map(f => f.filename);
|
||||
}
|
||||
|
||||
// Group filtered linux matrix entries by tag-suffix and emit a merge-matrix
|
||||
// entry for any tag-suffix that appears 2+ times. That's the trigger for
|
||||
// "this backend has multiple per-arch legs and we need a manifest list".
|
||||
// Singletons aren't merged — single-arch backends push by digest and don't
|
||||
// need a manifest list assembled across legs.
|
||||
// Group matrix entries by tag-suffix and emit a merge-matrix entry per group.
|
||||
// Both multi-leg groups (per-arch fan-out) and singletons get one entry each:
|
||||
// the build job pushes by digest only with no tags applied, so every backend
|
||||
// needs a downstream merge step to apply its tags via `imagetools create`,
|
||||
// regardless of how many per-arch legs feed it. Callers split entries by
|
||||
// arch class first (see splitByArch) and call this once per class so the
|
||||
// resulting matrices can be wired to merge jobs that `needs:` only their
|
||||
// corresponding build matrix — preventing slow single-arch builds from
|
||||
// gating multi-arch merges (the bug fixed in PR #9746).
|
||||
function computeMergeMatrix(entries) {
|
||||
const groups = new Map();
|
||||
for (const item of entries) {
|
||||
@@ -143,7 +147,6 @@ function computeMergeMatrix(entries) {
|
||||
}
|
||||
const include = [];
|
||||
for (const [tagSuffix, group] of groups) {
|
||||
if (group.length < 2) continue;
|
||||
// tag-latest must agree across legs — they're going to publish under
|
||||
// the same final tag, so disagreeing on whether it's also the :latest
|
||||
// tag is an authoring bug. Warn loudly so a Task 2.5 fan-out typo is
|
||||
@@ -177,17 +180,21 @@ function splitByArch(entries) {
|
||||
|
||||
function emitFullMatrix() {
|
||||
const { multiarch, singlearch } = splitByArch(includes);
|
||||
const mergeMatrix = computeMergeMatrix(includes);
|
||||
const hasMerges = mergeMatrix.include.length > 0 ? 'true' : 'false';
|
||||
const mergeMatrixMultiarch = computeMergeMatrix(multiarch);
|
||||
const mergeMatrixSinglearch = computeMergeMatrix(singlearch);
|
||||
const hasMergesMultiarch = mergeMatrixMultiarch.include.length > 0 ? 'true' : 'false';
|
||||
const hasMergesSinglearch = mergeMatrixSinglearch.include.length > 0 ? 'true' : 'false';
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `run-all=true\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-backends-singlearch=${singlearch.length > 0 ? 'true' : 'false'}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-backends-multiarch=${multiarch.length > 0 ? 'true' : 'false'}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-backends-darwin=true\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-merges=${hasMerges}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-merges-multiarch=${hasMergesMultiarch}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-merges-singlearch=${hasMergesSinglearch}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix-singlearch=${JSON.stringify({ include: singlearch })}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix-multiarch=${JSON.stringify({ include: multiarch })}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix-darwin=${JSON.stringify({ include: includesDarwin })}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge-matrix=${JSON.stringify(mergeMatrix)}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge-matrix-multiarch=${JSON.stringify(mergeMatrixMultiarch)}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge-matrix-singlearch=${JSON.stringify(mergeMatrixSinglearch)}\n`);
|
||||
for (const backend of allBackendPaths.keys()) {
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `${backend}=true\n`);
|
||||
}
|
||||
@@ -218,18 +225,22 @@ function emitFilteredMatrix(changedFiles) {
|
||||
console.log("Has multi-arch backends?:", hasBackendsMultiarch);
|
||||
console.log("Has Darwin backends?:", hasBackendsDarwin);
|
||||
|
||||
const mergeMatrix = computeMergeMatrix(filtered);
|
||||
const hasMerges = mergeMatrix.include.length > 0 ? 'true' : 'false';
|
||||
const mergeMatrixMultiarch = computeMergeMatrix(multiarch);
|
||||
const mergeMatrixSinglearch = computeMergeMatrix(singlearch);
|
||||
const hasMergesMultiarch = mergeMatrixMultiarch.include.length > 0 ? 'true' : 'false';
|
||||
const hasMergesSinglearch = mergeMatrixSinglearch.include.length > 0 ? 'true' : 'false';
|
||||
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `run-all=false\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-backends-singlearch=${hasBackendsSinglearch}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-backends-multiarch=${hasBackendsMultiarch}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-backends-darwin=${hasBackendsDarwin}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-merges=${hasMerges}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-merges-multiarch=${hasMergesMultiarch}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-merges-singlearch=${hasMergesSinglearch}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix-singlearch=${JSON.stringify({ include: singlearch })}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix-multiarch=${JSON.stringify({ include: multiarch })}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix-darwin=${JSON.stringify({ include: filteredDarwin })}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge-matrix=${JSON.stringify(mergeMatrix)}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge-matrix-multiarch=${JSON.stringify(mergeMatrixMultiarch)}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge-matrix-singlearch=${JSON.stringify(mergeMatrixSinglearch)}\n`);
|
||||
|
||||
// Per-backend boolean outputs
|
||||
for (const [backend, pathPrefix] of allBackendPaths) {
|
||||
|
||||
Reference in New Issue
Block a user