yams/scripts/local-ci/package-lane.sh

107 lines
4.1 KiB
Bash
Executable file

#!/usr/bin/env bash
# yams/scripts/local-ci/package-lane.sh
#
# One-command local lane: build the Linux packages in a cached Docker builder,
# then install + smoke-test them in clean systemd containers. This is the local
# equivalent of the release CI package job.
#
# build : run scripts/build-deb.sh inside docker/local-ci/debian-package.Dockerfile
# -> produces yams-*.deb and yams-*.rpm into the build dir
# validate: run scripts/local-ci/package-validate.sh against those artifacts
#
# Requirements on host:
# - Docker on PATH, on a Linux host (or Docker Desktop's Linux VM).
# - The validate phase needs privileged systemd-in-docker (cgroups). On macOS
# Docker Desktop the build phase works; the validate phase may not boot
# systemd -- use --build-only there and run validate on a Linux runner.
#
# Examples:
# bash scripts/local-ci/package-lane.sh # build + validate (deb + rpm)
# bash scripts/local-ci/package-lane.sh --only deb # deb lane only
# bash scripts/local-ci/package-lane.sh --build-only # just produce packages
# bash scripts/local-ci/package-lane.sh --validate-only # reuse existing packages
# bash scripts/local-ci/package-lane.sh --no-cache # rebuild the builder image
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
IMAGE="yams/ci-debian-package:trixie"
DOCKERFILE="${REPO_ROOT}/docker/local-ci/debian-package.Dockerfile"
BUILD_DIR="build/release-pkg" # relative to repo root; kept separate from dev build/
ONLY="all"
DO_BUILD=1
DO_VALIDATE=1
NO_CACHE=0
VERSION=""
log() { printf '\033[1;34m[lane]\033[0m %s\n' "$*"; }
fail() { printf '\033[1;31m[fail]\033[0m %s\n' "$*" >&2; }
usage() { sed -n '2,30p' "${BASH_SOURCE[0]}"; }
while [ "$#" -gt 0 ]; do
case "$1" in
--only) ONLY="$2"; shift 2 ;;
--build-dir) BUILD_DIR="$2"; shift 2 ;;
--version) VERSION="$2"; shift 2 ;;
--build-only) DO_VALIDATE=0; shift ;;
--validate-only) DO_BUILD=0; shift ;;
--no-cache) NO_CACHE=1; shift ;;
-h|--help) usage; exit 0 ;;
*) fail "unknown argument: $1"; usage; exit 2 ;;
esac
done
command -v docker >/dev/null 2>&1 || { fail "docker not found on PATH"; exit 2; }
# Resolve a version for the build (build-deb.sh packages only for tag/channel
# builds, so the build phase passes RELEASE_CHANNEL=nightly to force packaging).
if [ -z "${VERSION}" ]; then
VERSION="$(git -C "${REPO_ROOT}" describe --tags --abbrev=7 2>/dev/null || echo 0.0.0-dev)"
fi
ABS_BUILD_DIR="${BUILD_DIR}"
case "${ABS_BUILD_DIR}" in
/*) : ;;
*) ABS_BUILD_DIR="${REPO_ROOT}/${BUILD_DIR}" ;;
esac
if [ "${DO_BUILD}" -eq 1 ]; then
log "building cached builder image ${IMAGE}"
build_args=(-f "${DOCKERFILE}" -t "${IMAGE}" "${REPO_ROOT}")
[ "${NO_CACHE}" -eq 1 ] && build_args+=(--no-cache)
docker build "${build_args[@]}"
log "building packages (version=${VERSION}) into ${BUILD_DIR}"
mkdir -p "${ABS_BUILD_DIR}"
# Run the real build inside the container; chown artifacts back to the host
# user so the build dir isn't left root-owned on the bind mount.
# Persist the Conan cache across runs so dependencies aren't rebuilt from
# source every time (the container itself is --rm). BASE_VERSION is left unset
# so build-deb.sh derives a digit-leading version (dpkg requires that).
docker run --rm \
-v "${REPO_ROOT}:/workspace/yams" \
-v yams-conan-cache:/root/.conan2 \
-w /workspace \
-e RELEASE_CHANNEL=nightly \
-e GIT_REF="" \
-e BUILD_DIR="${BUILD_DIR}" \
-e MESON_EXTRA_ARGS="${MESON_EXTRA_ARGS:-}" \
-e CONAN_EXTRA_OPTS="${CONAN_EXTRA_OPTS:-}" \
-e HOST_UID="$(id -u)" \
-e HOST_GID="$(id -g)" \
"${IMAGE}" \
bash -lc '/workspace/yams/scripts/build-deb.sh; rc=$?; chown -R "${HOST_UID}:${HOST_GID}" "/workspace/yams/'"${BUILD_DIR}"'" 2>/dev/null || true; exit $rc'
log "built artifacts:"
find "${ABS_BUILD_DIR}" -maxdepth 1 -type f \( -name 'yams-*.deb' -o -name 'yams-*.rpm' \) -print
fi
if [ "${DO_VALIDATE}" -eq 1 ]; then
log "validating packages from ${BUILD_DIR}"
bash "${SCRIPT_DIR}/package-validate.sh" --build-dir "${ABS_BUILD_DIR}" --only "${ONLY}"
fi
log "done"