.POSIX: .SUFFIXES: .DEFAULT_GOAL := help # --- SETTINGS --- CORE_DIR = brain IMAGE_NAME = agent_media PYTHON_VERSION = 3.12.7 PYTHON_VERSION_SHORT = $(shell echo $(PYTHON_VERSION) | cut -d. -f1,2) # Change to 'uv' when ready. RUNNER ?= poetry SERVICE_NAME = agent_media export IMAGE_NAME export PYTHON_VERSION export PYTHON_VERSION_SHORT export RUNNER # --- ADAPTERS --- # UV uses "sync", Poetry uses "install". Both install DEV deps by default. INSTALL_CMD = $(if $(filter uv,$(RUNNER)),sync,install) # --- MACROS --- ARGS = $(filter-out $@,$(MAKECMDGOALS)) BUMP_CMD = cd $(CORE_DIR) && $(RUNNER) run bump-my-version bump COMPOSE_CMD = docker-compose DOCKER_CMD = docker build \ --build-arg PYTHON_VERSION=$(PYTHON_VERSION) \ --build-arg PYTHON_VERSION_SHORT=$(PYTHON_VERSION_SHORT) \ --build-arg RUNNER=$(RUNNER) \ -f $(CORE_DIR)/Dockerfile \ -t $(IMAGE_NAME):latest . RUNNER_ADD = cd $(CORE_DIR) && $(RUNNER) add RUNNER_HOOKS = cd $(CORE_DIR) && $(RUNNER) run pre-commit install -c ../.pre-commit-config.yaml RUNNER_INSTALL = cd $(CORE_DIR) && $(RUNNER) $(INSTALL_CMD) RUNNER_RUN = cd $(CORE_DIR) && $(RUNNER) run RUNNER_UPDATE = cd $(CORE_DIR) && $(RUNNER) update # --- STYLES --- B = \033[1m G = \033[32m T = \033[36m R = \033[0m # --- TARGETS --- .PHONY: add build build-test check-docker check-runner clean coverage down format help init-dotenv install install-hooks lint logs major minor patch prune ps restart run shell test up update _check_branch _ci-dump-config _ci-run-tests _push_tag # Catch-all for args %: @: add: check-runner @echo "$(T)โž• Adding dependency ($(RUNNER)): $(ARGS)$(R)" $(RUNNER_ADD) $(ARGS) build: check-docker @echo "$(T)๐Ÿณ Building Docker image...$(R)" $(DOCKER_CMD) @echo "โœ… Image $(IMAGE_NAME):latest ready." build-test: check-docker @echo "$(T)๐Ÿณ Building test image (with dev deps)...$(R)" docker build \ --build-arg RUNNER=$(RUNNER) \ --build-arg PYTHON_VERSION=$(PYTHON_VERSION) \ --build-arg PYTHON_VERSION_SHORT=$(PYTHON_VERSION_SHORT) \ -f $(CORE_DIR)/Dockerfile \ --target test \ -t $(IMAGE_NAME):test . @echo "โœ… Test image $(IMAGE_NAME):test ready." check-docker: @command -v docker >/dev/null 2>&1 || { echo "$(R)โŒ Docker not installed$(R)"; exit 1; } @docker info >/dev/null 2>&1 || { echo "$(R)โŒ Docker daemon not running$(R)"; exit 1; } check-runner: @command -v $(RUNNER) >/dev/null 2>&1 || { echo "$(R)โŒ $(RUNNER) not installed$(R)"; exit 1; } clean: @echo "$(T)๐Ÿงน Cleaning caches...$(R)" cd $(CORE_DIR) && rm -rf .ruff_cache __pycache__ .pytest_cache find $(CORE_DIR) -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true find $(CORE_DIR) -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true find $(CORE_DIR) -type f -name "*.pyc" -delete 2>/dev/null || true @echo "โœ… Caches cleaned." coverage: check-runner @echo "$(T)๐Ÿ“Š Running tests with coverage...$(R)" $(RUNNER_RUN) pytest --cov=. --cov-report=html --cov-report=term $(ARGS) @echo "โœ… Report generated in htmlcov/" down: check-docker @echo "$(T)๐Ÿ›‘ Stopping containers...$(R)" $(COMPOSE_CMD) down @echo "โœ… System stopped." format: check-runner @echo "$(T)โœจ Formatting with Ruff...$(R)" $(RUNNER_RUN) ruff format . $(RUNNER_RUN) ruff check --fix . @echo "โœ… Code cleaned." help: @echo "$(B)Available commands:$(R)" @echo "" @echo "$(G)Setup:$(R)" @echo " $(T)check-docker $(R) Verify Docker is installed and running." @echo " $(T)check-runner $(R) Verify package manager ($(RUNNER))." @echo " $(T)init-dotenv $(R) Create .env from .env.example with generated secrets." @echo " $(T)install $(R) Install ALL dependencies (Prod + Dev)." @echo " $(T)install-hooks $(R) Install git pre-commit hooks." @echo "" @echo "$(G)Docker:$(R)" @echo " $(T)build $(R) Build the docker image (production)." @echo " $(T)build-test $(R) Build the docker image (with dev deps for testing)." @echo " $(T)down $(R) Stop and remove containers." @echo " $(T)logs $(R) Follow logs." @echo " $(T)prune $(R) Clean Docker system." @echo " $(T)ps $(R) Show container status." @echo " $(T)restart $(R) Restart all containers." @echo " $(T)shell $(R) Open shell in container." @echo " $(T)up $(R) Start the agent." @echo "" @echo "$(G)Development:$(R)" @echo " $(T)add ... $(R) Add dependency (use --group dev or --dev if needed)." @echo " $(T)clean $(R) Clean caches." @echo " $(T)coverage $(R) Run tests with coverage." @echo " $(T)format $(R) Format code (Ruff)." @echo " $(T)lint $(R) Lint code without fixing." @echo " $(T)test ... $(R) Run tests (local with $(RUNNER))." @echo " $(T)update $(R) Update dependencies." @echo "" @echo "$(G)Versioning:$(R)" @echo " $(T)major/minor/patch $(R) Bump version and push tag (triggers CI/CD)." init-dotenv: @echo "$(T)๐Ÿ”‘ Initializing .env file...$(R)" @if [ -f .env ]; then \ echo "$(R)โš ๏ธ .env already exists. Skipping.$(R)"; \ exit 0; \ fi @if [ ! -f .env.example ]; then \ echo "$(R)โŒ .env.example not found$(R)"; \ exit 1; \ fi @if ! command -v openssl >/dev/null 2>&1; then \ echo "$(R)โŒ openssl not found. Please install it first.$(R)"; \ exit 1; \ fi @echo "$(T) โ†’ Copying .env.example...$(R)" @cp .env.example .env @echo "$(T) โ†’ Generating secrets...$(R)" @sed -i.bak "s|JWT_SECRET=.*|JWT_SECRET=$$(openssl rand -base64 32)|" .env @sed -i.bak "s|JWT_REFRESH_SECRET=.*|JWT_REFRESH_SECRET=$$(openssl rand -base64 32)|" .env @sed -i.bak "s|CREDS_KEY=.*|CREDS_KEY=$$(openssl rand -hex 16)|" .env @sed -i.bak "s|CREDS_IV=.*|CREDS_IV=$$(openssl rand -hex 8)|" .env @sed -i.bak "s|MEILI_MASTER_KEY=.*|MEILI_MASTER_KEY=$$(openssl rand -base64 32)|" .env @sed -i.bak "s|AGENT_BRAIN_API_KEY=.*|AGENT_BRAIN_API_KEY=$$(openssl rand -base64 24)|" .env @rm -f .env.bak @echo "$(G)โœ… .env created with generated secrets!$(R)" @echo "$(T)โš ๏ธ Don't forget to add your API keys:$(R)" @echo " - OPENAI_API_KEY" @echo " - DEEPSEEK_API_KEY" @echo " - TMDB_API_KEY (optional)" install: check-runner @echo "$(T)๐Ÿ“ฆ Installing FULL environment ($(RUNNER))...$(R)" $(RUNNER_INSTALL) @echo "โœ… Environment ready (Prod + Dev)." install-hooks: check-runner @echo "$(T)๐Ÿ”ง Installing hooks...$(R)" $(RUNNER_HOOKS) @echo "โœ… Hooks ready." lint: check-runner @echo "$(T)๐Ÿ” Linting code...$(R)" $(RUNNER_RUN) ruff check . logs: check-docker @echo "$(T)๐Ÿ“‹ Following logs...$(R)" $(COMPOSE_CMD) logs -f major: _check_branch @echo "$(T)๐Ÿ’ฅ Bumping major...$(R)" SKIP=all $(BUMP_CMD) major @$(MAKE) -s _push_tag minor: _check_branch @echo "$(T)โœจ Bumping minor...$(R)" SKIP=all $(BUMP_CMD) minor @$(MAKE) -s _push_tag patch: _check_branch @echo "$(T)๐Ÿš€ Bumping patch...$(R)" SKIP=all $(BUMP_CMD) patch @$(MAKE) -s _push_tag prune: check-docker @echo "$(T)๐Ÿ—‘๏ธ Pruning Docker resources...$(R)" docker system prune -af @echo "โœ… Docker cleaned." ps: check-docker @echo "$(T)๐Ÿ“‹ Container status:$(R)" @$(COMPOSE_CMD) ps restart: check-docker @echo "$(T)๐Ÿ”„ Restarting containers...$(R)" $(COMPOSE_CMD) restart @echo "โœ… Containers restarted." run: check-runner $(RUNNER_RUN) $(ARGS) shell: check-docker @echo "$(T)๐Ÿš Opening shell in $(SERVICE_NAME)...$(R)" $(COMPOSE_CMD) exec $(SERVICE_NAME) /bin/sh test: check-runner @echo "$(T)๐Ÿงช Running tests...$(R)" $(RUNNER_RUN) pytest $(ARGS) up: check-docker @echo "$(T)๐Ÿš€ Starting Agent Media...$(R)" $(COMPOSE_CMD) up -d @echo "โœ… System is up." update: check-runner @echo "$(T)๐Ÿ”„ Updating dependencies...$(R)" $(RUNNER_UPDATE) @echo "โœ… All packages up to date." _check_branch: @curr=$$(git rev-parse --abbrev-ref HEAD); \ if [ "$$curr" != "main" ]; then \ echo "โŒ Error: not on the main branch"; exit 1; \ fi _ci-dump-config: @echo "image_name=$(IMAGE_NAME)" @echo "python_version=$(PYTHON_VERSION)" @echo "python_version_short=$(PYTHON_VERSION_SHORT)" @echo "runner=$(IMAGE_NAME)" @echo "service_name=$(SERVICE_NAME)" _ci-run-tests: build-test @echo "$(T)๐Ÿงช Running tests in Docker...$(R)" docker run --rm \ -e DEEPSEEK_API_KEY \ -e TMDB_API_KEY \ $(IMAGE_NAME):test pytest @echo "โœ… Tests passed." _push_tag: @echo "$(T)๐Ÿ“ฆ Pushing tag...$(R)" git push --tags @echo "โœ… Tag pushed. Check CI for build status."