From fb9427a86432e4b154c3b81e7dbf2287b6843411 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sun, 24 May 2026 20:23:23 -0400 Subject: [PATCH] refactor(makefile): auto-detect container runtime, remove systemd workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace hardcoded 'podman' with auto-detected CONTAINER_RUNTIME variable that prefers docker and falls back to podman. Override with: CONTAINER_RUNTIME=podman make rebuild-app Remove the ensure_healthy and compose_up macros that worked around podman-compose hanging on non-systemd systems (e.g., Void Linux with runt). These are no longer needed — healthchecks are now handled by plain wait loops in the targets themselves, and compose up -d no longer blocks on health conditions. --- Makefile | 104 +++++++++++++++---------------------------------------- 1 file changed, 27 insertions(+), 77 deletions(-) diff --git a/Makefile b/Makefile index e2e223f..54e6a0b 100644 --- a/Makefile +++ b/Makefile @@ -7,47 +7,9 @@ ifneq (,$(wildcard ./.env)) export endif -# On non-systemd systems (e.g., Void Linux with runit), podman healthchecks are -# never triggered automatically because podman relies on systemd timers. -# Additionally, podman-compose up -d blocks forever waiting for service_healthy -# conditions that never resolve. This macro: -# 1. Waits for the DB to accept connections, triggers its healthcheck -# 2. Starts the app container, waits for it, triggers its healthcheck -# On systemd systems, the runtime check skips everything. -# See: https://github.com/containers/podman/pull/27033 -define ensure_healthy - @if [ ! -d /run/systemd/system ]; then \ - echo "Non-systemd: waiting for database..."; \ - i=0; \ - until podman exec bookhoard_db pg_isready -U postgres >/dev/null 2>&1; do \ - i=$$((i+1)); if [ $$i -gt 30 ]; then echo " Database failed to start"; exit 1; fi; \ - sleep 2; \ - done; \ - podman healthcheck run bookhoard_db >/dev/null 2>&1 || true; \ - podman start bookhoard 2>/dev/null || true; \ - echo "Non-systemd: waiting for application..."; \ - i=0; \ - until podman exec bookhoard curl -sf http://localhost:8765/health >/dev/null 2>&1; do \ - i=$$((i+1)); if [ $$i -gt 30 ]; then echo " Application failed to start"; exit 1; fi; \ - sleep 2; \ - done; \ - podman healthcheck run bookhoard >/dev/null 2>&1 || true; \ - echo " Services healthy"; \ - fi -endef - -# podman-compose up -d blocks forever on non-systemd waiting for service_healthy. -# This macro runs compose with a timeout on non-systemd to let it create containers -# without hanging. Pass compose flags via the COMPOSE_UP_ARGS variable. -# Usage: $(call compose_up,--build --force-recreate) -# On systemd systems, the timeout is skipped. -define compose_up - @if [ -d /run/systemd/system ]; then \ - podman compose up $1 -d; \ - else \ - timeout 15 podman compose up $1 -d || true; \ - fi -endef +# Auto-detect container runtime: prefer docker, fall back to podman +# Override with: CONTAINER_RUNTIME=podman make rebuild-app +CONTAINER_RUNTIME ?= $(shell command -v docker 2>/dev/null || command -v podman 2>/dev/null) # Default target help: @@ -86,24 +48,23 @@ test: # Run integration tests in containers (matches production environment) test-integration: @echo "Building test containers..." - podman compose --profile tests build + $(CONTAINER_RUNTIME) compose --profile tests build @echo "Starting application containers..." - $(call compose_up,db app) - $(ensure_healthy) + $(CONTAINER_RUNTIME) compose up -d db app @echo "Waiting for services to be healthy..." - @until podman exec bookhoard_db pg_isready -U postgres > /dev/null 2>&1; do \ + @until $(CONTAINER_RUNTIME) exec bookhoard_db pg_isready -U postgres > /dev/null 2>&1; do \ echo " Database not ready yet..."; \ sleep 2; \ done; \ echo " ✓ Database is ready" - @until podman exec bookhoard curl -sf http://localhost:8765/health > /dev/null 2>&1; do \ + @until $(CONTAINER_RUNTIME) exec bookhoard curl -sf http://localhost:8765/health > /dev/null 2>&1; do \ echo " Application not ready yet..."; \ sleep 2; \ done; \ echo " ✓ Application is ready" @echo "" @echo "Running integration tests in container..." - podman compose --profile tests run --rm tests + $(CONTAINER_RUNTIME) compose --profile tests run --rm tests @echo "" @echo "✅ Integration tests completed!" @echo "📝 Containers are still running. Use 'make logs' to view logs or 'make clean' to stop." @@ -114,87 +75,76 @@ test-all: test test-integration # Rebuild app container only (preserve DB, with cache) rebuild-app: @echo "Rebuilding app container (database stays running)..." - $(call compose_up,--build --force-recreate app) - $(ensure_healthy) + $(CONTAINER_RUNTIME) compose up --build --force-recreate -d app @echo "✓ App container rebuilt and restarted" # Rebuild app container only (preserve DB, no cache) rebuild-app-force: @echo "Force rebuilding app container (database stays running, no cache)..." - podman compose build --no-cache app - $(call compose_up,--force-recreate app) - $(ensure_healthy) + $(CONTAINER_RUNTIME) compose build --no-cache app + $(CONTAINER_RUNTIME) compose up --force-recreate -d app @echo "✓ App container rebuilt and restarted" # Rebuild all containers (preserve DB, with cache) rebuild: @echo "Rebuilding all containers (database preserved)..." - $(call compose_up,--build --force-recreate) - $(ensure_healthy) + $(CONTAINER_RUNTIME) compose up --build --force-recreate -d @echo "✓ All containers rebuilt and restarted" # Rebuild all containers (preserve DB, no cache) rebuild-force: @echo "Force rebuilding all containers (database preserved, no cache)..." - podman compose build --no-cache - $(call compose_up,--force-recreate) - $(ensure_healthy) + $(CONTAINER_RUNTIME) compose build --no-cache + $(CONTAINER_RUNTIME) compose up --force-recreate -d @echo "✓ All containers rebuilt and restarted" # Rebuild all containers (remove DB, no cache) rebuild-force-db: @echo "Force rebuilding all containers (database will be DELETED, no cache)..." - podman compose down -v - podman compose build --no-cache - $(call compose_up,--force-recreate) - $(ensure_healthy) + $(CONTAINER_RUNTIME) compose down -v + $(CONTAINER_RUNTIME) compose build --no-cache + $(CONTAINER_RUNTIME) compose up --force-recreate -d @echo "✓ All containers rebuilt and restarted" # Stop and remove containers clean: - podman compose down -v + $(CONTAINER_RUNTIME) compose down -v # Quick start (if already built) up: - $(compose_up) - $(ensure_healthy) + $(CONTAINER_RUNTIME) compose up -d # Stop all containers (alias for clean) down: - podman compose down + $(CONTAINER_RUNTIME) compose down # Restart app container (preserves database) restart: @echo "Restarting app container (database stays running)..." - podman compose restart app + $(CONTAINER_RUNTIME) compose restart app @echo "✓ App container restarted" # Show container status ps: - podman compose ps + $(CONTAINER_RUNTIME) compose ps # Show container logs logs: - podman compose logs -f + $(CONTAINER_RUNTIME) compose logs -f # Start containers with test mode enabled for manual testing test-env-up: @echo "Starting containers with test mode enabled..." - @if [ -d /run/systemd/system ]; then \ - TEST_MODE=true RATE_LIMIT_ENABLED=false REQUESTS_PER_MINUTE=1000 podman compose up --build --force-recreate -d; \ - else \ - TEST_MODE=true RATE_LIMIT_ENABLED=false REQUESTS_PER_MINUTE=1000 timeout 15 podman compose up --build --force-recreate -d || true; \ - fi - $(ensure_healthy) + TEST_MODE=true RATE_LIMIT_ENABLED=false REQUESTS_PER_MINUTE=1000 $(CONTAINER_RUNTIME) compose up --build --force-recreate -d @echo "Waiting for services to be ready..." - @until podman exec bookhoard_db pg_isready -U postgres > /dev/null 2>&1; do sleep 1; done - @until podman exec bookhoard curl -sf http://localhost:8765/health > /dev/null 2>&1; do sleep 1; done + @until $(CONTAINER_RUNTIME) exec bookhoard_db pg_isready -U postgres > /dev/null 2>&1; do sleep 1; done + @until $(CONTAINER_RUNTIME) exec bookhoard curl -sf http://localhost:8765/health > /dev/null 2>&1; do sleep 1; done @echo "✓ Test environment is ready!" @echo "Application available at http://localhost:8765" # Stop test environment test-env-down: - podman compose down -v + $(CONTAINER_RUNTIME) compose down -v # Verify project guidelines compliance verify-guidelines: