ci/docker: unify image build logic and run virgin tests across all distros
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled

Refactor Dockerfile into multi-stage virgin/full targets and introduce a single
flag-based image build script. Standardize image naming, remove redundant build
scripts, and update Makefile targets accordingly. CI workflows now build missing
virgin images and run root and user tests consistently across all supported
distributions.

https://chatgpt.com/share/693c29d9-9b28-800f-a549-5661c783d968
This commit is contained in:
Kevin Veen-Birkenbach
2025-12-12 16:40:21 +01:00
parent 08ab9fb142
commit 0dfbaa0f6b
16 changed files with 200 additions and 124 deletions

View File

@@ -7,6 +7,10 @@ jobs:
test-virgin-root: test-virgin-root:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 45 timeout-minutes: 45
strategy:
fail-fast: false
matrix:
distro: [arch, debian, ubuntu, fedora, centos]
steps: steps:
- name: Checkout repository - name: Checkout repository
@@ -15,7 +19,14 @@ jobs:
- name: Show Docker version - name: Show Docker version
run: docker version run: docker version
- name: Virgin Arch pkgmgr flake test (root) # 🔹 BUILD virgin image if missing
- name: Build virgin container (${{ matrix.distro }})
run: |
set -euo pipefail
distro="${{ matrix.distro }}" make build-missing
# 🔹 RUN test inside virgin image
- name: Virgin ${{ matrix.distro }} pkgmgr test (root)
run: | run: |
set -euo pipefail set -euo pipefail
@@ -24,13 +35,10 @@ jobs:
-v pkgmgr_repos:/root/Repositories \ -v pkgmgr_repos:/root/Repositories \
-v pkgmgr_pip_cache:/root/.cache/pip \ -v pkgmgr_pip_cache:/root/.cache/pip \
-w /src \ -w /src \
archlinux:latest \ "pkgmgr-${{ matrix.distro }}-virgin" \
bash -lc ' bash -lc '
set -euo pipefail set -euo pipefail
pacman -Syu --noconfirm git python python-pip nix make
# Fix: allow git operations on mounted repo path
git config --global --add safe.directory /src git config --global --add safe.directory /src
make install make install
@@ -46,4 +54,3 @@ jobs:
echo ">>> Running Nix-based: nix run .#pkgmgr -- version pkgmgr" echo ">>> Running Nix-based: nix run .#pkgmgr -- version pkgmgr"
nix run /src#pkgmgr -- version pkgmgr nix run /src#pkgmgr -- version pkgmgr
' '

View File

@@ -7,6 +7,10 @@ jobs:
test-virgin-user: test-virgin-user:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 45 timeout-minutes: 45
strategy:
fail-fast: false
matrix:
distro: [arch, debian, ubuntu, fedora, centos]
steps: steps:
- name: Checkout repository - name: Checkout repository
@@ -15,19 +19,24 @@ jobs:
- name: Show Docker version - name: Show Docker version
run: docker version run: docker version
- name: Virgin Arch pkgmgr user test (non-root with sudo) # 🔹 BUILD virgin image if missing
- name: Build virgin container (${{ matrix.distro }})
run: |
set -euo pipefail
distro="${{ matrix.distro }}" make build-missing
# 🔹 RUN test inside virgin image as non-root
- name: Virgin ${{ matrix.distro }} pkgmgr test (user)
run: | run: |
set -euo pipefail set -euo pipefail
docker run --rm \ docker run --rm \
-v "$PWD":/src \ -v "$PWD":/src \
-w /src \ -w /src \
archlinux:latest \ "pkgmgr-${{ matrix.distro }}-virgin" \
bash -lc ' bash -lc '
set -euo pipefail set -euo pipefail
pacman -Syu --noconfirm git python python-pip sudo base-devel debugedit nix make
make install make install
useradd -m dev useradd -m dev
@@ -35,7 +44,6 @@ jobs:
chmod 0440 /etc/sudoers.d/dev chmod 0440 /etc/sudoers.d/dev
chown -R dev:dev /src chown -R dev:dev /src
# --- make Nix usable for non-root inside this container ---
mkdir -p /nix/store /nix/var/nix /nix/var/log/nix /nix/var/nix/profiles mkdir -p /nix/store /nix/var/nix /nix/var/log/nix /nix/var/nix/profiles
chown -R dev:dev /nix chown -R dev:dev /nix
chmod 0755 /nix chmod 0755 /nix
@@ -45,21 +53,13 @@ jobs:
set -euo pipefail set -euo pipefail
cd /src cd /src
echo \">>> [dev] Using user: \$(whoami)\"
echo \">>> [dev] Running make setup-venv...\"
make setup-venv make setup-venv
echo \">>> [dev] Activating venv...\"
. \"\$HOME/.venvs/pkgmgr/bin/activate\" . \"\$HOME/.venvs/pkgmgr/bin/activate\"
echo \">>> [dev] Running: pkgmgr version pkgmgr\"
pkgmgr version pkgmgr pkgmgr version pkgmgr
echo \">>> [dev] Running Nix-based pkgmgr version...\"
export NIX_REMOTE=local export NIX_REMOTE=local
export NIX_CONFIG=\"experimental-features = nix-command flakes\" export NIX_CONFIG=\"experimental-features = nix-command flakes\"
nix run /src#pkgmgr -- version pkgmgr nix run /src#pkgmgr -- version pkgmgr
" "
' '

