From 29670dbd41a251a247f661a8f6c109348d81e2f3 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Tue, 3 Nov 2026 23:04:16 +0000 Subject: [PATCH] ci: stop queuing add-on runs on every master push addons-tests.yml now cancels an older run on master, as the other test workflows do. addons-package.yml puts all master pushes in one group without cancelling: a running publish finishes, and a newer queued run replaces an older queued one. Tag, release and PR runs keep separate groups. Document both in the workflow headers and .agents/ci-caching.md. Assisted-by: Claude:claude-sonnet-5-5 python3 --- .agents/ci-caching.md | 16 ++++++++++++++++ .github/workflows/addons-package.yml | 12 +++++++++++- .github/workflows/addons-tests.yml | 10 ++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/.agents/ci-caching.md b/.agents/ci-caching.md index dc497201fd..7ce1440255 100644 --- a/.agents/ci-caching.md +++ b/.agents/ci-caching.md @@ -303,6 +303,22 @@ concurrency: - Tag pushes group by their own tag ref, and schedule and `workflow_dispatch` runs group by SHA, so a master push never cancels them. - The cost: the run of an older commit shows as cancelled, so a failure that the newer commit also contains is reported by the newer run, not the older one. +### Add-on workflows + +`addons-tests.yml` uses the test-workflow group above, so a newer push to master cancels the older run. + +`addons-package.yml` builds and publishes every add-on from the whole tree on each run (no diff base), and the development alias moves only in its promote job. Only the newest master commit matters, but a running publish must not be cancelled half-way. It uses: + +```yaml +concurrency: + group: ci-addons-package-${{ github.event.pull_request.number || (github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master') || github.sha }}-${{ github.repository }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} +``` + +- Every push to master shares one group and never cancels a running one. GitHub keeps one pending run per group, so a newer queued run replaces an older queued one. The queue is at most one running and one pending run. +- Tag pushes and `release` events group by SHA, and PRs by number, so they never join the master group. +- The publish and promote jobs have their own job-level groups with `cancel-in-progress: false`, which stay as they are. + ### Image workflows are deliberately not cancelled `image.yml` and `backend.yml` keep the per-SHA group. Both decide what to build from the diff of one push (`event.before` to `sha`): the `changes` job in `image.yml`, `scripts/changed-backends.js` in `backend.yml`. If a queued run were replaced by a newer one, the newer run would only see its own diff. A code commit followed by a gallery-only commit would then build nothing. Do not add a pending-replacement group to them until the diff base is the last commit that was actually built. diff --git a/.github/workflows/addons-package.yml b/.github/workflows/addons-package.yml index d5f1cccd35..de74c2e450 100644 --- a/.github/workflows/addons-package.yml +++ b/.github/workflows/addons-package.yml @@ -39,6 +39,16 @@ name: 'add-on packages' # LocalAI reads that file (core/services/addons/catalog/official.go), so it # installs the packages its own release built, not the moving development ones. # +# Concurrency. Every run builds and publishes all add-ons from the whole tree, +# and the development alias moves only in the promote job, so only the newest +# master commit matters for the development channel. All pushes to master share +# one group with cancel-in-progress off: a running publish is never cancelled +# half-way through pushing images or moving an alias, and a newer queued run +# replaces an older queued one (GitHub keeps one pending run per group). A pull +# request groups by its number and cancels its own older runs. A tag push and a +# release event group by SHA, so they never share the master group and are never +# replaced. +# # Sandbox guest image. The sandbox-image job (sandbox-images.yml) builds and # signs the guest image and exposes its reference by digest as the output # "image" (@sha256:). The package job passes it to the @@ -91,7 +101,7 @@ on: types: [published] concurrency: - group: ci-addons-package-${{ github.event.pull_request.number || github.sha }}-${{ github.repository }} + group: ci-addons-package-${{ github.event.pull_request.number || (github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master') || github.sha }}-${{ github.repository }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} permissions: diff --git a/.github/workflows/addons-tests.yml b/.github/workflows/addons-tests.yml index 1daf0e103c..92f917dc87 100644 --- a/.github/workflows/addons-tests.yml +++ b/.github/workflows/addons-tests.yml @@ -11,6 +11,12 @@ name: 'Add-on Tests' # main test workflow (make test, make test-coverage-check). The packaging suite # runs in addons-package.yml. The UI unit tests of every add-on run in # tests-ui-unit.yml. +# +# Concurrency. A newer push to master cancels the older in-flight run of this +# workflow, as in the other test workflows: tests are cumulative, so only the +# newest commit is worth testing. A pull request groups by its number and +# cancels its own older runs. Tag pushes group by their own ref, and schedule +# and dispatch runs group by SHA, so a master push never cancels them. on: pull_request: paths: @@ -61,8 +67,8 @@ on: - '.github/actions/**' concurrency: - group: ci-addons-tests-${{ github.event.pull_request.number || github.sha }}-${{ github.repository }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} + group: ci-addons-tests-${{ github.event.pull_request.number || (github.event_name == 'push' && github.ref) || github.sha }}-${{ github.repository }} + cancel-in-progress: ${{ github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/master') }} permissions: contents: read