-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmake.dev
More file actions
357 lines (317 loc) Β· 16.7 KB
/
make.dev
File metadata and controls
357 lines (317 loc) Β· 16.7 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# Development workflow targets
# Migrated from app/Makefile for Phase 1 consolidation
# Load environment variables from .env if it exists
sinclude .env
export
# Development endpoint configuration
DEV_ENDPOINT ?= http://127.0.0.1:8001/mcp/
# Test results directory
RESULTS_DIR ?= build/test-results
.PHONY: test test-all test-unit test-catalog test-func test-func-platform test-e2e test-e2e-platform test-ci test-scripts test-mcp test-mcp-legacy test-mcp-docker test-docker-remote test-remote-docker run-docker-remote stop-docker-remote test-multiuser lint coverage coverage-results coverage-html run run-inspector kill dev-clean docker-check docker-build docker-run docker-test
# Directory targets
$(RESULTS_DIR):
@mkdir -p $(RESULTS_DIR)
# Test Targets
test:
@echo "Running unit tests (default)..."
@$(MAKE) test-unit
test-all: test-catalog | $(RESULTS_DIR)
@echo "Running all test phases with TUI..."
@export TEST_DOCKER_IMAGE=quilt-mcp:test && \
export QUILT_DISABLE_CACHE=true && \
export PYTHONPATH="src" && \
uv run --group test python scripts/test-runner.py
test-catalog:
@echo "Validating .env Quilt config matches quiltx..."
@ENV_CATALOG_URL=$${QUILT_CATALOG_URL:-} && \
if [ -z "$$ENV_CATALOG_URL" ]; then \
echo "β QUILT_CATALOG_URL missing from environment (.env?)"; \
exit 1; \
fi; \
QUILTX_OUTPUT="$$(uv run --group test python scripts/quilt_config_env.py)" && \
QUILT_CATALOG_URL="" && \
eval "$$QUILTX_OUTPUT" && \
QUILTX_CATALOG_URL=$$QUILT_CATALOG_URL && \
if [ "$$ENV_CATALOG_URL" != "$$QUILTX_CATALOG_URL" ]; then \
echo "β QUILT_CATALOG_URL mismatch"; \
echo " .env : $$ENV_CATALOG_URL"; \
echo " quiltx: $$QUILTX_CATALOG_URL"; \
exit 1; \
fi; \
echo "β
Quilt config matches quiltx"
test-ci: | $(RESULTS_DIR)
@echo "Running CI tests..."
@export PYTHONPATH="src" && uv run --group test python -m pytest tests/unit tests/func -v -m "not slow and not platform" --cov=quilt_mcp --cov-report=xml:$(RESULTS_DIR)/coverage-all.xml --cov-report=term-missing
test-unit: $(RESULTS_DIR)/coverage-unit.xml
$(RESULTS_DIR)/coverage-unit.xml: tests/unit/test_*.py | $(RESULTS_DIR)
@echo "Running unit tests only (fast, mocked)..."
@export PYTHONPATH="src" && uv run --group test python -m pytest tests/unit/ -v -s --cov=quilt_mcp --cov-report=xml:$(RESULTS_DIR)/coverage-unit.xml --cov-report=term-missing
test-func: test-catalog $(RESULTS_DIR)/coverage-func.xml
$(RESULTS_DIR)/coverage-func.xml: tests/func/test_*.py | $(RESULTS_DIR)
@echo "Running func tests (mocked)..."
@if [ -d "tests/func" ] && [ "$$(find tests/func -name "*.py" | wc -l)" -gt 0 ]; then \
export PYTHONPATH="src" && export PLATFORM_TEST_ENABLED=true && export TEST_BACKEND_MODE=$${TEST_BACKEND_MODE:-both} && uv run --group test python -m pytest tests/func/ -v -s --cov=quilt_mcp --cov-report=xml:$(RESULTS_DIR)/coverage-func.xml --cov-report=term-missing; \
else \
echo "No func tests found, creating empty coverage file..."; \
echo '<?xml version="1.0" ?><coverage></coverage>' > $(RESULTS_DIR)/coverage-func.xml; \
fi
test-func-platform: test-catalog
@echo "Running platform backend func tests..."
@export PYTHONPATH="src" && \
export PLATFORM_TEST_ENABLED=true && \
export TEST_BACKEND_MODE=platform && \
eval "$$(uv run --group test python scripts/quilt_config_env.py)" && \
uv run --group test python -m pytest tests/func/ -v
test-e2e: test-catalog $(RESULTS_DIR)/coverage-e2e.xml
test-e2e-platform: test-catalog
@echo "Running platform backend e2e tests..."
@if [ -d "tests/e2e" ] && [ "$$(find tests/e2e -name "*.py" | wc -l)" -gt 0 ]; then \
export PYTHONPATH="src" && \
export PLATFORM_TEST_ENABLED=true && \
export TEST_BACKEND_MODE=platform && \
eval "$$(uv run --group test python scripts/quilt_config_env.py)" && \
uv run --group test python -m pytest tests/e2e/ -v -m "not admin"; \
else \
echo "No e2e tests found"; \
fi
$(RESULTS_DIR)/coverage-e2e.xml: tests/e2e/test_*.py | $(RESULTS_DIR)
@echo "Running end-to-end workflow tests..."
@if [ -d "tests/e2e" ] && [ "$$(find tests/e2e -name "*.py" | wc -l)" -gt 0 ]; then \
export PYTHONPATH="src" && export PLATFORM_TEST_ENABLED=true && export TEST_BACKEND_MODE=$${TEST_BACKEND_MODE:-both} && uv run --group test python -m pytest tests/e2e/ -v -s -m "not admin" --cov=quilt_mcp --cov-report=xml:$(RESULTS_DIR)/coverage-e2e.xml --cov-report=term-missing; \
else \
echo "No e2e tests found, creating empty coverage file..."; \
echo '<?xml version="1.0" ?><coverage></coverage>' > $(RESULTS_DIR)/coverage-e2e.xml; \
fi
coverage: $(RESULTS_DIR)/coverage-analysis.csv coverage-results | $(RESULTS_DIR)
$(RESULTS_DIR)/coverage-analysis.csv: $(RESULTS_DIR)/coverage-unit.xml $(RESULTS_DIR)/coverage-func.xml $(RESULTS_DIR)/coverage-e2e.xml scripts/coverage_analysis.py | $(RESULTS_DIR)
@echo "Generating coverage analysis report..."
@export PYTHONPATH="src" && uv run --group test python scripts/coverage_analysis.py
coverage-results: $(RESULTS_DIR)/coverage-analysis.csv scripts/tests/coverage_required.yaml scripts/tests/test_coverage_analysis.py
@echo "Validating coverage thresholds..."
@export PYTHONPATH="src" && uv run --group test python scripts/tests/test_coverage_analysis.py || (echo "β Coverage thresholds not met! See scripts/tests/coverage_results.yaml for details" && exit 1)
@echo "β
Coverage validation passed - results in scripts/tests/coverage_results.yaml"
coverage-html:
@echo "Running tests with HTML coverage report..."
@export PYTHONPATH="src" && uv run --group test python -m pytest tests/ --cov=quilt_mcp --cov-report=html:htmlcov --cov-report=term-missing -v
@echo "β
HTML coverage report generated in htmlcov/"
@echo "π Open htmlcov/index.html in your browser to view the report"
test-scripts: coverage docker-check docker-build scripts/tests/test_*.py | $(RESULTS_DIR)
@echo "===πRunning script tests (coverage analysis, workflow behavior)..."
@if [ -d "scripts/tests" ] && [ "$$(find scripts/tests -name "test_*.py" | wc -l)" -gt 0 ]; then \
export PYTHONPATH="src" && uv run --group test python -m pytest scripts/tests/ -v; \
else \
echo "No script tests found"; \
fi
@echo "\n===π§ͺ Running MCP server tests (idempotent only)..."
@uv run --group test python scripts/tests/test_mcp.py --docker --image quilt-mcp:test
@echo "\n===β
Finished all script tests"
# MCP Server Testing Targets
# Refactored per spec/a18-mcp-test/10-mcp-refactor-phase1.md
# 10+ targets β 3 targets (one per deployment mode)
# Generate test config only when dependencies change (using platform backend)
TOOL_SOURCES := $(shell find src/quilt_mcp/tools -name "*.py" -type f 2>/dev/null)
scripts/tests/mcp-test.yaml: scripts/mcp-test-setup.py scripts/mcp-test.py $(TOOL_SOURCES) src/quilt_mcp/main.py
@echo "π§ Regenerating test configuration (sources changed)..."
@uv run --group test python scripts/mcp-test-setup.py
# Default - Platform backend, stdio transport (using consolidated mcp-test.py)
test-mcp: scripts/tests/mcp-test.yaml
@echo "===π§ͺ Running MCP server tests (platform backend, stdio)..."
@export TEST_BACKEND_MODE=platform && \
export FASTMCP_TRANSPORT=stdio && \
uv run --group test python scripts/mcp-test.py --spawn-local
# Legacy - Quilt3 backend, stdio transport (using consolidated mcp-test.py)
test-mcp-legacy: scripts/tests/mcp-test.yaml
@echo "===π§ͺ Running MCP server tests (quilt3 backend, stdio - LEGACY)..."
@export TEST_BACKEND_MODE=quilt3 && \
export FASTMCP_TRANSPORT=stdio && \
uv run --group test python scripts/mcp-test.py --spawn-local
# Production validation - Platform backend, HTTP+JWT, Docker
MCP_DOCKER_TOOLS ?= bucket_objects_list,admin_user_get,athena_query_validate,bucket_object_fetch,bucket_object_info,bucket_object_link,bucket_object_text,catalog_configure,catalog_uri,catalog_url,check_bucket_access,discover_permissions,generate_package_visualizations,generate_quilt_summarize_json,get_resource,package_browse,package_diff,search_explain,search_suggest,tabulator_tables_list
MCP_DOCKER_RESOURCES ?= all
MCP_DOCKER_LOOPS ?= none
test-mcp-docker: docker-build scripts/tests/mcp-test.yaml
@echo "===π§ͺ Running MCP server tests (platform backend, HTTP+JWT, Docker)..."
@export TEST_DOCKER_IMAGE=quilt-mcp:test && \
export TEST_BACKEND_MODE=platform && \
uv run --group test python scripts/docker_manager.py start \
--mode stateless \
--image $$TEST_DOCKER_IMAGE \
--name mcp-docker-test \
--port 8002 \
--jwt-secret "test-secret" && \
(uv run --group test python scripts/mcp-test.py http://localhost:8002/mcp \
--jwt \
--tools "$(MCP_DOCKER_TOOLS)" \
--resources "$(MCP_DOCKER_RESOURCES)" \
--loops "$(MCP_DOCKER_LOOPS)" \
--config scripts/tests/mcp-test.yaml && \
uv run --group test python scripts/docker_manager.py stop --name mcp-docker-test) || \
(uv run --group test python scripts/docker_manager.py stop --name mcp-docker-test && exit 1)
@echo "β
Docker testing completed"
# Remote Docker + ngrok workflow for Claude.ai testing (no OAuth yet)
# Usage:
# make run-docker-remote - Start Docker + Inspector + ngrok (DEFAULT)
# make run-docker-remote WITH_NGROK=0 - Start Docker + Inspector (local only)
# Default to WITH_NGROK=1 unless explicitly disabled
WITH_NGROK ?= 1
NGROK_DOMAIN ?= uniformly-alive-halibut.ngrok-free.app
LAUNCH_INSPECTOR ?= 1
run-docker-remote: docker-build
@echo "===π Starting remote Docker MCP server with fallback JWT..."
@# Validate required environment variables before starting
@if [ -z "$(QUILT_CATALOG_URL)" ]; then \
echo "β ERROR: QUILT_CATALOG_URL is not set"; \
echo " Set it in .env or run: quilt3 login"; \
exit 1; \
fi
@uv run --group test python scripts/docker_manager.py start \
--mode stateless \
--image quilt-mcp:test \
--name mcp-remote-ngrok \
--port 8000 \
--inject-fallback-jwt
@echo ""
@echo "β
Container running at http://localhost:8000/mcp"
@echo ""
@if [ "$(WITH_NGROK)" = "1" ]; then \
if command -v ngrok >/dev/null 2>&1; then \
echo "π Starting ngrok tunnel..."; \
pkill -f "ngrok http 8000" 2>/dev/null || true; \
ngrok http 8000 --domain=$(NGROK_DOMAIN) --log=stdout > /tmp/ngrok.log 2>&1 & \
sleep 3; \
echo ""; \
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββ"; \
echo "β
ngrok tunnel active at https://$(NGROK_DOMAIN)/mcp"; \
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββ"; \
echo ""; \
echo "π Configure Inspector UI (opens at http://localhost:6274):"; \
echo " 1. Transport Type: Select 'Streamable HTTP'"; \
echo " 2. URL: Enter 'https://$(NGROK_DOMAIN)/mcp'"; \
echo " 3. Connection Type: 'Direct'"; \
echo " 4. Click 'Connect'"; \
echo ""; \
echo "π§ For Claude Desktop, add to MCP config:"; \
echo " {"; \
echo " \"mcpServers\": {"; \
echo " \"quilt-remote\": {"; \
echo " \"url\": \"https://$(NGROK_DOMAIN)/mcp\""; \
echo " }"; \
echo " }"; \
echo " }"; \
echo ""; \
else \
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββ"; \
echo "β οΈ ngrok not found - install from https://ngrok.com"; \
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββ"; \
echo ""; \
echo "Or run manually in another terminal:"; \
echo " ngrok http 8000 --domain=$(NGROK_DOMAIN)"; \
echo ""; \
echo "π Configure Inspector UI (opens at http://localhost:6274):"; \
echo " 1. Transport Type: Select 'Streamable HTTP'"; \
echo " 2. URL: Enter 'http://localhost:8000/mcp' (local only)"; \
echo " 3. Connection Type: 'Direct'"; \
echo " 4. Click 'Connect'"; \
echo ""; \
fi; \
else \
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββ"; \
echo "π MCP Inspector Configuration (Local Only Mode)"; \
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββ"; \
echo ""; \
echo "π Configure Inspector UI (opens at http://localhost:6274):"; \
echo " 1. Transport Type: Select 'Streamable HTTP'"; \
echo " 2. URL: Enter 'http://localhost:8000/mcp'"; \
echo " 3. Connection Type: 'Direct'"; \
echo " 4. Click 'Connect'"; \
echo ""; \
echo "π‘ To enable ngrok remote access:"; \
echo " make stop-docker-remote"; \
echo " make run-docker-remote"; \
echo ""; \
fi
@if [ "$(LAUNCH_INSPECTOR)" = "1" ]; then \
command -v npx >/dev/null || (echo "Error: npx not found. Please install Node.js first." && exit 1); \
echo "β³ Launching Inspector..."; \
echo ""; \
npx @modelcontextprotocol/inspector; \
else \
echo "βοΈ Skipping Inspector launch (LAUNCH_INSPECTOR=0)"; \
fi
test-docker-remote: scripts/tests/mcp-test.yaml
@echo "===π§ͺ Running remote Docker MCP test against local endpoint..."
@$(MAKE) run-docker-remote WITH_NGROK=0 LAUNCH_INSPECTOR=0 && \
(echo "β³ Waiting for HTTP server to be ready..." && \
for i in 1 2 3 4 5 6 7 8 9 10; do \
if curl -sf http://localhost:8000/ >/dev/null 2>&1; then \
echo "β
Server is ready" && break; \
fi; \
echo " Attempt $$i/10: Server not ready yet, waiting..." && sleep 1; \
if [ $$i -eq 10 ]; then \
echo "β Server failed to become ready after 10 attempts" && \
$(MAKE) stop-docker-remote && exit 1; \
fi; \
done && \
uv run --group test python scripts/mcp-test.py http://localhost:8000/mcp \
--config scripts/tests/mcp-test.yaml \
--loops none && \
$(MAKE) stop-docker-remote) || \
($(MAKE) stop-docker-remote && exit 1)
@echo "β
Remote Docker local endpoint test completed"
test-remote-docker: test-docker-remote
stop-docker-remote:
@echo "Stopping Docker container..."
@uv run --group test python scripts/docker_manager.py stop --name mcp-remote-ngrok
@echo "Stopping Inspector..."
@pkill -f "@modelcontextprotocol/inspector" 2>/dev/null || echo "No MCP Inspector processes found"
@echo "Stopping ngrok..."
@pkill -f "ngrok http 8000" 2>/dev/null || echo "No ngrok processes found"
@echo "β
All processes stopped"
# Multiuser platform tests (pytest-based, unchanged)
test-multiuser:
@echo "Running multiuser platform tests..."
@export QUILT_MULTIUSER_MODE=true && \
export PYTHONPATH="src" && \
uv run --group test python -m pytest tests/func/test_multiuser.py -v
# Code Quality Targets
lint:
@echo "Running code linting and auto-fixing..."
@echo "Running ruff (format + lint) - auto-fixing..."
@uv run --group lint ruff format src/quilt_mcp/ tests/
@uv run --group lint ruff check --fix src/quilt_mcp/ tests/
@echo "Running mypy type checking..."
@uv run --group lint mypy src/quilt_mcp/ --show-error-codes --pretty
@echo "β
All linting completed"
# Development Server Targets
run:
@echo "Starting local MCP server..."
@echo "Server starting on $(DEV_ENDPOINT)"
@export PYTHONPATH="src" && uv run python src/main.py
run-inspector:
@echo "Launching MCP Inspector for visual testing..."
@command -v npx >/dev/null || (echo "Error: npx not found. Please install Node.js first." && exit 1)
@echo "Starting MCP Inspector with server at $(DEV_ENDPOINT)"
@echo "Inspector UI will be available at http://127.0.0.1:6274"
@export PYTHONPATH="src" && npx @modelcontextprotocol/inspector uv run python src/main.py
kill:
@echo "Killing running MCP server processes..."
@pkill -f "python.*main.py" 2>/dev/null || echo "No main.py processes found"
@pkill -f "python.*quilt_mcp" 2>/dev/null || echo "No quilt_mcp processes found"
@pkill -f "@modelcontextprotocol/inspector" 2>/dev/null || echo "No MCP Inspector processes found"
@lsof -ti :8000 | xargs -r kill 2>/dev/null || echo "No processes on port 8000"
@lsof -ti :8001 | xargs -r kill 2>/dev/null || echo "No processes on port 8001"
@echo "β
Server kill completed"
# Cleanup Targets
dev-clean:
@echo "Cleaning Python cache..."
@find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
@find . -type f -name "*.pyc" -delete 2>/dev/null || true
@echo "Cleaning test artifacts..."
@rm -rf $(RESULTS_DIR)/ .coverage .coverage.* htmlcov/ .pytest_cache/ 2>/dev/null || true
@find . -name "*.egg-info" -type d -exec rm -rf {} + 2>/dev/null || true
@echo "Cleaning build artifacts..."
@rm -rf build/ dist/ .ruff_cache/ 2>/dev/null || true
@find . -name ".DS_Store" -delete 2>/dev/null || true
@echo "Cleaning UV cache (for uvx test)..."
@rm -rf ~/.cache/uv/archive-v0/* 2>/dev/null || true
@echo "β
Development cleanup completed"