View File

@@ -1,54 +1,57 @@
# syntax=docker/dockerfile:1
# ------------------------------------------------------------ # ------------------------------------------------------------
# Base image selector — overridden by Makefile # Base image selector — overridden by build args / Makefile
# ------------------------------------------------------------ # ------------------------------------------------------------
ARG BASE_IMAGE ARG BASE_IMAGE
FROM ${BASE_IMAGE}
RUN echo "BASE_IMAGE=${BASE_IMAGE}" && \ # ============================================================
cat /etc/os-release || true # Target: virgin
# - installs distro deps (incl. make)
# - no pkgmgr build
# - no entrypoint
# ============================================================
FROM ${BASE_IMAGE} AS virgin
# ------------------------------------------------------------ RUN echo "BASE_IMAGE=${BASE_IMAGE}" && cat /etc/os-release || true
# Nix environment defaults
#
# Nix itself is installed by your system packages (via init-nix.sh).
# Here we only define default configuration options.
# ------------------------------------------------------------
ENV NIX_CONFIG="experimental-features = nix-command flakes"
# ------------------------------------------------------------
# Copy scripts and install distro dependencies
# ------------------------------------------------------------
WORKDIR /build WORKDIR /build
# Copy only scripts first so dependency installation can run early # Copy scripts first so dependency installation can be cached
COPY scripts/ scripts/ COPY scripts/installation/ scripts/installation/
RUN find scripts -type f -name '*.sh' -exec chmod +x {} \;
# ------------------------------------------------------------ # Install distro-specific build dependencies (including make)
# Select distro-specific Docker entrypoint RUN bash scripts/installation/dependencies.sh
# ------------------------------------------------------------
# Docker entrypoint (distro-agnostic, nutzt package.sh)
# ------------------------------------------------------------
COPY scripts/docker/entry.sh /usr/local/bin/docker-entry.sh
RUN chmod +x /usr/local/bin/docker-entry.sh
# ------------------------------------------------------------ # Virgin default
# Build and install distro-native package-manager package CMD ["bash"]
# via Makefile `install` target
# ------------------------------------------------------------
# ============================================================
# Target: full
# - inherits from virgin
# - builds + installs pkgmgr
# - sets entrypoint + default cmd
# ============================================================
FROM virgin AS full
# Nix environment defaults (only config; nix itself comes from deps/install flow)
ENV NIX_CONFIG="experimental-features = nix-command flakes"
WORKDIR /build
# Copy full repository for build
COPY . . COPY . .
RUN find scripts -type f -name '*.sh' -exec chmod +x {} \;
RUN set -e; \ # Build and install distro-native package-manager package
echo "Building and installing package-manager via make install..."; \ RUN set -euo pipefail; \
make install; \ echo "Building and installing package-manager via make install..."; \
rm -rf /build make install; \
cd /; rm -rf /build
# Entry point
COPY scripts/docker/entry.sh /usr/local/bin/docker-entry.sh
# ------------------------------------------------------------
# Runtime working directory and dev entrypoint
# ------------------------------------------------------------
WORKDIR /src WORKDIR /src
ENTRYPOINT ["/usr/local/bin/docker-entry.sh"] ENTRYPOINT ["/usr/local/bin/docker-entry.sh"]
CMD ["pkgmgr", "--help"] CMD ["pkgmgr", "--help"]

View File

