-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmake.deploy
More file actions
230 lines (195 loc) · 9.69 KB
/
make.deploy
File metadata and controls
230 lines (195 loc) · 9.69 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
# Production/packaging targets
# MCPB packaging system
# Paths
APP_DIR := src
ASSETS_DIR := src/deploy
BUILD_DIR := build
BUILD_PKGS_DIR := $(BUILD_DIR)/lib
DIST_DIR := dist
# Variables
PACKAGE_NAME := quilt-mcp
export DOCKER_IMAGE_NAME := quiltdata/mcp
# CI AWS account for Docker validation (different from local account)
CI_ACCOUNT := 850787717197
CI_REGION := us-east-1
CI_REGISTRY := $(CI_ACCOUNT).dkr.ecr.$(CI_REGION).amazonaws.com
# Allow VERSION to be overridden from command line, otherwise read from pyproject.toml
MANIFEST_VERSION := $(shell python3 scripts/version.py get-version 2>/dev/null || echo "dev")
PACKAGE_VERSION := $(if $(VERSION),$(VERSION),$(MANIFEST_VERSION))
PACKAGE_ID := $(DIST_DIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
MCPB_PACKAGE := $(PACKAGE_ID).mcpb
RELEASE_ZIP := $(PACKAGE_ID)-release.zip
# Source file dependencies
ASSET_FILES := $(wildcard $(ASSETS_DIR)/*)
APP_FILES := $(shell find $(APP_DIR)/quilt_mcp -name "*.py" 2>/dev/null || true)
.PHONY: deploy-build mcpb mcpb-validate python-dist python-publish release-zip deploy-clean check-tools docker-check docker-build docker-rebuild docker-push docker-push-dev docker-validate docker-tools
# Check for required tools
check-tools:
@command -v npx >/dev/null 2>&1 || { echo "❌ npx not found - install Node.js"; exit 1; }
@command -v uv >/dev/null 2>&1 || { echo "❌ uv not found - install uv package manager"; exit 1; }
@command -v mcpb >/dev/null 2>&1 || { echo "❌ mcpb not found - run: npm install -g @anthropic-ai/mcpb"; exit 1; }
@echo "✅ All required tools found"
# Build Environment Preparation
deploy-build: check-tools
@echo "Preparing production build environment..."
@$(MAKE) -f make.deploy mcpb-build-contents
@echo "✅ Build environment ready"
# Intermediate targets for incremental builds
# MCPB assets (only manifest, icon, README needed)
mcpb-assets: $(ASSET_FILES)
@echo "Preparing MCPB assets..."
@mkdir -p $(BUILD_DIR)/mcpb
@echo "Generating manifest.json from template..."
@sed 's/{{ version }}/$(PACKAGE_VERSION)/g' $(ASSETS_DIR)/manifest.json.j2 > $(BUILD_DIR)/mcpb/manifest.json
@echo "Copying icon and documentation..."
@cp $(ASSETS_DIR)/icon.png $(BUILD_DIR)/mcpb/
@cp $(ASSETS_DIR)/README.md $(BUILD_DIR)/mcpb/
@echo "✅ MCPB assets prepared"
# MCPB simplified build (no source code copying needed)
mcpb-build-contents: mcpb-assets
@echo "✅ MCPB build contents prepared"
# MCPB Package Creation
$(MCPB_PACKAGE): mcpb-build-contents
@echo "Packing with MCPB CLI..."
@mkdir -p $(DIST_DIR)
@mcpb pack $(BUILD_DIR)/mcpb $(MCPB_PACKAGE)
@echo "✅ Built $(MCPB_PACKAGE)"
mcpb: $(MCPB_PACKAGE)
@echo "✅ MCPB package created: $(MCPB_PACKAGE)"
# Python Package Distribution
python-dist: check-tools
@echo "🚀 Building Python artifacts..."
@mkdir -p $(DIST_DIR)
@uv sync --group dev
@uv run python -m build --wheel --sdist --outdir $(DIST_DIR)
@echo "✅ Python packaging complete"
python-publish:
@./scripts/release.sh python-publish
# MCPB Package Validation
mcpb-validate: check-tools mcpb
@echo "===🔍 Comprehensive MCPB package validation..."
@echo "\n1. Validating with MCPB CLI..."
@mcpb info $(MCPB_PACKAGE)
@echo "\n2. Validating generated manifest.json..."
@mcpb validate $(BUILD_DIR)/mcpb/manifest.json
@echo "\n3. Validating package structure..."
@test -f $(BUILD_DIR)/mcpb/manifest.json || { echo "❌ manifest.json missing"; exit 1; }
@test -f $(BUILD_DIR)/mcpb/icon.png || { echo "❌ icon.png missing"; exit 1; }
@test -f $(BUILD_DIR)/mcpb/README.md || { echo "❌ README.md missing"; exit 1; }
@echo "✅ Package structure validation passed"
@echo "\n4. Validating manifest content..."
@grep -q '"name": "quilt-mcp"' $(BUILD_DIR)/mcpb/manifest.json || { echo "❌ Invalid name in manifest"; exit 1; }
@grep -q '"version": "$(PACKAGE_VERSION)"' $(BUILD_DIR)/mcpb/manifest.json || { echo "❌ Invalid version in manifest"; exit 1; }
@grep -q '"entry_point": "uvx"' $(BUILD_DIR)/mcpb/manifest.json || { echo "❌ Invalid entry_point in manifest"; exit 1; }
@grep -q '"args": \["quilt-mcp"\]' $(BUILD_DIR)/mcpb/manifest.json || { echo "❌ Invalid args in manifest"; exit 1; }
@echo "✅ Manifest content validation passed"
@echo "\n5. Testing UVX execution from unpacked MCPB..."
@rm -rf /tmp/mcpb-test && mkdir -p /tmp/mcpb-test
@mcpb unpack $(MCPB_PACKAGE) /tmp/mcpb-test >/dev/null 2>&1
@cd /tmp/mcpb-test && timeout 3 uvx --no-cache quilt-mcp >/dev/null 2>&1; \
EXIT_CODE=$$?; \
if [ $$EXIT_CODE -eq 124 ]; then \
echo "✅ UVX execution test passed (server started successfully from unpacked MCPB)"; \
else \
echo "❌ UVX execution test failed (exit code $$EXIT_CODE - server crashed or failed to start)"; \
exit 1; \
fi
@rm -rf /tmp/mcpb-test
@echo "\n6. Running prerequisites validation..."
@bash $(ASSETS_DIR)/check-mcpb.sh >/dev/null 2>&1 || { echo "❌ Prerequisites validation failed"; exit 1; }
@echo "✅ Prerequisites validation passed"
@echo "\n===✅ Comprehensive MCPB package validation passed"
# Release Bundle Creation
$(RELEASE_ZIP): mcpb-validate $(ASSETS_DIR)/README.md $(ASSETS_DIR)/check-mcpb.sh
@echo "Creating release bundle..."
@mkdir -p $(DIST_DIR)/release
@cp $(MCPB_PACKAGE) $(DIST_DIR)/release/
@cp $(ASSETS_DIR)/README.md $(DIST_DIR)/release/
@cp $(ASSETS_DIR)/check-mcpb.sh $(DIST_DIR)/release/
@cd $(DIST_DIR)/release && zip -r ../$(PACKAGE_NAME)-$(PACKAGE_VERSION)-release.zip .
@rm -rf $(DIST_DIR)/release
@echo "✅ Built $(RELEASE_ZIP)"
release-zip: $(RELEASE_ZIP)
@echo "✅ Release bundle $(RELEASE_ZIP) ready for distribution"
# Docker Operations
# Minimal check for local builds (no AWS/ECR setup)
docker-check:
@command -v docker >/dev/null 2>&1 || { echo "❌ Docker not found - install Docker"; exit 1; }
@docker info >/dev/null 2>&1 || { echo "❌ Docker daemon not running or not accessible"; exit 1; }
@echo "✅ Docker available"
# Full ECR tooling (only needed for push operations)
docker-tools: docker-check
@echo "🔍 Detecting AWS account..."
@AWS_ACCOUNT_ID=$$(aws sts get-caller-identity --query Account --output text) && \
AWS_REGION=$${AWS_DEFAULT_REGION:-us-east-1} && \
echo "✅ Using AWS account: $$AWS_ACCOUNT_ID (region: $$AWS_REGION)" && \
echo "🔍 Checking ECR repository..." && \
aws ecr describe-repositories --repository-names $(DOCKER_IMAGE_NAME) --region $$AWS_REGION >/dev/null 2>&1 || \
{ echo "📦 Creating ECR repository..." && aws ecr create-repository --repository-name $(DOCKER_IMAGE_NAME) --region $$AWS_REGION >/dev/null; } && \
echo "✅ ECR repository ready" && \
echo "🔓 Setting repository to public read..." && \
aws ecr set-repository-policy --repository-name $(DOCKER_IMAGE_NAME) --region $$AWS_REGION --policy-text '{"Version":"2012-10-17","Statement":[{"Sid":"AllowPublicRead","Effect":"Allow","Principal":"*","Action":["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]}' >/dev/null 2>&1 || \
echo "⚠️ Warning: Could not set public read policy (may already be set or insufficient permissions)" && \
echo "🔐 Authenticating with ECR..." && \
aws ecr get-login-password --region $$AWS_REGION | docker login --username AWS --password-stdin $$AWS_ACCOUNT_ID.dkr.ecr.$$AWS_REGION.amazonaws.com >/dev/null 2>&1 && \
echo "✅ ECR authentication successful"
# Docker image build with dependency tracking
DOCKER_SENTINEL := $(BUILD_DIR)/.docker-build-test
DOCKER_DEPS := Dockerfile pyproject.toml uv.lock $(APP_FILES)
$(DOCKER_SENTINEL): $(DOCKER_DEPS) | docker-check
@echo "🐳 Building Docker image (source files changed)..."
@mkdir -p $(BUILD_DIR)
@uv run python scripts/docker_manager.py build --version test
@touch $(DOCKER_SENTINEL)
@echo "✅ Docker build completed"
docker-build: $(DOCKER_SENTINEL)
@echo "✅ Docker image up to date (use 'make docker-rebuild' to force rebuild)"
# Force rebuild (bypass cache)
docker-rebuild: docker-check
@echo "🔄 Force rebuilding Docker image..."
@rm -f $(DOCKER_SENTINEL)
@$(MAKE) docker-build
docker-push: docker-tools
@echo "🐳 Building and pushing Docker image..."
@GIT_SHA=$$(git rev-parse --short=8 HEAD 2>/dev/null || echo "unknown") && \
echo "Using git SHA: $$GIT_SHA" && \
VERSION=$(PACKAGE_VERSION) GIT_SHA=$$GIT_SHA uv run python scripts/docker_manager.py push --version $(PACKAGE_VERSION) --git-sha $$GIT_SHA
@echo "✅ Docker push completed"
docker-push-dev: docker-tools
@echo "🐳 Building and pushing development Docker image..."
@GIT_SHA=$$(git rev-parse --short=8 HEAD 2>/dev/null || echo "unknown") && \
DEV_VERSION="$(PACKAGE_VERSION)-dev-$(shell date +%Y%m%d%H%M%S)" && \
echo "Using development version: $$DEV_VERSION" && \
echo "Using git SHA: $$GIT_SHA" && \
VERSION=$$DEV_VERSION GIT_SHA=$$GIT_SHA uv run python scripts/docker_manager.py push --version $$DEV_VERSION --git-sha $$GIT_SHA --no-latest
@echo "✅ Development Docker push completed"
docker-validate:
@echo "🔍 Validating Docker images in CI registry (public read)..."
@echo "Using CI registry: $(CI_REGISTRY)"
@uv run python scripts/docker_manager.py validate --registry $(CI_REGISTRY) --no-latest --skip-auth
@echo "✅ Docker validation completed"
# Release Tagging Targets
release-tag:
@echo "Pulling latest changes from remote..."
@git pull
@echo "Creating release tag..."
@if [ "${DRY_RUN}" = "1" ]; then \
echo "🔍 DRY RUN: Would create release tag"; \
./scripts/release.sh release --dry-run; \
else \
./scripts/release.sh release; \
fi
release-dev-tag:
@echo "Creating development tag..."
@if [ "${DRY_RUN}" = "1" ]; then \
echo "🔍 DRY RUN: Would create development tag"; \
./scripts/release.sh dev --dry-run; \
else \
./scripts/release.sh dev; \
fi
# Cleanup Targets
deploy-clean:
@echo "Cleaning build artifacts..."
@rm -rf $(BUILD_DIR) $(DIST_DIR)
@rm -f *.mcpb # Clean MCPB packages from root
@echo "✅ Deploy cleanup completed"