2025-12-23 11:14:24 +01:00
PYTHON ?= python3
2025-12-23 19:41:31 +01:00
# ----------------------------
# E2E (existing)
# ----------------------------
2025-12-23 11:14:24 +01:00
COMPOSE_FILE := tests/e2e/docker-compose.yml
COMPOSE := docker compose -f $( COMPOSE_FILE)
2025-12-23 11:36:20 +01:00
VENV_DIR := .venv
VENV_PY := $( VENV_DIR) /bin/python
VENV_PIP := $( VENV_DIR) /bin/pip
# E2E defaults (override like: make e2e MATOMO_URL=http://127.0.0.1:8081)
MATOMO_URL ?= http://127.0.0.1:8080
MATOMO_ADMIN_USER ?= administrator
MATOMO_ADMIN_PASSWORD ?= AdminSecret123!
MATOMO_ADMIN_EMAIL ?= administrator@example.org
MATOMO_TOKEN_DESCRIPTION ?= e2e-make-token
2025-12-23 19:41:31 +01:00
# ----------------------------
# Container image (production-like)
# ----------------------------
IMAGE_NAME ?= ghcr.io/kevinveenbirkenbach/matomo-bootstrap
IMAGE_VERSION ?= 1.0.1
# Optional .env file for container runs
ENV_FILE ?= .env
# ----------------------------
# docker-compose stack (Matomo + MariaDB + Bootstrap)
# ----------------------------
COMPOSE_STACK_FILE ?= docker-compose.yml
COMPOSE_STACK := docker compose -f $( COMPOSE_STACK_FILE)
.PHONY : help \
venv deps-e2e playwright-install e2e-up e2e-install e2e-test e2e-down e2e logs clean \
2025-12-24 17:22:50 +01:00
test-integration \
2025-12-23 19:41:31 +01:00
image-build image-run image-shell image-push image-clean \
stack-up stack-down stack-logs stack-ps stack-bootstrap stack-rebootstrap stack-clean stack-reset
2025-12-23 11:14:24 +01:00
help :
@echo "Targets:"
2025-12-24 17:22:50 +01:00
@echo " venv Create local venv in $( VENV_DIR) "
2025-12-23 11:36:20 +01:00
@echo " deps-e2e Install package + E2E deps into venv"
@echo " playwright-install Install Chromium for Playwright (inside venv)"
@echo " e2e-up Start Matomo + DB for E2E tests"
@echo " e2e-install Run Matomo bootstrap (product code)"
@echo " e2e-test Run E2E tests (unittest)"
@echo " e2e-down Stop and remove E2E containers"
@echo " e2e Full cycle: up → install → test → down"
2025-12-23 19:41:31 +01:00
@echo " logs Show Matomo logs (E2E compose)"
@echo " clean Stop E2E containers + remove venv"
2025-12-24 17:22:50 +01:00
@echo " test-integration Run integration tests (unittest)"
2025-12-23 19:41:31 +01:00
@echo ""
@echo "Container image targets:"
@echo " image-build Build matomo-bootstrap container image"
@echo " image-run Run container bootstrap using $( ENV_FILE) (token-only stdout) "
@echo " image-shell Start interactive shell in container"
@echo " image-push Push image tags ( $( IMAGE_VERSION) + latest) "
@echo " image-clean Remove local image tags"
@echo ""
@echo "docker-compose stack targets (docker-compose.yml):"
@echo " stack-up Start MariaDB + Matomo (no bootstrap)"
@echo " stack-bootstrap Run one-shot bootstrap (prints token to stdout)"
@echo " stack-reset Full reset: down -v → build → up → bootstrap"
@echo " stack-down Stop stack"
@echo " stack-clean Stop stack and REMOVE volumes (DANGER)"
@echo " stack-logs Follow Matomo logs (stack)"
@echo " stack-ps Show stack status"
2025-12-23 11:36:20 +01:00
@echo ""
2025-12-23 19:41:31 +01:00
@echo "Variables:"
@echo " E2E: MATOMO_URL, MATOMO_ADMIN_USER, MATOMO_ADMIN_PASSWORD, MATOMO_ADMIN_EMAIL, MATOMO_TOKEN_DESCRIPTION"
@echo " IMG: IMAGE_NAME, IMAGE_VERSION, ENV_FILE"
@echo " STK: COMPOSE_STACK_FILE"
# ----------------------------
# E2E targets
# ----------------------------
2025-12-23 11:36:20 +01:00
venv :
2026-02-13 15:20:18 +01:00
@set -e; \
if [ ! -d " $( VENV_DIR) " ] ; then \
echo " Creating $( VENV_DIR) ... " ; \
$( PYTHON) -m venv " $( VENV_DIR) " ; \
fi ; \
if ! [ -x " $( VENV_PY) " ] || ! " $( VENV_PY) " -V >/dev/null 2>& 1; then \
echo " Repairing $( VENV_PY) symlink ... " ; \
fix_target = "" ; \
for cand in " $( VENV_DIR) /bin/python3.14 " " $( VENV_DIR) /bin/python3.13 " " $( VENV_DIR) /bin/python3.12 " " $( VENV_DIR) /bin/python3.11 " " $( VENV_DIR) /bin/python3.10 " ; do \
if [ -x " $$ cand " ] ; then \
fix_target = " $$ (basename " $$ cand")" ; \
break; \
fi ; \
done ; \
if [ -z " $$ fix_target " ] && [ -x " $( VENV_PIP) " ] ; then \
shebang = " $$ (head -n1 " $( VENV_PIP) " | sed 's/^#!//')" ; \
if [ -n " $$ shebang " ] && [ -x " $$ shebang " ] ; then \
fix_target = " $$ (basename " $$ shebang")" ; \
fi ; \
fi ; \
if [ -n " $$ fix_target " ] && [ -x " $( VENV_DIR) /bin/ $$ fix_target " ] ; then \
ln -sfn " $$ fix_target " " $( VENV_PY) " ; \
ln -sfn " $$ fix_target " " $( VENV_DIR) /bin/python3 " ; \
fi ; \
fi ; \
if ! [ -x " $( VENV_PIP) " ] || ! " $( VENV_PIP) " --version >/dev/null 2>& 1; then \
echo "Repairing pip via ensurepip ..." ; \
" $( VENV_PY) " -m ensurepip --upgrade >/dev/null 2>& 1 || true; \
fi ; \
if ! [ -x " $( VENV_PY) " ] || ! " $( VENV_PY) " -V >/dev/null 2>& 1; then \
echo " ERROR: Could not repair $( VENV_PY) in existing $( VENV_DIR) . " ; \
echo " Run 'make clean' once or remove $( VENV_DIR) manually. " ; \
exit 2; \
fi ; \
if ! [ -x " $( VENV_PIP) " ] || ! " $( VENV_PIP) " --version >/dev/null 2>& 1; then \
echo " ERROR: Could not repair $( VENV_PIP) in existing $( VENV_DIR) . " ; \
echo " Run 'make clean' once or remove $( VENV_DIR) manually. " ; \
exit 2; \
fi ; \
" $( VENV_PIP) " -q install -U pip setuptools wheel >/dev/null
2025-12-23 11:36:20 +01:00
deps-e2e : venv
@$( VENV_PIP) install -e ".[e2e]"
playwright-install : deps -e 2e
2025-12-23 21:38:27 +01:00
@$( VENV_PY) -m playwright install chromium
2025-12-23 11:14:24 +01:00
e2e-up :
$( COMPOSE) up -d
2025-12-23 11:36:20 +01:00
@echo " Waiting for Matomo to answer (any HTTP code) on $( MATOMO_URL) / ... "
2025-12-23 11:14:24 +01:00
@for i in $$ ( seq 1 180) ; do \
2025-12-23 11:36:20 +01:00
code = $$ ( curl -sS -o /dev/null -w "%{http_code}" --max-time 2 " $( MATOMO_URL) / " || true ) ; \
if [ " $$ code " != "000" ] ; then \
echo " Matomo answered with HTTP $$ code. " ; \
2025-12-23 11:14:24 +01:00
exit 0; \
fi ; \
sleep 1; \
done ; \
2025-12-23 11:36:20 +01:00
echo " Matomo did not answer on $( MATOMO_URL) " ; \
2025-12-23 11:14:24 +01:00
$( COMPOSE) ps; \
$( COMPOSE) logs --no-color --tail= 200 matomo; \
exit 1
2025-12-23 11:36:20 +01:00
e2e-install : playwright -install
MATOMO_URL = " $( MATOMO_URL) " \
MATOMO_ADMIN_USER = " $( MATOMO_ADMIN_USER) " \
MATOMO_ADMIN_PASSWORD = " $( MATOMO_ADMIN_PASSWORD) " \
MATOMO_ADMIN_EMAIL = " $( MATOMO_ADMIN_EMAIL) " \
MATOMO_TOKEN_DESCRIPTION = " $( MATOMO_TOKEN_DESCRIPTION) " \
2025-12-23 12:21:13 +01:00
MATOMO_CONTAINER_NAME = "e2e-matomo" \
2025-12-23 11:36:20 +01:00
PYTHONPATH = src $( VENV_PY) -m matomo_bootstrap
2025-12-23 11:14:24 +01:00
2025-12-23 11:36:20 +01:00
e2e-test : deps -e 2e
PYTHONPATH = src $( VENV_PY) -m unittest discover -s tests/e2e -v
2025-12-23 11:14:24 +01:00
e2e-down :
$( COMPOSE) down -v
2025-12-23 19:41:31 +01:00
e2e-nix :
docker compose -f tests/e2e/docker-compose.yml up -d
python3 -m unittest -v tests/e2e/test_bootstrap_nix.py
docker compose -f tests/e2e/docker-compose.yml down -v
2025-12-23 11:14:24 +01:00
e2e : e 2e -up e 2e -install e 2e -test e 2e -down
logs :
$( COMPOSE) logs -f matomo
clean : e 2e -down
2025-12-23 11:36:20 +01:00
rm -rf $( VENV_DIR)
2025-12-23 19:41:31 +01:00
2025-12-24 17:22:50 +01:00
# ----------------------------
# Integration tests
# ----------------------------
test-integration :
PYTHONPATH = src $( PYTHON) -m unittest discover -s tests/integration -v
2025-12-23 19:41:31 +01:00
# ----------------------------
# Container image workflow
# ----------------------------
image-build :
docker build -t $( IMAGE_NAME) :$( IMAGE_VERSION) -t $( IMAGE_NAME) :latest .
image-run :
@test -f " $( ENV_FILE) " || ( echo " Missing $( ENV_FILE) . Create it from env.sample. " ; exit 1)
docker run --rm \
--env-file " $( ENV_FILE) " \
--network host \
$( IMAGE_NAME) :$( IMAGE_VERSION)
image-shell :
@test -f " $( ENV_FILE) " || ( echo " Missing $( ENV_FILE) . Create it from env.sample. " ; exit 1)
docker run --rm -it \
--env-file " $( ENV_FILE) " \
--network host \
--entrypoint /bin/bash \
$( IMAGE_NAME) :$( IMAGE_VERSION)
image-push :
docker push $( IMAGE_NAME) :$( IMAGE_VERSION)
docker push $( IMAGE_NAME) :latest
image-clean :
docker rmi $( IMAGE_NAME) :$( IMAGE_VERSION) $( IMAGE_NAME) :latest || true
# ----------------------------
# docker-compose stack workflow
# ----------------------------
## Start MariaDB + Matomo (without bootstrap)
stack-up :
$( COMPOSE_STACK) up -d db matomo
@echo "Matomo is starting on http://127.0.0.1:8080"
## Run one-shot bootstrap (prints token to stdout)
stack-bootstrap :
$( COMPOSE_STACK) run --rm bootstrap
## Re-run bootstrap (forces a fresh one-shot run)
stack-rebootstrap :
$( COMPOSE_STACK) rm -f bootstrap || true
$( COMPOSE_STACK) run --rm bootstrap
## Follow Matomo logs (stack)
stack-logs :
$( COMPOSE_STACK) logs -f matomo
## Show running services (stack)
stack-ps :
$( COMPOSE_STACK) ps
## Stop stack
stack-down :
$( COMPOSE_STACK) down
## Stop stack and REMOVE volumes (DANGER)
stack-clean :
$( COMPOSE_STACK) down -v
## Full reset: down -v → rebuild bootstrap → up → bootstrap
stack-reset :
$( COMPOSE_STACK) down -v
$( COMPOSE_STACK) build --no-cache bootstrap
$( COMPOSE_STACK) up -d db matomo
@echo "Waiting for Matomo to become reachable..."
@sleep 10
$( COMPOSE_STACK) run --rm bootstrap