#!/usr/bin/env bash # Build, smoke-test and — in CI, on a publishing ref — push images. # # Usage: build-images.sh ... # # 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 /vX.Y.Z -> :vX.Y.Z :vX.Y :vX published release # push to main -> :latest :main- latest tracks main # pull request -> :pr- 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. set -euo pipefail cd "$(dirname "$0")/.." REGISTRY=${REGISTRY:-gitea.libretechconsulting.com} NAMESPACE=${NAMESPACE:-rmcguire} [ $# -gt 0 ] || { echo "usage: ${0##*/} ..." >&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 /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 "${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)"