ci: build the image once instead of twice #7

Merged
lyrathorpe merged 1 commits from ci/one-build-not-two into main 2026-08-24 17:31:48 +01:00
+29 -19
View File
@@ -45,7 +45,8 @@ jobs:
# The suite runs inside the image, against the interpreter that ships,
# rather than against whatever the runner happens to provide. A failing
# test fails the build. Layers are shared with the push build below.
# test fails the build. The runtime stage below is built from the same
# daemon afterwards, so its layers are already in cache.
- name: Run the test suite inside the image
run: docker build --target test -t music-curator:test .
@@ -124,9 +125,6 @@ jobs:
echo "release=${release}" >> "$GITHUB_OUTPUT"
echo "Computed bump=${bump}, release=${release}, base=${base}"
- name: Set up Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
- name: Log in to the Gitea container registry
if: github.event_name != 'pull_request'
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
@@ -135,21 +133,33 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.PACKAGES_TOKEN }}
- name: Build and push
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
with:
context: .
# Without this the last stage in the Dockerfile -- the test stage --
# would be what gets published.
target: runtime
# The NAS is the only host this runs on. Building arm64 as well would
# mean emulating it under QEMU for no consumer.
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.version.outputs.tags }}
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
# Plain `docker build` rather than buildx. buildx boots its own buildkit
# in a container with a cache of its own, so it shared nothing with the
# test build above and rebuilt the image from the base image up -- two
# full builds per run. It earns that cost when building for several
# platforms; this only ever targets the amd64 NAS, so it does not.
#
# `--target runtime` is a strict prefix of the test stage, so every layer
# is already in the daemon's cache and this resolves in seconds.
- name: Build the runtime image
run: |
set -euo pipefail
tags=()
while IFS= read -r tag; do
[ -n "$tag" ] && tags+=(-t "$tag")
done <<< "${{ steps.version.outputs.tags }}"
docker build --target runtime \
--label "org.opencontainers.image.source=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" \
--label "org.opencontainers.image.revision=${GITHUB_SHA}" \
"${tags[@]}" .
- name: Push
if: github.event_name != 'pull_request'
run: |
set -euo pipefail
while IFS= read -r tag; do
[ -n "$tag" ] && docker push "$tag"
done <<< "${{ steps.version.outputs.tags }}"
# Record the release: write the computed version into pyproject.toml, then
# commit and tag it, so the packaging metadata always matches the release