Drop the layer-caching work: no CACHE_MODE, no registry buildcache tag, no buildx container builder, no scheduled cache-busting build, no no_cache input. Instead build with --no-cache --pull every time. Caching was working against the point of this repo: nothing is version-pinned, so a cached `apk add` layer keeps shipping whatever packages existed when it was first built, and a rebuild quietly stops meaning "current". --no-cache alone isn't enough either — it would still build on a stale local copy of the FROM image. Verified the only CACHED entries left are the `# syntax=` frontend image and --pull re-resolving the base manifest (unchanged digest). The apk and yq layers re-run every build. Costs ~40s per image, which also makes the four-node cache-sharing question moot. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
130 lines
3.5 KiB
Bash
Executable File
130 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build, smoke-test and — in CI, on a publishing ref — push images.
|
|
#
|
|
# Usage: build-images.sh <image>...
|
|
#
|
|
# How an image gets tagged is a property of the git ref, not of the image, so one
|
|
# run treats every image it builds the same way:
|
|
#
|
|
# tag <image>/vX.Y.Z -> :vX.Y.Z :vX.Y :vX published release
|
|
# push to main -> :latest :main-<sha> latest tracks main
|
|
# pull request -> :pr-<n> built, never pushed
|
|
# anywhere else -> :dev built, never pushed (local default)
|
|
#
|
|
# `latest` has exactly one owner (main), so a release tag and a main build can never
|
|
# race to define it.
|
|
#
|
|
# Uses plain `docker build` rather than buildx with a container driver: it loads
|
|
# straight into the local image store so the smoke test can run before anything is
|
|
# published, and it produces a plain manifest with no attestations, which Gitea's
|
|
# registry rejects.
|
|
#
|
|
# Builds are always FRESH: --no-cache so every layer re-runs, and --pull so the FROM
|
|
# image is re-resolved against the registry and replaced if the tag has moved. This
|
|
# is the whole point of not pinning versions — a cached `apk add` layer would keep
|
|
# shipping whatever packages existed when it was first built, and --no-cache alone
|
|
# would still build on a stale local copy of the base image.
|
|
#
|
|
# Costs about 40s per image. Worth it to know that a rebuild means current.
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
REGISTRY=${REGISTRY:-gitea.libretechconsulting.com}
|
|
NAMESPACE=${NAMESPACE:-rmcguire}
|
|
|
|
[ $# -gt 0 ] || {
|
|
echo "usage: ${0##*/} <image>..." >&2
|
|
exit 2
|
|
}
|
|
|
|
sha=$(git rev-parse --short=7 HEAD)
|
|
revision=$(git rev-parse HEAD)
|
|
created=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
|
|
push=false
|
|
if [ "${GITHUB_REF_TYPE:-}" = tag ]; then
|
|
mode="release"
|
|
version=${GITHUB_REF_NAME##*/}
|
|
[[ $version =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
|
|
echo "tag '${GITHUB_REF_NAME}' is not of the form <image>/vX.Y.Z" >&2
|
|
exit 1
|
|
}
|
|
push=true
|
|
elif [ "${GITHUB_EVENT_NAME:-}" = pull_request ]; then
|
|
mode="pr"
|
|
version="pr-${PR_NUMBER:-0}"
|
|
elif [ "${GITHUB_REF_NAME:-}" = main ]; then
|
|
mode="main"
|
|
version="main-$sha"
|
|
push=true
|
|
else
|
|
mode="local"
|
|
version=dev
|
|
fi
|
|
|
|
tags_for() {
|
|
local repo="$REGISTRY/$NAMESPACE/$1" n
|
|
case $mode in
|
|
release)
|
|
n=${version#v}
|
|
printf '%s\n' "$repo:$version" "$repo:v${n%.*}" "$repo:v${n%%.*}"
|
|
;;
|
|
main) printf '%s\n' "$repo:latest" "$repo:$version" ;;
|
|
*) printf '%s\n' "$repo:$version" ;;
|
|
esac
|
|
}
|
|
|
|
# Collapsible sections in the Actions log; plain headers when run locally.
|
|
group() {
|
|
if [ -n "${GITHUB_ACTIONS:-}" ]; then
|
|
echo "::group::$*"
|
|
else
|
|
echo "==> $*"
|
|
fi
|
|
}
|
|
endgroup() {
|
|
if [ -n "${GITHUB_ACTIONS:-}" ]; then
|
|
echo "::endgroup::"
|
|
fi
|
|
}
|
|
|
|
echo "mode=$mode version=$version push=$push images=$*"
|
|
|
|
for image in "$@"; do
|
|
[ -f "images/$image/Dockerfile" ] || {
|
|
echo "no such image: images/$image/Dockerfile does not exist" >&2
|
|
exit 1
|
|
}
|
|
|
|
mapfile -t tags < <(tags_for "$image")
|
|
tag_args=()
|
|
for tag in "${tags[@]}"; do tag_args+=(--tag "$tag"); done
|
|
|
|
group "build $image"
|
|
docker build --no-cache --pull "${tag_args[@]}" \
|
|
--build-arg "VERSION=$version" \
|
|
--build-arg "REVISION=$revision" \
|
|
--build-arg "CREATED=$created" \
|
|
"images/$image"
|
|
endgroup
|
|
|
|
if [ -x "images/$image/test.sh" ]; then
|
|
group "test $image"
|
|
"images/$image/test.sh" "${tags[0]}"
|
|
endgroup
|
|
else
|
|
echo "note: $image has no test.sh, nothing to smoke-test"
|
|
fi
|
|
|
|
if [ "$push" = true ]; then
|
|
group "push $image"
|
|
for tag in "${tags[@]}"; do
|
|
echo "pushing $tag"
|
|
docker push "$tag"
|
|
done
|
|
endgroup
|
|
fi
|
|
done
|
|
|
|
echo "done: $* ($mode)"
|