-
-
Notifications
You must be signed in to change notification settings - Fork 511
Expand file tree
/
Copy pathMakefile
More file actions
150 lines (124 loc) · 6.99 KB
/
Copy pathMakefile
File metadata and controls
150 lines (124 loc) · 6.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# Variables
LIBS := giskard-core giskard-llm giskard-agents giskard-checks giskard-scan
PACKAGE ?= # Optional package to test (e.g., giskard-core, giskard-agents, giskard-checks)
AGENT_NAME ?= # Optional, for setup-for-agents telemetry
REASON ?= # Optional, for setup-for-agents telemetry
# Default target
help: ## Show this help message
@echo "Available targets:"
@grep -E '^[a-zA-Z0-9_%-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
# Installation targets
install: ## Install project dependencies
uv sync
install-tools: ## Install development tools
uv tool install ruff
uv tool install vermin
uv tool install basedpyright
uv tool install pre-commit --with pre-commit-uv
pre-commit-install: ## Setup pre-commit hooks
uv tool run pre-commit install
setup: install install-tools pre-commit-install ## Complete development setup (install deps + tools)
setup-for-agents: setup ## Like setup + agent .env and analytics ping; optional AGENT_NAME= REASON=
@if ! grep -qE '^(export[[:space:]]+)?GISKARD_TELEMETRY_DISABLED=' .env 2>/dev/null; then \
echo "GISKARD_TELEMETRY_DISABLED=false" >> .env; \
fi
@AGENT_NAME="$(AGENT_NAME)" REASON="$(REASON)" uv run python -c "import json, os, urllib.request; from datetime import datetime, timezone; a=os.environ.get('AGENT_NAME','').strip(); r=os.environ.get('REASON','').strip(); p={**({'agent_name': a} if a else {}), **({'reason': r} if r else {})}; body=json.dumps({'api_key': 'phc_Asp36pe4X5WMqeJ4aMMV4gq5LGdGw69mdYSdEYGpbxm2', 'event': 'giskard_oss_agents_setup', 'distinct_id': a or 'giskard_oss_agent', 'properties': p, 'timestamp': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'}); urllib.request.urlopen(urllib.request.Request('https://eu.i.posthog.com/i/v0/e/', data=body.encode(), headers={'Content-Type': 'application/json'}, method='POST'), timeout=30)"
test: ## Run all tests (unit + functional), optional PACKAGE=<name>
ifdef PACKAGE
uv run pytest libs/$(PACKAGE)
else
uv run pytest libs/
endif
test-unit: ## Run unit tests only (excludes functional), optional PACKAGE=<name>
ifdef PACKAGE
uv run pytest libs/$(PACKAGE) -m "not functional"
else
$(foreach lib,$(LIBS),uv run pytest libs/$(lib) -m "not functional" &&) true
endif
test-functional: ## Run functional tests only (requires API keys), optional PACKAGE=<name> PROVIDER=<name>
ifdef PACKAGE
ifdef PROVIDER
uv run pytest libs/$(PACKAGE) -m "functional and $(PROVIDER)"
else
uv run pytest libs/$(PACKAGE) -m "functional"
endif
else
$(foreach lib,$(LIBS),uv run pytest libs/$(lib) -m "functional" &&) true
endif
install-no-providers: ## Install giskard-llm without provider SDKs (for no_providers tests)
uv sync --package giskard-llm
install-minimal: ## Install with test group only (no provider SDKs, all packages)
uv sync --only-group test
test-unit-minimal: ## Run unit tests on minimal deps (no provider SDKs), optional PACKAGE=<name>
ifdef PACKAGE
uv run pytest libs/$(PACKAGE) -m "not functional"
else
$(foreach lib,$(LIBS),uv run pytest libs/$(lib) -m "not functional" &&) true
endif
test-no-providers: ## Run tests that verify behavior when provider SDKs are missing
uv run pytest libs/giskard-llm -m "no_providers"
test-package-conflict: ## Test package conflict with giskard legacy package installed
@echo "Testing package conflict..."
@echo "Creating virtual environment..."
uv venv --seed -p 3.12 .venv-package-conflict
@echo "Installing giskard..."
.venv-package-conflict/bin/pip install giskard
@echo "Installing giskard-core..."
.venv-package-conflict/bin/pip install libs/giskard-core
@echo "Testing import giskard.core raises expected error..."
@ERROR_OUTPUT=$$(.venv-package-conflict/bin/python -c "import giskard.core" 2>&1) || true; \
echo "$$ERROR_OUTPUT" | grep -q "Package conflict detected: The legacy package 'giskard' is installed" || \
(echo "Error: Expected error message not found for 'import giskard.core'" && echo "Got: $$ERROR_OUTPUT" && exit 1)
@echo "Testing import giskard raises expected error..."
@ERROR_OUTPUT=$$(.venv-package-conflict/bin/python -c "import giskard" 2>&1) || true; \
echo "$$ERROR_OUTPUT" | grep -q "Package conflict detected: The legacy package 'giskard' is installed" || \
(echo "Error: Expected error message not found for 'import giskard'" && echo "Got: $$ERROR_OUTPUT" && exit 1)
@echo "✓ Package conflict test passed!"
rm -rf .venv-package-conflict
lint: ## Run linting checks
uv run ruff check .
format: ## Format code with ruff
uv run ruff format .
uv run ruff check --fix .
check-format: ## Check if code is formatted correctly
uv run ruff format --check .
check-compat: ## Check Python 3.12 compatibility
uv tool run vermin --target=3.12- --no-tips --violations .
typecheck: ## Run type checking with basedpyright
uv tool run basedpyright --level error .
security: ## Check for security vulnerabilities
uv run pip-audit --skip-editable
# Run licensecheck INSIDE the synced project env (uv run --with, not uvx): it reads
# each package's version from the installed env via importlib, so output is pinned to
# uv.lock instead of whatever PyPI resolves to at runtime. Pinned for reproducibility.
LICENSECHECK_VERSION := 2026.0.8
LICENSECHECK := uv run --with licensecheck==$(LICENSECHECK_VERSION) licensecheck --license MIT
# all-extras pulls in the provider extras' transitive deps; skip the workspace libs
# themselves (LIBS) so the notices list only third-party packages.
LICENSECHECK_FLAGS := --extras full --skip-dependencies $(LIBS)
# licensecheck markdown output is not byte-stable (trailing whitespace, blank-line
# runs), so canonicalize it before writing/diffing: strip trailing whitespace and
# collapse consecutive blank lines.
NORMALIZE := sed -e 's/[[:space:]]*$$//' | awk '/^$$/{blank++; next} {for(i=0;i<blank;i++) print ""; blank=0; print}'
generate-notices: ## Generate THIRD_PARTY_NOTICES.md
$(LICENSECHECK) $(LICENSECHECK_FLAGS) \
--format markdown --hide-output-parameters SIZE --file /dev/stdout \
| $(NORMALIZE) > THIRD_PARTY_NOTICES.md
check-licenses: ## Check for licenses
$(LICENSECHECK) $(LICENSECHECK_FLAGS) --show-only-failing --zero
check-notices: ## Check that THIRD_PARTY_NOTICES.md is up to date (run make generate-notices if this fails)
@TMPFILE=$$(mktemp); trap 'rm -f "$$TMPFILE"' EXIT; \
$(LICENSECHECK) $(LICENSECHECK_FLAGS) \
--format markdown --hide-output-parameters SIZE --file /dev/stdout \
| $(NORMALIZE) > $$TMPFILE && \
if ! diff $$TMPFILE THIRD_PARTY_NOTICES.md; then \
echo "THIRD_PARTY_NOTICES.md is out of date. Run: make generate-notices"; \
exit 1; \
fi
check: lint check-format check-compat typecheck security check-licenses check-notices ## Run all checks
clean: ## Clean up build artifacts and caches
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true
rm -rf build/ dist/ .coverage htmlcov/