260 lines
8.3 KiB
Makefile
260 lines
8.3 KiB
Makefile
.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=$(RUNNER)"
|
||
@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."
|