@@ -57,10 +57,16 @@ setup-nix:
# Docker build targets (delegated to scripts/build) # Docker build targets (delegated to scripts/build)
# ------------------------------------------------------------ # ------------------------------------------------------------
build: build:
@bash scripts/build/build-image.sh @bash scripts/build/image.sh --target virgin
@bash scripts/build/image.sh
build-missing:
@bash scripts/build/image.sh --target virgin --missing
@bash scripts/build/image.sh --missing
build-no-cache: build-no-cache:
@bash scripts/build/build-image-no-cache.sh @bash scripts/build/image.sh --target virgin --no-cache
@bash scripts/build/image.sh --no-cache
build-no-cache-all: build-no-cache-all:
@set -e; \ @set -e; \
@@ -88,13 +94,6 @@ test-env-virtual: build-missing
test-env-nix: build-missing test-env-nix: build-missing
@bash scripts/test/test-env-nix.sh @bash scripts/test/test-env-nix.sh
# ------------------------------------------------------------
# Build only missing container images
# ------------------------------------------------------------
build-missing:
@bash scripts/build/build-image-missing.sh
# Combined test target for local + CI (unit + integration + e2e) # Combined test target for local + CI (unit + integration + e2e)
test: test-env-virtual test-unit test-integration test-e2e test: test-env-virtual test-unit test-integration test-e2e

View File

@@ -1,24 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "${SCRIPT_DIR}/resolve-base-image.sh"
IMAGE="package-manager-test-$distro"
BASE_IMAGE="$(resolve_base_image "$distro")"
if docker image inspect "$IMAGE" >/dev/null 2>&1; then
echo "[build-missing] Image already exists: $IMAGE (skipping)"
exit 0
fi
echo
echo "------------------------------------------------------------"
echo "[build-missing] Building missing image: $IMAGE"
echo "BASE_IMAGE = $BASE_IMAGE"
echo "------------------------------------------------------------"
docker build \
--build-arg BASE_IMAGE="$BASE_IMAGE" \
-t "$IMAGE" \
.

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "${SCRIPT_DIR}/resolve-base-image.sh"
base_image="$(resolve_base_image "$distro")"
echo ">>> Building test image for distro '$distro' with NO CACHE (BASE_IMAGE=$base_image)..."
docker build \
--no-cache \
--build-arg BASE_IMAGE="$base_image" \
-t "package-manager-test-$distro" \
.

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "${SCRIPT_DIR}/resolve-base-image.sh"
base_image="$(resolve_base_image "$distro")"
echo ">>> Building test image for distro '$distro' (BASE_IMAGE=$base_image)..."
docker build \
--build-arg BASE_IMAGE="$base_image" \
-t "package-manager-test-$distro" \
.

