Files
2026-07-13 13:35:10 +08:00

203 lines
9.4 KiB
Makefile

GIT_ROOT ?= $(shell git rev-parse --show-toplevel)
# Optionally show commands being executed with V=1
Q := $(if $(V),,@)
# Common paths
RAGAS_PATHS := src tests docs
help: ## Show all Makefile targets
$(Q)grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}'
# =============================================================================
# SETUP & INSTALLATION
# =============================================================================
setup-venv: ## Set up uv virtual environment
@echo "Setting up uv virtual environment..."
$(Q)VIRTUAL_ENV= uv venv
@echo "Virtual environment created at .venv"
@echo "To activate: source .venv/bin/activate"
install-minimal: ## Install minimal dev dependencies (fast setup - 79 packages)
@echo "Installing minimal development dependencies (fast setup)..."
@if [ ! -d ".venv" ]; then \
echo "Virtual environment not found, creating one..."; \
$(MAKE) setup-venv; \
fi
@echo "Installing core ragas + essential dev tools..."
$(Q)uv pip install -e ".[dev-minimal]"
@echo "Setting up pre-commit hooks..."
$(Q)uv run pre-commit install
@echo "Minimal installation complete! (79 packages)"
@echo "Note: For full features including ML packages, use 'make install'"
install: ## Install full dependencies with uv sync (backward compatible - modern approach)
@echo "Installing full development dependencies with uv sync..."
@if [ ! -d ".venv" ]; then \
echo "Virtual environment not found, creating one..."; \
$(MAKE) setup-venv; \
fi
@echo "Installing ragas with full dev environment..."
$(Q)VIRTUAL_ENV= uv sync --group dev
@echo "Setting up pre-commit hooks..."
$(Q)uv run pre-commit install
@echo "Full installation complete! (Modern uv sync approach)"
# =============================================================================
# CODE QUALITY
# =============================================================================
.PHONY: help setup-venv install-minimal install format type check clean test test-e2e benchmarks benchmarks-docker run-ci run-ci-fast run-ci-format-check run-ci-type run-ci-tests build-docs serve-docs
format: ## Format and lint all code
@echo "Formatting and linting all code..."
@echo "(ruff format) Formatting ragas..."
$(Q)uv run --active ruff format src tests docs --exclude src/ragas/_version.py --config pyproject.toml
@echo "(ruff) Auto-fixing ragas (includes import sorting and unused imports)..."
$(Q)uv run --active ruff check src tests docs --exclude src/ragas/_version.py --fix-only --config pyproject.toml
@echo "(ruff) Final linting check for ragas..."
$(Q)uv run --active ruff check src tests docs --exclude src/ragas/_version.py --config pyproject.toml
type: ## Type check all code
@echo "Type checking all code..."
@echo "(pyright) Typechecking ragas..."
$(Q)PYRIGHT_PYTHON_FORCE_VERSION=latest uv run --active pyright -p pyproject.toml src
check: format type ## Quick health check (format + type, no tests)
@echo "Code quality check complete!"
# =============================================================================
# BENCHMARKS
# =============================================================================
benchmarks: ## Run all benchmarks locally
@echo "Running all benchmarks..."
@echo "Running evaluation benchmarks..."
$(Q)cd $(GIT_ROOT)/tests/benchmarks && uv run python benchmark_eval.py
@echo "Running testset generation benchmarks..."
$(Q)cd $(GIT_ROOT)/tests/benchmarks && uv run python benchmark_testsetgen.py
benchmarks-docker: ## Run benchmarks in docker
@echo "Running benchmarks in docker..."
$(Q)cd $(GIT_ROOT) || exit 1
docker buildx build --build-arg OPENAI_API_KEY=$(OPENAI_API_KEY) -t ragas-benchmark -f $(GIT_ROOT)/tests/benchmarks/Dockerfile .
docker inspect ragas-benchmark:latest | jq ".[0].Size" | numfmt --to=si
benchmarks-test: ## Run benchmarks for ragas unit tests
@echo "Running ragas unit tests with timing benchmarks..."
$(Q)uv run --active pytest --nbmake tests/unit --durations=0 -v $(shell if [ -n "$(k)" ]; then echo "-k $(k)"; fi)
# =============================================================================
# CI/BUILD
# =============================================================================
run-ci: ## Run complete CI pipeline (mirrors GitHub CI exactly)
@echo "Running complete CI pipeline..."
@echo "Format check..."
$(Q)uv run --active ruff format --check src tests docs --exclude src/ragas/_version.py --config pyproject.toml
$(Q)uv run --active ruff check src tests docs --exclude src/ragas/_version.py --config pyproject.toml
@echo "Type check..."
$(Q)$(MAKE) type
@echo "Unit tests..."
$(Q)__RAGAS_DEBUG_TRACKING=true RAGAS_DO_NOT_TRACK=true uv run --active pytest --nbmake tests/unit --dist loadfile -n auto
@echo "All CI checks passed!"
run-ci-format-check: ## Run format check in dry-run mode (like GitHub CI)
@echo "Running format check (dry-run, like GitHub CI)..."
@echo "Checking ragas formatting..."
$(Q)uv run --active ruff format --check src tests docs --exclude src/ragas/_version.py --config pyproject.toml
$(Q)uv run --active ruff check src docs tests --exclude src/ragas/_version.py --config pyproject.toml
run-ci-type: ## Run type checking (matches GitHub CI)
@echo "Running type checking (matches GitHub CI)..."
$(Q)$(MAKE) type
run-ci-tests: ## Run all tests with CI options
@echo "Running all tests with CI options..."
$(Q)__RAGAS_DEBUG_TRACKING=true RAGAS_DO_NOT_TRACK=true pytest --nbmake tests/unit --dist loadfile -n auto
run-ci-fast: ## Fast CI check for quick local validation (2-3 minutes)
@echo "Running fast CI check for quick feedback..."
@echo "Format check..."
$(Q)uv run --active ruff format --check src tests docs --exclude src/ragas/_version.py --config pyproject.toml
$(Q)uv run --active ruff check src docs tests --exclude src/ragas/_version.py --config pyproject.toml
@echo "Core unit tests (no nbmake for speed)..."
$(Q)uv run --active pytest tests/unit --dist loadfile -n auto -x
@echo "Fast CI check completed!"
clean: ## Clean all generated files
@echo "Cleaning all generated files..."
$(Q)find . -type f -name '*.py[co]' -delete -o -type d -name __pycache__ -delete
$(Q)rm -rf site/ docs/site/ .mypy_cache .pytest_cache .ruff_cache
$(Q)rm -rf dist/ build/ *.egg-info/ src/*.egg-info/
$(Q)rm -rf .coverage htmlcov/ .tox/ .venv/
$(Q)find . -name '*.log' -delete
$(Q)find . -name '.DS_Store' -delete
$(Q)find . -name 'temp*' -type d -exec rm -rf {} + 2>/dev/null || true
$(Q)find . -name '.tmp*' -type d -exec rm -rf {} + 2>/dev/null || true
@echo "Cleanup complete!"
# =============================================================================
# TESTING
# =============================================================================
test: ## Run all unit tests
@echo "Running all unit tests..."
$(Q)uv run --active pytest tests/unit $(shell if [ -n "$(k)" ]; then echo "-k $(k)"; fi)
test-all: ## Run all unit tests (including notebooks)
@echo "Running all unit tests (including notebooks)..."
$(Q)uv run --active pytest --nbmake tests/unit $(shell if [ -n "$(k)" ]; then echo "-k $(k)"; fi)
test-e2e: ## Run all end-to-end tests
@echo "Running all end-to-end tests..."
$(Q)uv run --active pytest --nbmake tests/e2e -s
# =============================================================================
# DOCUMENTATION
# =============================================================================
build-docs: ## Build all documentation
@echo "Building all documentation..."
@echo "Converting ipynb notebooks to md files..."
$(Q)MKDOCS_CI=true uv run python $(GIT_ROOT)/docs/ipynb_to_md.py
@echo "Building ragas documentation..."
$(Q)MKDOCS_CI=false uv run --group docs mkdocs build
check-pdf-deps: ## Check if WeasyPrint is properly installed with all dependencies
@echo "Checking if WeasyPrint is properly installed..."
@uv run --group docs-pdf python -c "import weasyprint; weasyprint.HTML(string='<h1>Test</h1>').write_pdf(target=None)" 2>/dev/null && \
echo "WeasyPrint is installed and all dependencies are available" || \
(echo ""; \
echo "WeasyPrint is not installed or has missing system dependencies"; \
echo ""; \
echo "Setup Instructions: https://doc.courtbouillon.org/weasyprint/stable/first_steps.html"; \
echo "Troubleshooting: https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#troubleshooting"; \
echo ""; \
exit 1)
check-mermaid-deps: ## Check Mermaid CLI is available and can render a diagram
@command -v node >/dev/null || (echo "Node.js is required for Mermaid PDF rendering"; exit 1)
@command -v mmdc >/dev/null || (echo "Missing 'mmdc' (Mermaid CLI). Mermaid diagrams in PDF depend on Mermaid CLI."; exit 1)
@tmp_dir="$$(mktemp -d)"; \
printf "graph TD\n A-->B\n" > "$$tmp_dir/diag.mmd"; \
mmdc -i "$$tmp_dir/diag.mmd" -o "$$tmp_dir/diag.svg" >/dev/null 2>&1 || \
(echo "Mermaid CLI found, but rendering failed (mmdc couldn't produce SVG)."; rm -rf "$$tmp_dir"; exit 1); \
test -s "$$tmp_dir/diag.svg" || \
(echo "Mermaid CLI ran but produced an empty SVG."; rm -rf "$$tmp_dir"; exit 1); \
rm -rf "$$tmp_dir"; \
echo "Mermaid CLI is installed and can render diagrams"
build-docs-pdf: check-pdf-deps check-mermaid-deps ## Build documentation with PDF export (requires WeasyPrint)
@echo "Building documentation with PDF export..."
$(Q)MKDOCS_CI=false ENABLE_PDF_EXPORT=1 uv run --group docs --group docs-pdf mkdocs build -f mkdocs-pdf.yml
@echo "PDF generated at: site/pdf/document.pdf"
serve-docs: ## Build and serve documentation locally
$(Q)MKDOCS_CI=false uv run --group docs mkdocs serve --dirtyreload