-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathMakefile
More file actions
362 lines (326 loc) · 15.4 KB
/
Makefile
File metadata and controls
362 lines (326 loc) · 15.4 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
358
359
360
361
362
IMAGE_NAME := ghcr.io/thevibeworks/deva
TAG := latest
RUST_TAG := rust
CORE_TAG := core
DOCKERFILE := Dockerfile
RUST_DOCKERFILE := Dockerfile.rust
MAIN_IMAGE := $(IMAGE_NAME):$(TAG)
RUST_IMAGE := $(IMAGE_NAME):$(RUST_TAG)
CORE_IMAGE := $(IMAGE_NAME):$(CORE_TAG)
CONTAINER_NAME := deva-$(shell basename $(PWD))-$(shell date +%s)
# Smart image detection: auto-detect available image for version checking
# Prefers rust (superset of base) then falls back to latest
DETECTED_IMAGE := $(shell \
if docker image inspect $(IMAGE_NAME):$(RUST_TAG) >/dev/null 2>&1; then \
echo "$(IMAGE_NAME):$(RUST_TAG)"; \
elif docker image inspect $(IMAGE_NAME):$(TAG) >/dev/null 2>&1; then \
echo "$(IMAGE_NAME):$(TAG)"; \
else \
echo "$(IMAGE_NAME):$(TAG)"; \
fi)
CLAUDE_CODE_VERSION := $(shell npm view @anthropic-ai/claude-code version 2>/dev/null || echo "2.1.81")
CODEX_VERSION := $(shell npm view @openai/codex version 2>/dev/null || echo "0.116.0")
GEMINI_CLI_VERSION := $(shell npm view @google/gemini-cli version 2>/dev/null || echo "0.35.0")
ATLAS_CLI_VERSION := $(shell gh api repos/lroolle/atlas-cli/releases/latest --jq '.tag_name' 2>/dev/null || echo "v0.1.4")
COPILOT_API_VERSION := $(shell gh api repos/ericc-ch/copilot-api/branches/master --jq '.commit.sha' 2>/dev/null || echo "0ea08febdd7e3e055b03dd298bf57e669500b5c1")
export DOCKER_BUILDKIT := 1
.DEFAULT_GOAL := help
.PHONY: build
build: build-all
.PHONY: build-main
build-main:
@echo "🔨 Building Docker image with $(DOCKERFILE)..."
@if command -v npm >/dev/null 2>&1; then \
echo "🔎 Resolving latest versions from npm..."; \
else \
echo "ℹ npm not found; using defaults/fallbacks"; \
fi
@# Inspect existing image labels; print direct diff lines
@prev_claude=$$(docker inspect --format='{{ index .Config.Labels "org.opencontainers.image.claude_code_version" }}' $(MAIN_IMAGE) 2>/dev/null || true); \
prev_codex=$$(docker inspect --format='{{ index .Config.Labels "org.opencontainers.image.codex_version" }}' $(MAIN_IMAGE) 2>/dev/null || true); \
prev_gemini=$$(docker inspect --format='{{ index .Config.Labels "org.opencontainers.image.gemini_cli_version" }}' $(MAIN_IMAGE) 2>/dev/null || true); \
fmt() { v="$$1"; if [ -z "$$v" ] || [ "$$v" = "<no value>" ]; then echo "-"; else case "$$v" in v*) echo "$$v";; *) echo "v$$v";; esac; fi; }; \
curC=$$(fmt "$$prev_claude"); curX=$$(fmt "$$prev_codex"); curG=$$(fmt "$$prev_gemini"); \
tgtC=$$(fmt "$(CLAUDE_CODE_VERSION)"); tgtX=$$(fmt "$(CODEX_VERSION)"); tgtG=$$(fmt "$(GEMINI_CLI_VERSION)"); \
if [ "$$curC" = "$$tgtC" ] && [ "$$curX" = "$$tgtX" ] && [ "$$curG" = "$$tgtG" ]; then \
echo "Claude: $$tgtC (no change)"; \
echo "Codex: $$tgtX (no change)"; \
echo "Gemini: $$tgtG (no change)"; \
echo "Already up-to-date"; \
else \
if [ "$$curC" = "$$tgtC" ]; then \
echo "Claude: $$tgtC (no change)"; \
else \
echo "Claude: $$curC -> $$tgtC"; \
fi; \
if [ "$$curX" = "$$tgtX" ]; then \
echo "Codex: $$tgtX (no change)"; \
else \
echo "Codex: $$curX -> $$tgtX"; \
fi; \
if [ "$$curG" = "$$tgtG" ]; then \
echo "Gemini: $$tgtG (no change)"; \
else \
echo "Gemini: $$curG -> $$tgtG"; \
fi; \
fi
@echo "Hint: override via CLAUDE_CODE_VERSION=... CODEX_VERSION=... GEMINI_CLI_VERSION=... ATLAS_CLI_VERSION=... COPILOT_API_VERSION=... or run 'make bump-versions' to pin"
docker build -f $(DOCKERFILE) --build-arg CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) --build-arg CODEX_VERSION=$(CODEX_VERSION) --build-arg GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) --build-arg ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) --build-arg COPILOT_API_VERSION=$(COPILOT_API_VERSION) -t $(MAIN_IMAGE) .
@echo "✅ Build completed: $(MAIN_IMAGE)"
.PHONY: rebuild
rebuild:
@echo "🔨 Rebuilding Docker image (no cache) with $(DOCKERFILE)..."
docker build -f $(DOCKERFILE) --no-cache --build-arg CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) --build-arg CODEX_VERSION=$(CODEX_VERSION) --build-arg GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) --build-arg ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) --build-arg COPILOT_API_VERSION=$(COPILOT_API_VERSION) -t $(MAIN_IMAGE) .
@echo "✅ Rebuild completed: $(MAIN_IMAGE)"
.PHONY: build-core
build-core:
@echo "🔨 Building stable core image..."
docker build -f $(DOCKERFILE) --target agent-base --build-arg COPILOT_API_VERSION=$(COPILOT_API_VERSION) -t $(CORE_IMAGE) .
@echo "✅ Core build completed: $(CORE_IMAGE)"
.PHONY: build-rust-image
build-rust-image:
@echo "🔨 Building Rust Docker image..."
docker build -f $(RUST_DOCKERFILE) \
--build-arg BASE_IMAGE=$(CORE_IMAGE) \
--build-arg CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) \
--build-arg CODEX_VERSION=$(CODEX_VERSION) \
--build-arg GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) \
--build-arg ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) \
-t $(RUST_IMAGE) .
@echo "✅ Rust build completed: $(RUST_IMAGE)"
.PHONY: build-rust
build-rust: build-core build-rust-image
.PHONY: build-all
build-all:
@echo "🔨 Building all images with versions: Claude $(CLAUDE_CODE_VERSION), Codex $(CODEX_VERSION), Gemini $(GEMINI_CLI_VERSION), Atlas $(ATLAS_CLI_VERSION), Copilot-API $(COPILOT_API_VERSION)..."
@$(MAKE) build-core COPILOT_API_VERSION=$(COPILOT_API_VERSION)
@$(MAKE) build-main CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) CODEX_VERSION=$(CODEX_VERSION) GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) COPILOT_API_VERSION=$(COPILOT_API_VERSION)
@$(MAKE) build-rust-image CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) CODEX_VERSION=$(CODEX_VERSION) GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) COPILOT_API_VERSION=$(COPILOT_API_VERSION)
@echo "✅ All images built successfully"
.PHONY: buildx
buildx:
@echo "🔨 Building with docker buildx..."
docker buildx build -f $(DOCKERFILE) --load --build-arg CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) --build-arg CODEX_VERSION=$(CODEX_VERSION) --build-arg GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) --build-arg ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) --build-arg COPILOT_API_VERSION=$(COPILOT_API_VERSION) -t $(MAIN_IMAGE) .
@echo "✅ Buildx completed: $(MAIN_IMAGE)"
.PHONY: buildx-multi
buildx-multi:
@echo "🔨 Building multi-arch images for amd64 and arm64..."
docker buildx build -f $(DOCKERFILE) --platform linux/amd64,linux/arm64 \
--build-arg CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) \
--build-arg CODEX_VERSION=$(CODEX_VERSION) \
--build-arg GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) \
--build-arg ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) \
--build-arg COPILOT_API_VERSION=$(COPILOT_API_VERSION) \
--push -t $(MAIN_IMAGE) .
@echo "✅ Multi-arch build completed and pushed: $(MAIN_IMAGE)"
.PHONY: buildx-multi-rust
buildx-multi-rust:
@echo "🔨 Building multi-arch Rust images for amd64 and arm64..."
docker buildx build -f $(RUST_DOCKERFILE) --platform linux/amd64,linux/arm64 \
--build-arg BASE_IMAGE=$(MAIN_IMAGE) \
--push -t $(RUST_IMAGE) .
@echo "✅ Multi-arch Rust build completed and pushed: $(RUST_IMAGE)"
.PHONY: buildx-multi-local
buildx-multi-local:
@echo "🔨 Building multi-arch images locally..."
docker buildx build --platform linux/amd64,linux/arm64 \
--build-arg CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) \
--build-arg CODEX_VERSION=$(CODEX_VERSION) \
--build-arg GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) \
--build-arg ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) \
--build-arg COPILOT_API_VERSION=$(COPILOT_API_VERSION) \
-t $(MAIN_IMAGE) .
@echo "✅ Multi-arch build completed locally: $(MAIN_IMAGE)"
.PHONY: versions-up
versions-up:
@MAIN_IMAGE=$(DETECTED_IMAGE) \
BUILD_IMAGE=$(MAIN_IMAGE) \
RUST_IMAGE=$(RUST_IMAGE) \
DOCKERFILE=$(DOCKERFILE) \
RUST_DOCKERFILE=$(RUST_DOCKERFILE) \
CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) \
CODEX_VERSION=$(CODEX_VERSION) \
GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) \
ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) \
COPILOT_API_VERSION=$(COPILOT_API_VERSION) \
./scripts/version-upgrade.sh
.PHONY: versions
versions:
@CLAUDE_CODE_VERSION=$(CLAUDE_CODE_VERSION) \
CODEX_VERSION=$(CODEX_VERSION) \
GEMINI_CLI_VERSION=$(GEMINI_CLI_VERSION) \
ATLAS_CLI_VERSION=$(ATLAS_CLI_VERSION) \
COPILOT_API_VERSION=$(COPILOT_API_VERSION) \
MAIN_IMAGE=$(DETECTED_IMAGE) \
./scripts/version-report.sh
.PHONY: clean
clean:
@echo "🧹 Aggressive Docker cleanup..."
@echo "Removing project images..."
-docker rmi $(MAIN_IMAGE) 2>/dev/null || true
-docker rmi $(RUST_IMAGE) 2>/dev/null || true
-docker rmi $(CORE_IMAGE) 2>/dev/null || true
@echo "Pruning stopped containers..."
-docker container prune -f
@echo "Pruning unused images..."
-docker image prune -f
@echo "Pruning unused networks..."
-docker network prune -f
@echo "Pruning build cache..."
-docker builder prune -f
@echo "✅ Cleanup completed"
.PHONY: clean-all
clean-all:
@echo "🧹 NUCLEAR: Removing ALL unused Docker resources..."
@echo "WARNING: This will remove ALL unused containers, images, networks, and volumes"
@echo "Press Ctrl+C within 3 seconds to cancel..."
@sleep 3
@echo "Removing project images..."
-docker rmi $(MAIN_IMAGE) 2>/dev/null || true
-docker rmi $(RUST_IMAGE) 2>/dev/null || true
-docker rmi $(CORE_IMAGE) 2>/dev/null || true
@echo "Removing ALL stopped containers..."
-docker container prune -af
@echo "Removing ALL dangling and unused images..."
-docker image prune -af
@echo "Removing ALL unused networks..."
-docker network prune -f
@echo "Removing ALL unused volumes..."
-docker volume prune -af
@echo "Removing ALL build cache..."
-docker builder prune -af
@echo "Final system prune..."
-docker system prune -af --volumes
@df -h | grep -E '(Filesystem|/var/lib/docker|overlay)' 2>/dev/null || echo "Docker storage info not available"
@echo "✅ Nuclear cleanup completed"
.PHONY: shell
shell:
@echo "🐚 Opening shell in $(MAIN_IMAGE)..."
docker run --rm -it \
-v $(PWD):$(PWD) \
-w $(PWD) \
--name $(CONTAINER_NAME) \
$(MAIN_IMAGE) /bin/zsh
.PHONY: test
test:
@echo "🧪 Testing $(MAIN_IMAGE)..."
@echo "Testing claude command..."
docker run --rm $(MAIN_IMAGE) claude --version
@echo "Testing development tools..."
docker run --rm $(MAIN_IMAGE) bash -c 'python --version && node --version && go version'
@echo "✅ All tests passed"
.PHONY: test-rust
test-rust:
@echo "🧪 Testing $(RUST_IMAGE)..."
@echo "Testing Rust toolchain..."
docker run --rm $(RUST_IMAGE) bash -c 'rustc --version && cargo --version && rustfmt --version && clippy-driver --version'
@echo "Testing Rust tools..."
docker run --rm $(RUST_IMAGE) bash -c 'cargo-watch --version && wasm-pack --version'
@echo "✅ Rust tests passed"
.PHONY: test-local
test-local:
@echo "🧪 Testing $(MAIN_IMAGE) with local directory..."
docker run --rm -it \
-v $(PWD):$(PWD) \
-w $(PWD) \
$(MAIN_IMAGE) bash -c 'pwd && ls -la && claude --version'
.PHONY: info
info:
@echo "📊 Image information for $(MAIN_IMAGE):"
@docker images $(MAIN_IMAGE) --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}"
@echo ""
@echo "🔍 Image layers:"
@docker history $(MAIN_IMAGE) --no-trunc
.PHONY: push
push:
@echo "📤 Pushing $(MAIN_IMAGE) to registry..."
docker push $(MAIN_IMAGE)
@echo "✅ Push completed"
.PHONY: pull
pull:
@echo "📥 Pulling $(MAIN_IMAGE) from registry..."
docker pull $(MAIN_IMAGE)
@echo "✅ Pull completed"
.PHONY: build-test
build-test: build test
@echo "✅ Build and test completed successfully"
.PHONY: dev
dev: build shell
.PHONY: context-size
context-size:
@echo "📏 Build context size:"
@du -sh . --exclude='.git' --exclude='node_modules' --exclude='.claude-trace'
.PHONY: lint
lint:
@echo "🔍 Linting Dockerfile..."
@if command -v hadolint >/dev/null 2>&1; then \
hadolint Dockerfile; \
echo "✅ Dockerfile linting completed"; \
else \
echo "⚠️ hadolint not found. Install with: brew install hadolint"; \
echo " Or run in Docker: docker run --rm -i hadolint/hadolint < Dockerfile"; \
fi
.PHONY: version-check
version-check:
@./scripts/version-check.sh
.PHONY: release-patch
release-patch:
@./deva.sh claude -Q -- -p "Execute release workflow from @workflows/RELEASE.md for a **patch** release"
.PHONY: release-minor
release-minor:
@./deva.sh claude -Q -- -p "Execute release workflow from @workflows/RELEASE.md for a **minor** release"
.PHONY: release-major
release-major:
@./deva.sh claude -Q -- -p "Execute release workflow from @workflows/RELEASE.md for a **major** release"
.PHONY: help
help:
@echo "deva.sh - Docker Build Shortcuts"
@echo "==============================="
@echo ""
@echo "Usage: make [target]"
@echo ""
@echo "Available targets:"
@echo " build Build all images (auto-detects latest npm versions)"
@echo " build-core Build stable core image only"
@echo " build-main Build main Docker image only"
@echo " build-rust Build Rust Docker image"
@echo " build-all Build all images (main + rust)"
@echo " rebuild Rebuild without cache"
@echo " buildx Build with buildx"
@echo " buildx-multi Build multi-arch and push"
@echo " buildx-multi-rust Build multi-arch Rust and push"
@echo " versions Compare built vs latest versions with changelogs"
@echo " versions-up Upgrade both images to latest npm versions"
@echo " test Test main image"
@echo " test-rust Test Rust image"
@echo " shell Open shell in container"
@echo " clean Aggressive cleanup (unused containers/images/networks/cache)"
@echo " clean-all NUCLEAR cleanup (ALL unused Docker resources + volumes)"
@echo " push Push image to registry"
@echo " pull Pull image from registry"
@echo " info Show image information"
@echo " lint Lint Dockerfile"
@echo ""
@echo "Environment variables:"
@echo " IMAGE_NAME Main image name (default: $(IMAGE_NAME))"
@echo " TAG Docker image tag (default: $(TAG))"
@echo " RUST_TAG Rust image tag (default: $(RUST_TAG))"
@echo " CORE_TAG Stable core image tag (default: $(CORE_TAG))"
@echo " DOCKERFILE Dockerfile to use (default: $(DOCKERFILE))"
@echo " RUST_DOCKERFILE Rust Dockerfile path (default: $(RUST_DOCKERFILE))"
@echo " CLAUDE_CODE_VERSION Claude CLI version (default: $(CLAUDE_CODE_VERSION))"
@echo " CODEX_VERSION Codex CLI version (default: $(CODEX_VERSION))"
@echo " GEMINI_CLI_VERSION Gemini CLI version (default: $(GEMINI_CLI_VERSION))"
@echo " ATLAS_CLI_VERSION Atlas CLI version (default: $(ATLAS_CLI_VERSION))"
@echo ""
@echo "Examples:"
@echo " make build # Build all images with latest versions"
@echo " make build-core # Build stable core image only"
@echo " make build-main # Build main image only"
@echo " make build-rust # Build Rust image only"
@echo " make TAG=dev build # Build all with custom tag"
@echo " make CLAUDE_CODE_VERSION=2.0.5 build # Override with specific version"
@echo " make GEMINI_CLI_VERSION=0.18.0 build # Override gemini version"
@echo " make ATLAS_CLI_VERSION=5f6a20c build # Pin atlas-cli to specific commit"
@echo " make versions # Check current versions"
@echo " make versions-up # Upgrade to latest (includes atlas-cli)"