-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathMakefile
More file actions
478 lines (412 loc) · 17.1 KB
/
Copy pathMakefile
File metadata and controls
478 lines (412 loc) · 17.1 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
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
.PHONY: build install test test-go test-js check-model-tags check-stderr-patterns test-integration test-integration-go test-integration-cli test-integration-api test-integration-client test-ui test-ui-headed test-ui-debug test-ui-report test-all test-ci test-setup test-clean clean run fmt fmt-check fmt-docs fmt-docs-check lint lint-go lint-frontend deps-go deps-js deps tailwind vendor-codemirror build-mac-app clean-mac-app test-webviewlog build-mock-acp ci install-hooks homebrew-generate homebrew-test homebrew-test-style homebrew-test-install homebrew-test-cask homebrew-tap-setup homebrew-clean smoke-build smoke-test-cli smoke-test smoke-clean
# Binary name
BINARY_NAME=mitto
# macOS app bundle settings
APP_NAME=Mitto
APP_BUNDLE=$(APP_NAME).app
APP_BINARY=mitto-app
# Go parameters
GOCMD=go
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOGET=$(GOCMD) get
GOMOD=$(GOCMD) mod
GOFMT=$(GOCMD) fmt
# Node parameters
NPM=npm
# Build flags
LDFLAGS=-ldflags "-s -w"
# Main build target
build:
$(GOBUILD) $(LDFLAGS) -o $(BINARY_NAME) ./cmd/mitto
# Install to GOPATH/bin
install:
$(GOCMD) install ./cmd/mitto
# Run all unit tests (Go + JavaScript)
test: test-go test-js
# Run Go unit tests (excludes integration tests)
test-go:
@echo "Running Go unit tests..."
$(GOTEST) -v ./internal/... ./cmd/...
# Run JavaScript unit tests
test-js: deps-js
@echo "Running JavaScript tests..."
$(NPM) test
# Validate builtin model-tag references against the canonical Go tag set.
# Fails if any builtin prompt references a modelTag not in config.CanonicalModelTags(),
# any builtin processor's enabledWhen calls Session.HasModelTag("<tag>") with an unknown tag,
# or if config/config.default.yaml `models:` drifts from config.DefaultModelProfiles().
check-model-tags:
@echo "Validating builtin model-tag references (prompts + processors)..."
$(GOTEST) -run 'TestBuiltinPrompts_ModelTagsAreCanonical|TestDefaultModelProfiles_MatchesEmbeddedYAML|TestCanonicalModelTags|TestEffectiveModelProfiles_MergeAndPrecedence' ./internal/config/
$(GOTEST) -run 'TestBuiltinProcessors_HasModelTagArgsAreCanonical|TestHasModelTagArgsChecker_CatchesTypo' ./internal/processors/
# Validate builtin agent stderr patterns compile as valid Go regexes (mitto-k6h).
# Fails if any pattern in config/agents/builtin/*/metadata.yaml stderrPatterns
# (crash / ignore / degraded) fails regexp.Compile.
check-stderr-patterns:
@echo "Validating builtin agent stderr patterns..."
$(GOTEST) -run 'TestBuiltinAgents_StderrPatternsCompile' ./internal/agents/
# =============================================================================
# Integration & UI Tests
# =============================================================================
# These tests use a mock ACP server for deterministic, repeatable testing.
# Build the mock server first with: make build-mock-acp
# =============================================================================
# Build mock ACP server
build-mock-acp:
@echo "Building mock ACP server..."
$(GOBUILD) -o tests/mocks/acp-server/mock-acp-server ./tests/mocks/acp-server
# Run legacy integration tests (bash scripts, requires real ACP server)
test-integration-legacy: build
@echo "Running legacy integration tests..."
@./tests/integration/run_all.sh
# Run Go-based integration tests (uses mock ACP server)
test-integration-go: build build-mock-acp
@echo "Running Go integration tests..."
$(GOTEST) -v -tags=integration ./tests/integration/...
# Run CLI integration tests only
test-integration-cli: build build-mock-acp
@echo "Running CLI integration tests..."
$(GOTEST) -v -tags=integration ./tests/integration/cli/...
# Run API integration tests only
test-integration-api: build build-mock-acp
@echo "Running API integration tests..."
$(GOTEST) -v -tags=integration ./tests/integration/api/...
# Run client integration tests only
test-integration-client: build build-mock-acp
@echo "Running client integration tests..."
$(GOTEST) -v -tags=integration ./tests/integration/client/...
# Run runner integration tests (platform-specific)
test-integration-runner: build
@echo "Running runner integration tests..."
$(GOTEST) -v ./internal/runner/... -run TestRunnerFallback
# Run all integration tests (Go-based, uses mock ACP)
test-integration: test-integration-go
# Run UI tests with Playwright
test-ui: build tailwind build-mock-acp
@echo "Running UI tests..."
npx playwright test --config=tests/ui/playwright.config.ts
# Run UI tests in headed mode (visible browser)
test-ui-headed: build tailwind build-mock-acp
@echo "Running UI tests (headed)..."
npx playwright test --config=tests/ui/playwright.config.ts --headed
# Run UI tests in debug mode
test-ui-debug: build tailwind build-mock-acp
@echo "Running UI tests (debug)..."
npx playwright test --config=tests/ui/playwright.config.ts --debug
# Show Playwright test report
test-ui-report:
npx playwright show-report tests/ui/playwright-report
# Run all tests (unit + integration + UI)
test-all: test test-integration test-ui
# Setup test environment (install Playwright browsers, etc.)
test-setup: deps
@echo "Setting up test environment..."
npx playwright install chromium
@echo "Test environment ready."
# Clean test artifacts
test-clean:
@echo "Cleaning test artifacts..."
rm -rf tests/ui/test-results
rm -rf tests/ui/playwright-report
rm -f tests/mocks/acp-server/mock-acp-server
rm -rf /tmp/mitto-test-*
# Run tests in CI mode
test-ci: test-setup
@echo "Running tests in CI mode..."
CI=true $(MAKE) test
CI=true $(MAKE) test-integration
CI=true $(MAKE) test-ui
# Clean build artifacts
clean: clean-mac-app
$(GOCLEAN)
rm -f $(BINARY_NAME)
rm -rf node_modules
# Run the application (pass ARGS to provide command line arguments)
run: build
./$(BINARY_NAME) $(ARGS)
# Format Go code
fmt:
$(GOFMT) ./...
# Check Go code formatting (fails if files need formatting)
fmt-check:
@echo "Checking Go code formatting..."
@test -z "$$(gofmt -l .)" || (echo "The following files need formatting:" && gofmt -l . && exit 1)
@echo "All Go files are properly formatted."
# Format documentation markdown files (requires prettier)
fmt-docs: deps-js
@echo "Formatting documentation markdown files..."
npx prettier --write "docs/**/*.md"
# Check documentation formatting (fails if files need formatting)
fmt-docs-check: deps-js
@echo "Checking documentation formatting..."
npx prettier --check "docs/**/*.md"
# Lint Go code (requires golangci-lint)
lint-go:
golangci-lint run --timeout=5m
# Lint frontend code (HTML, CSS, JavaScript)
lint-frontend: deps-js
@echo "Linting frontend code..."
$(NPM) run lint:frontend
# Lint all code
lint: lint-go lint-frontend
# =============================================================================
# CI Target
# =============================================================================
# Run all the same checks that run in GitHub Actions CI.
# This includes: formatting check, linting, unit tests, and integration tests.
# UI tests are excluded as they require a browser.
#
# Usage: make ci
# =============================================================================
ci: deps tailwind build-mock-acp build
@echo "=============================================="
@echo "Running CI checks locally..."
@echo "=============================================="
@echo ""
@echo "Step 1/6: Checking Go formatting..."
@$(MAKE) fmt-check
@echo ""
@echo "Step 2/6: Running golangci-lint..."
@$(MAKE) lint-go
@echo ""
@echo "Step 3/6: Linting frontend code..."
@$(MAKE) lint-frontend
@echo ""
@echo "Step 4/6: Running Go unit tests..."
@$(MAKE) test-go
@echo ""
@echo "Step 5/6: Running JavaScript unit tests..."
@$(MAKE) test-js
@echo ""
@echo "Step 6/6: Running integration tests..."
@MITTO_TEST_MODE=1 $(MAKE) test-integration
@echo ""
@echo "=============================================="
@echo "✅ All CI checks passed!"
@echo "=============================================="
# Install the repo's git hooks (currently: pre-commit runs `make fmt-check`).
# This has repeatedly been the first thing to fail in CI after a feature
# commit lands with unformatted Go files, masking every later CI stage.
# Run this once after cloning: make install-hooks
install-hooks:
git config core.hooksPath .githooks
chmod +x .githooks/*
@echo "Git hooks installed (core.hooksPath=.githooks). 'make fmt-check' now runs on every commit."
# Download Go dependencies
deps-go:
$(GOMOD) download
$(GOMOD) tidy
# Install JavaScript dependencies
deps-js:
@if [ ! -d "node_modules" ]; then \
echo "Installing JavaScript dependencies..."; \
$(NPM) install; \
fi
# Build Tailwind CSS (generates web/static/tailwind.css)
tailwind: deps-js
@echo "Building Tailwind CSS..."
$(NPM) run tailwind
# Regenerate the local CodeMirror bundle (web/static/vendor/codemirror/codemirror.js)
# Only needed when updating CodeMirror versions; the bundle is committed.
vendor-codemirror: deps-js
@echo "Bundling CodeMirror..."
$(NPM) run vendor:codemirror
# Download all dependencies
deps: deps-go deps-js
# =============================================================================
# macOS Desktop App
# =============================================================================
# Build the macOS app bundle (Mitto.app)
#
# Requirements:
# - macOS with Command Line Tools installed (xcode-select --install)
# - CGO is required for the webview library
#
# The resulting Mitto.app can be:
# - Run directly: open Mitto.app
# - Copied to /Applications for permanent installation
# - Distributed as a .dmg or .zip file
#
# Environment variables:
# MITTO_ACP_SERVER - Override the default ACP server
# MITTO_WORK_DIR - Override the working directory for ACP sessions
# =============================================================================
build-mac-app: deps-go
@echo "Building macOS app bundle..."
@# Generate app icon from source icon.png
@echo "Generating app icon..."
@platform/mac/generate-icon.sh
@# Create app bundle structure
@mkdir -p "$(APP_BUNDLE)/Contents/MacOS"
@mkdir -p "$(APP_BUNDLE)/Contents/Resources"
@# Build the Go binary with CGO enabled (required for webview)
@echo "Compiling $(APP_BINARY)..."
CGO_ENABLED=1 $(GOBUILD) $(LDFLAGS) -o "$(APP_BUNDLE)/Contents/MacOS/$(APP_BINARY)" ./cmd/mitto-app
@# Build and bundle the CLI binary (used for MCP STDIO proxy)
@echo "Compiling $(BINARY_NAME) CLI..."
$(GOBUILD) $(LDFLAGS) -o "$(APP_BUNDLE)/Contents/MacOS/$(BINARY_NAME)" ./cmd/mitto
@# Copy Info.plist
@cp platform/mac/Info.plist "$(APP_BUNDLE)/Contents/"
@# Copy icon
@cp platform/mac/AppIcon.icns "$(APP_BUNDLE)/Contents/Resources/"
@# Ad-hoc sign the app with entitlements (required for notifications)
@echo "Signing app bundle..."
@codesign --force --deep --sign - --entitlements platform/mac/Entitlements.plist "$(APP_BUNDLE)"
@echo ""
@echo "✅ Built $(APP_BUNDLE)"
@echo " - $(APP_BINARY) (macOS app)"
@echo " - $(BINARY_NAME) (CLI for MCP proxy)"
@echo ""
@echo "To run the app:"
@echo " open $(APP_BUNDLE)"
@echo ""
@echo "To install to Applications:"
@echo " cp -r $(APP_BUNDLE) /Applications/"
@echo ""
# Clean macOS app bundle
clean-mac-app:
rm -rf "$(APP_BUNDLE)"
rm -f webviewlog_test
# Test WebView console logging (macOS only)
# Compiles and runs the Objective-C unit tests for webviewlog_darwin.m
test-webviewlog:
@echo "Compiling WebView logger tests..."
@clang -framework Foundation \
-o webviewlog_test \
cmd/mitto-app/webviewlog_darwin.m \
platform/mac/tests/webviewlog_darwin_test.m
@echo "Running tests..."
@./webviewlog_test
@rm -f webviewlog_test
# =============================================================================
# Homebrew Packaging
# =============================================================================
# Test Homebrew formula and cask generation and installation.
# Requires: brew (Homebrew) to be installed.
#
# Usage:
# make homebrew-generate # Generate formula and cask files
# make homebrew-test # Full test: generate, style, install, verify
# make homebrew-test-style # Only run style checks
# make homebrew-test-install # Test installation (requires generate first)
# make homebrew-clean # Clean up test artifacts and tap
# =============================================================================
HOMEBREW_VERSION ?= latest
HOMEBREW_TAP_NAME = local/mitto-test
HOMEBREW_TAP_PATH = /opt/homebrew/Library/Taps/local/homebrew-mitto-test
HOMEBREW_GEN_SCRIPT = platform/homebrew/generate-formula.sh
# Generate Homebrew formula and cask
homebrew-generate:
@echo "Generating Homebrew formula and cask for version: $(HOMEBREW_VERSION)"
@mkdir -p build/homebrew
@cd build/homebrew && $(CURDIR)/$(HOMEBREW_GEN_SCRIPT) --all $(HOMEBREW_VERSION)
@echo ""
@echo "✅ Generated files in build/homebrew/:"
@ls -la build/homebrew/mitto*.rb
# Run style checks on generated formula and cask
homebrew-test-style: homebrew-generate
@echo ""
@echo "Running Homebrew style checks..."
@echo ""
@echo "Formula style check:"
@brew style build/homebrew/mitto.rb
@echo ""
@echo "Cask style check:"
@brew style build/homebrew/mitto.cask.rb
@echo ""
@echo "✅ All style checks passed!"
# Set up local tap for testing
homebrew-tap-setup: homebrew-generate
@echo "Setting up local tap for testing..."
@if brew tap | grep -q "$(HOMEBREW_TAP_NAME)"; then \
echo "Tap already exists, cleaning up first..."; \
$(MAKE) homebrew-clean; \
fi
@brew tap-new --no-git $(HOMEBREW_TAP_NAME)
@mkdir -p $(HOMEBREW_TAP_PATH)/Casks
@cp build/homebrew/mitto.rb $(HOMEBREW_TAP_PATH)/Formula/
@cp build/homebrew/mitto.cask.rb $(HOMEBREW_TAP_PATH)/Casks/mitto.rb
@echo "✅ Local tap ready: $(HOMEBREW_TAP_NAME)"
# Test formula installation
homebrew-test-install: homebrew-tap-setup
@echo ""
@echo "Testing CLI formula installation..."
@brew install --formula $(HOMEBREW_TAP_NAME)/mitto
@echo ""
@echo "Running formula test..."
@brew test $(HOMEBREW_TAP_NAME)/mitto
@echo ""
@echo "Verifying CLI installation..."
@which mitto
@mitto --help | head -3
@echo ""
@echo "✅ CLI formula installation test passed!"
# Test cask installation (includes CLI as dependency)
homebrew-test-cask: homebrew-tap-setup
@echo ""
@echo "Testing cask installation (includes CLI dependency)..."
@brew install --cask $(HOMEBREW_TAP_NAME)/mitto
@echo ""
@echo "Verifying installations..."
@echo "CLI: $$(which mitto)"
@echo "App: $$(ls -d /Applications/Mitto.app 2>/dev/null || echo 'not found')"
@mitto --help | head -3
@test -d /Applications/Mitto.app || (echo "❌ Mitto.app not found in /Applications" && exit 1)
@echo ""
@echo "✅ Cask installation test passed!"
# Full Homebrew test: generate, style check, install formula, install cask
homebrew-test: homebrew-clean
@echo "=============================================="
@echo " HOMEBREW PACKAGING FULL TEST"
@echo "=============================================="
@echo ""
@$(MAKE) homebrew-test-style
@echo ""
@$(MAKE) homebrew-test-cask
@echo ""
@echo "=============================================="
@echo "✅ All Homebrew packaging tests passed!"
@echo "=============================================="
@$(MAKE) homebrew-clean
# =============================================================================
# Smoke Tests (Docker-based Linux verification)
# =============================================================================
# These tests compile mitto for linux (matching host architecture) and run it inside Docker
# to verify the binary works correctly on Linux.
#
# Usage:
# make smoke-build # Compile Linux binaries and build Docker image
# make smoke-test-cli # Run CLI-only smoke tests inside Docker (fast)
# make smoke-test # Run full smoke tests including Playwright UI tests
# make smoke-clean # Clean up smoke test artifacts
# =============================================================================
# Detect host architecture for Docker compatibility (Apple Silicon → arm64, x86 → amd64)
SMOKE_GOARCH ?= $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
# Cross-compile binaries and build Docker image for smoke tests
smoke-build:
@echo "Compiling mitto for linux/$(SMOKE_GOARCH) (static)..."
@mkdir -p tests/smoke/.build
CGO_ENABLED=0 GOOS=linux GOARCH=$(SMOKE_GOARCH) $(GOBUILD) $(LDFLAGS) -o tests/smoke/.build/mitto ./cmd/mitto
CGO_ENABLED=0 GOOS=linux GOARCH=$(SMOKE_GOARCH) $(GOBUILD) -o tests/smoke/.build/mock-acp-server ./tests/mocks/acp-server
@echo "Building Docker image..."
docker compose -f tests/smoke/docker-compose.yml build
# Run CLI-only smoke tests inside Docker (fast, no browser needed)
smoke-test-cli: smoke-build
docker compose -f tests/smoke/docker-compose.yml run --rm mitto /home/mitto/smoke-test.sh
# Run full smoke tests including Playwright UI tests from host
smoke-test: smoke-build
bash tests/smoke/run.sh
# Clean up smoke test artifacts
smoke-clean:
docker compose -f tests/smoke/docker-compose.yml down --rmi local 2>/dev/null || true
rm -rf tests/smoke/.build
# Clean up Homebrew test artifacts
homebrew-clean:
@echo "Cleaning up Homebrew test artifacts..."
@-brew uninstall --cask mitto 2>/dev/null || true
@-brew uninstall --formula mitto 2>/dev/null || true
@-brew untap $(HOMEBREW_TAP_NAME) 2>/dev/null || true
@rm -rf build/homebrew
@echo "✅ Cleanup complete"