120
scripts/build/image.sh Executable file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/env bash
set -euo pipefail
# Unified docker image builder for all distros.
#
# Supports:
# --missing Build only if image does not exist
# --no-cache Disable docker layer cache
# --target Dockerfile target (e.g. virgin|full)
# --tag Override image tag (default: pkgmgr-$distro[-$target])
#
# Requires:
# - env var: distro (arch|debian|ubuntu|fedora|centos)
# - base.sh in same dir
#
# Examples:
# distro=arch bash scripts/build/image.sh
# distro=arch bash scripts/build/image.sh --no-cache
# distro=arch bash scripts/build/image.sh --missing
# distro=arch bash scripts/build/image.sh --target virgin
# distro=arch bash scripts/build/image.sh --target virgin --missing
# distro=arch bash scripts/build/image.sh --tag myimg:arch
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=/dev/null
source "${SCRIPT_DIR}/base.sh"
: "${distro:?Environment variable 'distro' must be set (arch|debian|ubuntu|fedora|centos)}"
NO_CACHE=0
MISSING_ONLY=0
TARGET=""
IMAGE_TAG="" # derive later unless --tag is provided
usage() {
local default_tag="pkgmgr-${distro}"
if [[ -n "${TARGET:-}" ]]; then
default_tag="${default_tag}-${TARGET}"
fi
cat <<EOF
Usage: distro=<distro> $0 [--missing] [--no-cache] [--target <name>] [--tag <image>]
Options:
--missing Build only if the image does not already exist
--no-cache Build with --no-cache
--target <name> Build a specific Dockerfile target (e.g. virgin|full)
--tag <image> Override the output image tag (default: ${default_tag})
-h, --help Show help
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--no-cache) NO_CACHE=1; shift ;;
--missing) MISSING_ONLY=1; shift ;;
--target)
TARGET="${2:-}"
if [[ -z "${TARGET}" ]]; then
echo "ERROR: --target requires a value (e.g. virgin|full)" >&2
exit 2
fi
shift 2
;;
--tag)
IMAGE_TAG="${2:-}"
if [[ -z "${IMAGE_TAG}" ]]; then
echo "ERROR: --tag requires a value" >&2
exit 2
fi
shift 2
;;
-h|--help) usage; exit 0 ;;
*)
echo "ERROR: Unknown argument: $1" >&2
usage
exit 2
;;
esac
done
# Auto-tag: if --tag not provided, derive from distro (+ target suffix)
if [[ -z "${IMAGE_TAG}" ]]; then
IMAGE_TAG="pkgmgr-${distro}"
if [[ -n "${TARGET}" ]]; then
IMAGE_TAG="${IMAGE_TAG}-${TARGET}"
fi
fi
BASE_IMAGE="$(resolve_base_image "$distro")"
if [[ "${MISSING_ONLY}" == "1" ]]; then
if docker image inspect "${IMAGE_TAG}" >/dev/null 2>&1; then
echo "[build] Image already exists: ${IMAGE_TAG} (skipping due to --missing)"
exit 0
fi
fi
echo
echo "------------------------------------------------------------"
echo "[build] Building image: ${IMAGE_TAG}"
echo "distro = ${distro}"
echo "BASE_IMAGE = ${BASE_IMAGE}"
if [[ -n "${TARGET}" ]]; then echo "target = ${TARGET}"; fi
if [[ "${NO_CACHE}" == "1" ]]; then echo "cache = disabled"; fi
echo "------------------------------------------------------------"
build_args=(--build-arg "BASE_IMAGE=${BASE_IMAGE}")
if [[ "${NO_CACHE}" == "1" ]]; then
build_args+=(--no-cache)
fi
if [[ -n "${TARGET}" ]]; then
build_args+=(--target "${TARGET}")
fi
build_args+=(-t "${IMAGE_TAG}" .)
docker build "${build_args[@]}"

0
scripts/setup/nix.sh Normal file → Executable file
View File

0
scripts/setup/venv.sh Normal file → Executable file
View File

View File

@@ -12,7 +12,7 @@ docker run --rm \
-e REINSTALL_PKGMGR=1 \ -e REINSTALL_PKGMGR=1 \
-e TEST_PATTERN="${TEST_PATTERN}" \ -e TEST_PATTERN="${TEST_PATTERN}" \
--workdir /src \ --workdir /src \
"package-manager-test-${distro}" \ "pkgmgr-${distro}" \
bash -lc ' bash -lc '
set -euo pipefail set -euo pipefail

2
scripts/test/test-env-nix.sh Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
IMAGE="package-manager-test-${distro}" IMAGE="pkgmgr-${distro}"
echo "============================================================" echo "============================================================"
echo ">>> Running Nix flake-only test in ${distro} container" echo ">>> Running Nix flake-only test in ${distro} container"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
IMAGE="package-manager-test-$distro" IMAGE="pkgmgr-$distro"
echo echo
echo "------------------------------------------------------------" echo "------------------------------------------------------------"

View File

@@ -12,7 +12,7 @@ docker run --rm \
--workdir /src \ --workdir /src \
-e REINSTALL_PKGMGR=1 \ -e REINSTALL_PKGMGR=1 \
-e TEST_PATTERN="${TEST_PATTERN}" \ -e TEST_PATTERN="${TEST_PATTERN}" \
"package-manager-test-${distro}" \ "pkgmgr-${distro}" \
bash -lc ' bash -lc '
set -e; set -e;
git config --global --add safe.directory /src || true; git config --global --add safe.directory /src || true;

View File

@@ -12,7 +12,7 @@ docker run --rm \
--workdir /src \ --workdir /src \
-e REINSTALL_PKGMGR=1 \ -e REINSTALL_PKGMGR=1 \
-e TEST_PATTERN="${TEST_PATTERN}" \ -e TEST_PATTERN="${TEST_PATTERN}" \
"package-manager-test-${distro}" \ "pkgmgr-${distro}" \
bash -lc ' bash -lc '
set -e; set -e;
git config --global --add safe.directory /src || true; git config --global --add safe.directory /src || true;