# UnitForge Makefile # Development workflow automation using uv package manager .PHONY: help install install-dev clean test test-cov lint format type-check .PHONY: server cli demo docker-build docker-dev docker-prod docker-test .PHONY: pre-commit setup-dev deps-update deps-check security-check .PHONY: build package publish docs release # Default target .DEFAULT_GOAL := help # Colors for output (load from centralized utility) include scripts/colors.mk # Configuration PYTHON_VERSION := 3.8 PROJECT_NAME := unitforge VENV_PATH := .venv UV_INSTALLED := $(shell command -v uv 2> /dev/null) help: ## Show this help message $(call header,UnitForge Development Makefile) @echo "" @echo -e "$(GREEN)Available targets:$(NC)" @awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*##/ { printf " $(YELLOW)%-20s$(NC) %s\n", $$1, $$2 }' $(MAKEFILE_LIST) @echo "" @echo -e "$(GREEN)Quick start:$(NC)" @echo " make setup-dev # Set up development environment" @echo " make server # Start development server" @echo " make test # Run tests" @echo "" check-uv: ## Check if uv is installed ifndef UV_INSTALLED $(call error,uv is not installed) @echo "Install it with: curl -LsSf https://astral.sh/uv/install.sh | sh" @exit 1 else $(call success,uv is available) endif setup-dev: check-uv ## Set up development environment with uv $(call info,Setting up development environment...) @if [ -d "$(VENV_PATH)" ]; then \ echo -e "$(YELLOW)$(WARNING_SYMBOL)$(NC) Removing existing virtual environment..."; \ rm -rf $(VENV_PATH); \ fi uv venv --python python3 $(call success,Virtual environment created) @$(MAKE) install-dev @if [ -f ".pre-commit-config.yaml" ]; then \ echo -e "$(BLUE)$(INFO_SYMBOL)$(NC) Installing pre-commit hooks..."; \ . $(VENV_PATH)/bin/activate && pre-commit install; \ echo -e "$(GREEN)$(SUCCESS_SYMBOL)$(NC) Pre-commit hooks installed"; \ fi $(call success,Development environment ready!) @echo "" @echo -e "$(YELLOW)Next steps:$(NC)" @echo " source $(VENV_PATH)/bin/activate # Activate environment" @echo " make server # Start development server" @echo " make test # Run tests" install: check-uv ## Install production dependencies $(call info,Installing production dependencies...) uv pip install -e . $(call success,Production dependencies installed) install-dev: check-uv ## Install development dependencies $(call info,Installing development dependencies...) uv pip install -e ".[dev,web]" $(call success,Development dependencies installed) deps-update: check-uv ## Update all dependencies $(call info,Updating dependencies...) uv pip install --upgrade -e ".[dev,web]" $(call success,Dependencies updated) deps-check: ## Check for dependency vulnerabilities $(call info,Checking dependencies for vulnerabilities...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run pip-audit --desc || true; \ else \ echo -e "$(YELLOW)$(WARNING_SYMBOL)$(NC) Virtual environment not found. Run 'make setup-dev' first."; \ fi clean: ## Clean up cache files and build artifacts $(call info,Cleaning up...) find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true find . -type f -name "*.pyc" -delete 2>/dev/null || true find . -type f -name "*.pyo" -delete 2>/dev/null || true find . -type f -name "*.orig" -delete 2>/dev/null || true rm -rf .pytest_cache/ htmlcov/ .coverage .mypy_cache/ dist/ build/ rm -rf *.egg-info/ rm -f *.service *.timer *.socket *.mount *.target *.path $(call success,Cleanup complete) test: ## Run tests $(call info,Running tests...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run pytest tests/ -v; \ else \ uv run pytest tests/ -v; \ fi test-cov: ## Run tests with coverage $(call info,Running tests with coverage...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run pytest tests/ --cov=backend --cov-report=html --cov-report=term; \ else \ uv run pytest tests/ --cov=backend --cov-report=html --cov-report=term; \ fi $(call success,Coverage report generated in htmlcov/) test-watch: ## Run tests in watch mode $(call info,Running tests in watch mode...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run pytest tests/ -v --watch; \ else \ uv run pytest tests/ -v --watch; \ fi lint: ## Run linters $(call info,Running linters...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && \ uv run black --check backend/ tests/ && \ uv run isort --check-only backend/ tests/ && \ uv run flake8 backend/ tests/ --max-line-length=88 --extend-ignore=E203,W503 --exclude=.venv,__pycache__,build,dist; \ else \ uv run black --check backend/ tests/ && \ uv run isort --check-only backend/ tests/ && \ uv run flake8 backend/ tests/ --max-line-length=88 --extend-ignore=E203,W503 --exclude=.venv,__pycache__,build,dist; \ fi $(call success,Linting passed) format: ## Format code $(call info,Formatting code...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && \ uv run black backend/ tests/ && \ uv run isort backend/ tests/; \ else \ uv run black backend/ tests/ && \ uv run isort backend/ tests/; \ fi $(call success,Code formatted) type-check: ## Run type checking $(call info,Running type checks...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && PYTHONPATH=. uv run mypy backend/app/ backend/cli/ --ignore-missing-imports; \ else \ PYTHONPATH=. uv run mypy backend/app/ backend/cli/ --ignore-missing-imports; \ fi $(call success,Type checking passed) security-check: ## Run security checks $(call info,Running security checks...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run bandit -r backend/ -x tests/; \ else \ uv run bandit -r backend/ -x tests/; \ fi $(call success,Security checks passed) pre-commit: ## Run pre-commit hooks on all files $(call info,Running pre-commit hooks...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run pre-commit run --all-files; \ else \ uv run pre-commit run --all-files; \ fi server: ## Start development server $(call info,Starting development server...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && ./start-server.sh --log-level debug; \ else \ ./start-server.sh --log-level debug; \ fi server-prod: ## Start production server $(call info,Starting production server...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && ./start-server.sh --no-reload --log-level info; \ else \ ./start-server.sh --no-reload --log-level info; \ fi cli: ## Run CLI with help $(call header,UnitForge CLI) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && ./unitforge-cli --help; \ else \ ./unitforge-cli --help; \ fi demo: ## Run interactive demo $(call info,Starting interactive demo...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && ./demo.sh; \ else \ ./demo.sh; \ fi # Docker targets docker-build: ## Build Docker images $(call info,Building Docker images...) docker-compose build $(call success,Docker images built) docker-dev: ## Start development environment with Docker $(call info,Starting development environment with Docker...) docker-compose up unitforge-dev docker-prod: ## Start production environment with Docker $(call info,Starting production environment with Docker...) docker-compose --profile production up docker-test: ## Run tests in Docker $(call info,Running tests in Docker...) docker-compose --profile test up unitforge-test docker-cli: ## Run CLI in Docker $(call info,Running CLI in Docker...) docker-compose --profile cli run --rm unitforge-cli --help docker-clean: ## Clean Docker containers and images $(call info,Cleaning Docker containers and images...) docker-compose down --volumes --remove-orphans docker system prune -f $(call success,Docker cleanup complete) # Package and release targets build: clean ## Build package $(call info,Building package...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run python -m build; \ else \ uv run python -m build; \ fi $(call success,Package built in dist/) package: build ## Create distribution packages $(call info,Creating distribution packages...) @ls -la dist/ $(call success,Distribution packages ready) publish-test: package ## Publish to TestPyPI $(call info,Publishing to TestPyPI...) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run twine upload --repository testpypi dist/*; \ else \ uv run twine upload --repository testpypi dist/*; \ fi publish: package ## Publish to PyPI $(call info,Publishing to PyPI...) $(call warning,This will publish to the real PyPI. Are you sure? [y/N]) @read -r confirm && [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ] || (echo "Aborted" && exit 1) @if [ -f "$(VENV_PATH)/bin/activate" ]; then \ . $(VENV_PATH)/bin/activate && uv run twine upload dist/*; \ else \ uv run twine upload dist/*; \ fi docs: ## Generate documentation $(call info,Generating documentation...) $(call warning,Documentation generation not yet implemented) # Comprehensive quality check check-all: lint security-check test ## Run all quality checks $(call success,All quality checks passed) # Release preparation release-check: check-all build ## Prepare for release $(call info,Performing release checks...) $(call success,Release checks completed) @echo "" @echo -e "$(YELLOW)Release checklist:$(NC)" @echo " □ Update version in pyproject.toml" @echo " □ Update CHANGELOG.md" @echo " □ Commit changes" @echo " □ Create git tag" @echo " □ Run 'make publish'" # Quick development cycle dev: format lint test ## Quick development cycle (format, lint, test) $(call success,Development cycle complete) # Initialize new development environment init: setup-dev ## Initialize new development environment $(call success,Development environment initialized) @echo "" @echo -e "$(BLUE)Try these commands:$(NC)" @echo " make server # Start web server" @echo " make cli # Try CLI tool" @echo " make demo # Interactive demo" @echo " make test # Run tests" # Show project status status: ## Show project status $(call header,UnitForge Project Status) @echo "" @echo -e "$(YELLOW)Virtual Environment:$(NC)" @if [ -d "$(VENV_PATH)" ]; then \ echo " ✓ Virtual environment exists at $(VENV_PATH)"; \ if [ -n "$$VIRTUAL_ENV" ]; then \ echo " ✓ Virtual environment is activated"; \ else \ echo " ⚠ Virtual environment not activated"; \ fi \ else \ echo " ✗ Virtual environment not found"; \ fi @echo "" @echo -e "$(YELLOW)Dependencies:$(NC)" @if command -v uv >/dev/null 2>&1; then \ echo " ✓ uv package manager available"; \ else \ echo " ✗ uv package manager not found - REQUIRED"; \ fi @echo "" @echo -e "$(YELLOW)Project Files:$(NC)" @if [ -f "pyproject.toml" ]; then echo " ✓ pyproject.toml"; else echo " ✗ pyproject.toml"; fi @if [ -f "unitforge-cli" ]; then echo " ✓ CLI tool"; else echo " ✗ CLI tool"; fi @if [ -f "start-server.sh" ]; then echo " ✓ Server script"; else echo " ✗ Server script"; fi @if [ -d "backend" ]; then echo " ✓ Backend code"; else echo " ✗ Backend code"; fi @if [ -d "frontend" ]; then echo " ✓ Frontend code"; else echo " ✗ Frontend code"; fi @if [ -d "tests" ]; then echo " ✓ Tests"; else echo " ✗ Tests"; fi