Files
cozystack/.github/workflows/build-release.yaml
T
Myasnikov Daniil e226b85f86 fix(ci): overlay images from the PR base branch, and publish per-line artifacts
Supersedes the interim guard in this branch`s first commit, which skipped the
overlay entirely for release-line PRs. Skipping fixed the wrong images but left
those PRs testing their line`s last release: for any package the PR did not
rebuild, the committed ref is the released digest, so a component changed by an
earlier backport was exercised as its pre-backport binary until the next rc.

The overlay now reads `cozystack-packages:<base branch>` instead of always
`:main`, and build-release.yaml publishes that artifact for every maintained
`release-<major>.<minor>` branch the way build-main.yaml does for main: images
tagged with the branch, and the whole packages tree pushed with each reference
digest-pinned to what the run just built. Each base branch therefore has its own
generation to overlay from, which is what the original bug was really about —
#3437 failed install because main`s cozystack-controller served an aggregated
OpenAPI release-1.6`s charts could not validate against.

Three deliberate choices:

  * The trigger matches line branches only (`release-[0-9]+.[0-9]+`). The
    per-release and rc staging branches promote-rc.yaml and tags.yaml create
    (release-1.6.1, release-1.6.0-rc.4) must not trigger a full rebuild — their
    images come from the tag build, and rebuilding them would be waste.
  * WRITE_CACHE stays 0. CACHE_REGISTRY/<img>:buildcache is a single ref per
    image and build-main.yaml is deliberately its only, serialized writer so
    concurrent builds cannot race on the cache manifest (the 409 class #2711
    fixed for image tags). A line build can overlap a main build, so writing here
    would reintroduce that race. Line builds read the cache.
  * A missing artifact still degrades to committed refs, but on a release line it
    now emits a ::warning:: naming the branch. Silent degradation is
    indistinguishable from a working overlay, which is how a mis-specified branch
    filter would hide for a whole release cycle.

Cost: one `make build` per push to a maintained line, i.e. per merged backport.

hack/overlay-main-images_test.bats pins the artifact tag to the base branch,
rejects a hardcoded :main in either overlay step, and pins build-release.yaml`s
branch filter, image tag and WRITE_CACHE=0. Mutation-checked: restoring :main,
setting WRITE_CACHE=1, and broadening the filter to release-* each fail a test.
13/13 green; actionlint and zizmor clean.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit 2330d6f3ca)
2026-08-03 18:25:39 +05:00

117 lines
4.8 KiB
YAML

name: Build release line
# Publishes the per-line equivalent of what build-main.yaml publishes for main:
# every image tagged with the line's branch name, and the whole packages tree as
# the `cozystack-packages:<branch>` OCI artifact with each image reference
# digest-pinned to the images this run just pushed (`make build` ->
# packages/core/installer image-packages does the `flux push artifact`).
#
# Why it exists: pull-requests.yaml overlays image refs for every package a PR
# did NOT rebuild, so that e2e and the installer do not test last-release images
# for everything outside the PR's build matrix. That overlay had only
# `cozystack-packages:main` to read, which meant a release-line PR was handed
# MAIN's binaries to run against its own line's charts — a cross-generation mix
# that failed deterministically (see #3437: main's cozystack-controller served an
# aggregated OpenAPI release-1.6's charts could not validate against). With this
# artifact published per line, the overlay reads the PR's own base branch and the
# generations match.
#
# Cost: one full `make build` per push to a maintained line, i.e. per merged
# backport. That is the price of release-line PRs testing their line's tip rather
# than its last release.
env:
# Same per-CI registry as pull-requests.yaml and build-main.yaml.
REGISTRY: iad.ocir.io/idyksih5sir9/cozystack
on:
push:
# Maintained LINE branches only: `release-<major>.<minor>`. The `+` quantifies
# the preceding character class, and `.` is literal, so this matches
# release-1.6 but NOT the per-release staging branches promote-rc.yaml creates
# (release-1.6.1) nor rc staging branches (release-1.6.0-rc.4) — building
# those would be pure waste, since their images are built by tags.yaml.
branches: ['release-[0-9]+.[0-9]+']
paths-ignore:
- 'docs/**'
# Per line: a newer push to the same line supersedes an in-flight build, but
# different lines build independently.
concurrency:
group: build-release-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build-line:
name: Build ${{ github.ref_name }} images and packages artifact
runs-on: oracle-vm-24cpu-96gb-x86-64
timeout-minutes: 120
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
fetch-tags: true
# This workflow holds packages:write and an OCIR push token; it never
# pushes git, so don't leave the checkout's GITHUB_TOKEN in .git/config
# where a later build step could read it.
persist-credentials: false
# Ephemeral runners lack the flux CLI the installer's image-packages step
# shells out to; install if absent (idempotent).
- name: Set up build toolchain
run: |
command -v flux >/dev/null \
|| curl -fsSL https://fluxcd.io/install.sh | sudo bash
- name: Set up Docker config
run: |
if [ -d ~/.docker ]; then
cp -r ~/.docker "${{ runner.temp }}/.docker"
fi
- name: Login to OCIR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
username: ${{ secrets.OCIR_USER }}
password: ${{ secrets.OCIR_TOKEN }}
registry: iad.ocir.io
env:
DOCKER_CONFIG: ${{ runner.temp }}/.docker
# Same isolated buildkit as build-main.yaml, so a line build never contends
# with PR builds on the shared embedded builder.
- name: Set up Buildx (docker-container driver)
id: buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
with:
driver: docker-container
env:
DOCKER_CONFIG: ${{ runner.temp }}/.docker
- name: Build line images and publish the packages artifact
run: make build
env:
DOCKER_CONFIG: ${{ runner.temp }}/.docker
BUILDER: ${{ steps.buildx.outputs.name }}
# READ the shared mode=max cache, never write it. CACHE_REGISTRY/<img>:
# buildcache is a single ref per image and build-main.yaml is
# deliberately its only writer, serialized, precisely so concurrent
# builds cannot race on the cache manifest (the 409 collision class
# #2711 fixed for image tags). A line build can overlap a main build, so
# writing here would reintroduce exactly that race.
WRITE_CACHE: '0'
# Floating per-line handle: images and the packages artifact both land
# under the branch name (e.g. :release-1.6). Versioned and :latest tags
# belong to releases (tags.yaml / finalize), never to this workflow.
IMAGE_TAG: ${{ github.ref_name }}
PUBLISH_VERSIONED: '0'
PUBLISH_FLOATING: '0'