Merge branch 'feature/ci-images' into feature/opencv5
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
#!/bin/bash
|
||||
# build_builder_image.sh — build and publish the DP-007 CI builder image to the
|
||||
# Gitea container registry.
|
||||
#
|
||||
# TRACES: DP-007 | PR-004
|
||||
#
|
||||
# Usage:
|
||||
# scripts/ci/build_builder_image.sh # build only, tag v1
|
||||
# scripts/ci/build_builder_image.sh --push # build and push
|
||||
# scripts/ci/build_builder_image.sh --tag v2 --push # bump the pinned tag
|
||||
# scripts/ci/build_builder_image.sh --no-cache # force a clean rebuild
|
||||
#
|
||||
# The tag is the contract with CI. .gitea/workflows/unit-tests.yml names an
|
||||
# explicit tag in its `container:` block and never `latest`, so that rebuilding
|
||||
# the image cannot silently change what a previous green build meant. Bumping
|
||||
# the dependency set means bumping the tag AND editing the workflow — the two
|
||||
# edits landing in the same commit is the point, not an inconvenience.
|
||||
#
|
||||
# Registry auth: this script does not log in. Do it once, out of band:
|
||||
# docker login gitea.tourolle.paris
|
||||
# The CI host is already authenticated this way (its cached credentials in
|
||||
# ~/.docker/config.json are what the kpnpp-builder push relies on), so a
|
||||
# workflow that calls this script needs no secret plumbing.
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
|
||||
REGISTRY="gitea.tourolle.paris"
|
||||
OWNER="dtourolle"
|
||||
IMAGE="sae-builder-cpu"
|
||||
DOCKERFILE="Dockerfile.builder-cpu"
|
||||
|
||||
# The tag CI pins to today. Keep this in step with the `container.image` line in
|
||||
# .gitea/workflows/unit-tests.yml; the workflow asserts at run time that the
|
||||
# image it landed in reports this same version, so a drift shows up as a failed
|
||||
# job rather than as a build against the wrong toolchain.
|
||||
TAG="v1"
|
||||
|
||||
PUSH=0
|
||||
EXTRA_ARGS=()
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--push) PUSH=1 ;;
|
||||
--tag) TAG="${2:?--tag needs a value}"; shift ;;
|
||||
--no-cache) EXTRA_ARGS+=(--no-cache) ;;
|
||||
-h|--help) sed -n '2,30p' "${BASH_SOURCE[0]}"; exit 0 ;;
|
||||
*) echo "error: unknown argument '$1'" >&2; exit 2 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$TAG" = "latest" ]; then
|
||||
echo "error: refusing to build the tag 'latest'." >&2
|
||||
echo "DP-007 requires CI to pin an immutable tag. A moving 'latest' means a" >&2
|
||||
echo "rebuild retroactively changes what every earlier green build proved." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
REF="${REGISTRY}/${OWNER}/${IMAGE}:${TAG}"
|
||||
# A second tag carrying the commit that produced the image. The workflow pins
|
||||
# the human-readable tag; this one is the audit trail — given any image you can
|
||||
# recover the Dockerfile that built it.
|
||||
SHA="$(git -C "$REPO_ROOT" rev-parse --short HEAD)"
|
||||
REF_SHA="${REGISTRY}/${OWNER}/${IMAGE}:${TAG}-${SHA}"
|
||||
|
||||
# The Dockerfile COPYs nothing from the repository on purpose (see its closing
|
||||
# comment), so the build context is an empty directory rather than the repo
|
||||
# root. Sending ~1 GB of models, fixtures and experiment data to the daemon for
|
||||
# a build that reads none of it is pure latency.
|
||||
CONTEXT="$(mktemp -d)"
|
||||
trap 'rm -rf "$CONTEXT"' EXIT
|
||||
|
||||
echo "=== building ${REF}"
|
||||
echo " dockerfile: ${REPO_ROOT}/${DOCKERFILE}"
|
||||
echo " context: (empty — the image embeds no repository content)"
|
||||
echo
|
||||
echo " Expect this to take a while: OpenCV 5 is compiled from source because"
|
||||
echo " no Debian release ships it. That cost is paid once per image, which is"
|
||||
echo " the entire reason DP-007 asks for a prebuilt image instead of"
|
||||
echo " installing dependencies inside each CI run."
|
||||
echo
|
||||
|
||||
docker build \
|
||||
"${EXTRA_ARGS[@]}" \
|
||||
--build-arg "IMAGE_TAG=${TAG}" \
|
||||
-f "${REPO_ROOT}/${DOCKERFILE}" \
|
||||
-t "${REF}" \
|
||||
-t "${REF_SHA}" \
|
||||
"${CONTEXT}"
|
||||
|
||||
echo
|
||||
echo "=== built"
|
||||
docker image inspect "${REF}" --format ' {{.RepoTags}} {{.Size}} bytes'
|
||||
docker run --rm "${REF}" sh -c 'echo " SAE_BUILDER=$SAE_BUILDER version=$SAE_BUILDER_VERSION ort=$SAE_ORT_VERSION opencv=$SAE_OPENCV_VERSION"'
|
||||
|
||||
if [ "$PUSH" -eq 0 ]; then
|
||||
echo
|
||||
echo "Not pushed. Re-run with --push, or push by hand:"
|
||||
echo " docker push ${REF}"
|
||||
echo " docker push ${REF_SHA}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== pushing"
|
||||
# No `latest` tag is pushed, by design. Publishing one invites a workflow to use
|
||||
# it, and DP-007 exists to prevent exactly that.
|
||||
docker push "${REF}"
|
||||
docker push "${REF_SHA}"
|
||||
|
||||
echo
|
||||
echo "=== published ${REF}"
|
||||
echo "If this was a dependency-set change, bump the tag in"
|
||||
echo " .gitea/workflows/unit-tests.yml (container.image)"
|
||||
echo " scripts/ci/build_builder_image.sh (TAG, above)"
|
||||
echo "in the same commit, so no run can build against an image the repository"
|
||||
echo "does not describe."
|
||||
Reference in New Issue
Block a user