Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/build-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,19 @@ on: # yamllint disable-line rule:truthy
- ".claude/**"
- ".github/workflows/cleanup-old-images.yml"
workflow_call:
inputs:
changed_only:
description: >-
Build only variants whose upstream base digest changed.
type: boolean
default: false
workflow_dispatch:
inputs:
changed_only:
description: >-
Build only variants whose upstream base digest changed.
type: boolean
default: false
permissions:
contents: write
packages: write
Expand All @@ -33,3 +45,4 @@ jobs:
image_flavor: ["Bazzite"]
with:
image_flavor: ${{ matrix.image_flavor }}
changed_only: ${{ inputs.changed_only || false }}
25 changes: 24 additions & 1 deletion .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ on: # yamllint disable-line rule:truthy
inputs:
image_flavor:
type: string
changed_only:
description: >-
Select only variants whose upstream base digest changed.
Scheduled runs always do this regardless of this input.
type: boolean
default: false
concurrency:
group: >-
${{ github.workflow }}-${{ github.ref
Expand Down Expand Up @@ -52,7 +58,8 @@ jobs:
GITHUB_ACTOR: ${{ github.actor }}
GITHUB_TOKEN: ${{ github.token }}
run: |
if [[ "${{ github.event_name }}" == "schedule" ]]; then
if [[ "${{ inputs.changed_only }}" == "true" \
|| "${{ github.event_name }}" == "schedule" ]]; then
changed_only=true
else
changed_only=false
Expand All @@ -74,11 +81,27 @@ jobs:
echo "images=$images" >> "$GITHUB_OUTPUT"
echo "manifest_images=$manifest_images" >> "$GITHUB_OUTPUT"
echo "publish=$publish" >> "$GITHUB_OUTPUT"

# An empty matrix is a normal outcome on scheduled runs; say so on
# the run page rather than only in this job's log.
{
echo "## ${{ inputs.image_flavor }} build matrix"
echo
if [[ "$images" == "[]" ]]; then
echo "No variants need rebuilding: every published image"
echo "already records the current upstream base digest."
else
jq -r '.[] | "- `\(.image)` (\(.arch))"' <<<"$images"
fi
} >> "$GITHUB_STEP_SUMMARY"
build-image:
name: >-
Build ${{ inputs.image_flavor }} Images
(${{ matrix.combo.image }}/${{ matrix.combo.arch }})
needs: get-images
# GitHub fails the entire run -- with no failing job and no annotation --
# when a strategy matrix expression evaluates to []. Skip the job instead.
if: ${{ needs.get-images.outputs.images != '[]' }}
runs-on: ${{ matrix.combo.runner }}
continue-on-error: false
permissions:
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/build-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,19 @@ on: # yamllint disable-line rule:truthy
- ".claude/**"
- ".github/workflows/cleanup-old-images.yml"
workflow_call:
inputs:
changed_only:
description: >-
Build only variants whose upstream base digest changed.
type: boolean
default: false
workflow_dispatch:
inputs:
changed_only:
description: >-
Build only variants whose upstream base digest changed.
type: boolean
default: false
permissions:
contents: write
packages: write
Expand All @@ -33,3 +45,4 @@ jobs:
image_flavor: ["Server"]
with:
image_flavor: ${{ matrix.image_flavor }}
changed_only: ${{ inputs.changed_only || false }}
22 changes: 21 additions & 1 deletion docs/design/build-scheduling.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,13 @@ never triggers a build either, regardless of what files changed.
- The matrix job emits `images` (flat list of `{image, arch, runner,
base_digest}`) and `manifest_images` (grouped by image, for the later
multi-arch manifest step), plus `publish` (`true` except on `pull_request`).
It also writes the selection to `$GITHUB_STEP_SUMMARY` — the chosen
image/arch pairs, or "No variants need rebuilding" — so a no-op run
explains itself on the run page.

**`build-image` job** runs `just build <image> <base_digest>` per matrix
**`build-image` job** is guarded by
`if: needs.get-images.outputs.images != '[]'`, then runs
`just build <image> <base_digest>` per matrix
entry, pinning the build to the exact digest the matrix already resolved
(not re-resolving the tag, which could have moved). It labels the built image
with `org.opencontainers.image.base.digest=<base_digest>` and a "Verify
Expand All @@ -91,6 +96,21 @@ resolved version tag, and signs both with Cosign.
- Pushes to `main` always publish every enabled variant that built,
regardless of digest state — publishing is driven by the git event, not by
whether a rebuild was "needed."
- An empty matrix is the normal steady state for a scheduled run once every
variant is current, and it is why `build-image` carries
`if: needs.get-images.outputs.images != '[]'`. Without that guard GitHub
fails the *entire run* when a `strategy.matrix` expression evaluates to
`[]` ("Matrix vector 'combo' does not contain any values") — the job is
never created, so nothing shows as failed, there is no annotation, and
`gh run view --log-failed` is empty. Do not remove the guard.
`create-manifest` (`manifest_images != '[]'`) and `check`'s "Exit on
failure" step already tolerate the same empty-matrix case.
- `build-desktop.yml` and `build-server.yml` accept a `changed_only` boolean
on `workflow_dispatch`, which forces the scheduled-run selection path
(including the empty matrix) on demand:
`gh workflow run build-desktop.yml -f changed_only=true`. Scheduled runs
select changed-only regardless of the input; every other trigger defaults
to `false`.
- To debug why a variant was or wasn't selected on a scheduled run, check the
"Get Images for Build" job's log output from `just generate-ci-matrix`
(`stderr` prints `Skipping <tag>; <base>:<tag> is unchanged` for skipped
Expand Down
Loading