- Replace bloated 1016-line Makefile with focused 730-line version - Add DC := docker compose variable for v2 compatibility - Consolidate 5 install-* targets into single install-tools - Remove redundant targets: self-cleanup, test-full, deploy-up/down/status - Add missing implementations for all 85 declared .PHONY targets - Include native lib variants, verification, security, OpenAPI, docs, perf targets
714 lines
28 KiB
Makefile
714 lines
28 KiB
Makefile
# =============================================================================
|
|
# FetchML Build System - Streamlined
|
|
# =============================================================================
|
|
|
|
.PHONY: all build prod prod-with-native dev cross-platform build-cli \
|
|
native-build native-release native-debug native-test native-smoke native-clean \
|
|
clean clean-release prepare-release verify-build \
|
|
test test-unit test-integration test-e2e test-coverage \
|
|
test-infra-up test-infra-down \
|
|
lint configlint worker-configlint ci-local ci-checks \
|
|
verify-quick verify-all verify-schema test-schema-validation \
|
|
lint-custom verify-audit verify-audit-chain install-tools \
|
|
security-scan gosec govulncheck check-unsafe security-audit \
|
|
openapi-generate openapi-generate-server openapi-validate \
|
|
openapi-check-ci openapi-check-implementation \
|
|
openapi-generate-clients \
|
|
docs docs-setup docs-build docs-build-prod docs-generate docs-serve \
|
|
benchmark benchmark-local benchmark-native benchmark-compare \
|
|
load-test chaos-test profile-load profile-load-norate profile-ws-queue profile-tools detect-regressions detect-regressions-native \
|
|
clean-benchmarks status size complete-suite \
|
|
dev-up dev-down dev-logs dev-restart \
|
|
staging-up staging-down staging-logs staging-restart staging-status \
|
|
homelab-secure-up homelab-secure-down \
|
|
prod-up prod-down prod-logs prod-restart prod-status \
|
|
status-all clean-deploy rollback-staging rollback-prod deploy-health-check \
|
|
install docker-build dev-smoke prod-smoke test-auth help
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Variables
|
|
# -----------------------------------------------------------------------------
|
|
|
|
OK := ✓
|
|
DOCS_PORT ?= 1313
|
|
DOCS_BIND ?= 127.0.0.1
|
|
DOCS_BASEURL ?= /
|
|
BUILD_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo dev)
|
|
BUILD_TIME := $(shell date -u +%Y%m%d.%H%M%S)
|
|
LDFLAGS := -X main.BuildHash=$(BUILD_HASH) -X main.BuildTime=$(BUILD_TIME)
|
|
LDFLAGS_PROD := -s -w
|
|
NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
|
DC := docker compose
|
|
TEST_COMPOSE := deployments/docker-compose.test.yml
|
|
|
|
define test_summary
|
|
@passed=$$(grep -c "^--- PASS:" $(1) 2>/dev/null || echo 0); \
|
|
failed=$$(grep -c "^--- FAIL:" $(1) 2>/dev/null || echo 0); \
|
|
skipped=$$(grep -c "^--- SKIP:" $(1) 2>/dev/null || echo 0); \
|
|
echo " Passed: $$passed Failed: $$failed Skipped: $$skipped"; \
|
|
if [ "$$failed" -gt 0 ]; then exit 1; fi
|
|
endef
|
|
|
|
define ensure_tool
|
|
@if ! command -v $(1) >/dev/null 2>&1; then \
|
|
echo "Installing $(1)..."; \
|
|
go install $(2); \
|
|
fi
|
|
endef
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Build
|
|
# -----------------------------------------------------------------------------
|
|
|
|
all: build
|
|
|
|
build: native-build openapi-generate-server
|
|
@mkdir -p bin/server bin/cli bin/native
|
|
go build -ldflags="$(LDFLAGS)" -o bin/server/api-server ./cmd/api-server/main.go
|
|
go build -ldflags="$(LDFLAGS)" -o bin/server/worker ./cmd/worker/worker_server.go
|
|
go build -ldflags="$(LDFLAGS)" -o bin/server/data_manager ./cmd/data_manager
|
|
go build -ldflags="$(LDFLAGS)" -o bin/server/user_manager ./cmd/user_manager
|
|
go build -ldflags="$(LDFLAGS)" -o bin/server/tui ./cmd/tui
|
|
@cp native/build/lib*.so native/build/lib*.dylib bin/native/ 2>/dev/null || true
|
|
$(MAKE) -C ./cli all
|
|
@cp cli/zig-out/bin/ml bin/cli/
|
|
@echo "$(OK) All components built"
|
|
|
|
prod:
|
|
@mkdir -p bin/server bin/cli
|
|
go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/api-server cmd/api-server/main.go
|
|
go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/worker cmd/worker/worker_server.go
|
|
go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/data_manager ./cmd/data_manager
|
|
go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/user_manager ./cmd/user_manager
|
|
go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/tui ./cmd/tui
|
|
$(MAKE) -C cli prod
|
|
@cp cli/zig-out/bin/ml bin/cli/
|
|
@echo "$(OK) Production binaries built"
|
|
|
|
dev:
|
|
@mkdir -p bin/server bin/cli
|
|
go build -buildvcs=false -o bin/server/api-server cmd/api-server/main.go
|
|
go build -buildvcs=false -o bin/server/worker cmd/worker/worker_server.go
|
|
go build -buildvcs=false -o bin/server/data_manager ./cmd/data_manager
|
|
go build -buildvcs=false -o bin/server/user_manager ./cmd/user_manager
|
|
go build -buildvcs=false -o bin/server/tui ./cmd/tui
|
|
$(MAKE) -C cli dev
|
|
@cp cli/zig-out/bin/ml bin/cli/
|
|
@echo "$(OK) Development binaries built"
|
|
|
|
native-build:
|
|
@mkdir -p native/build
|
|
@cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j$(NPROC)
|
|
@echo "$(OK) Native libraries built"
|
|
|
|
native-release:
|
|
@mkdir -p native/build
|
|
@cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_C_FLAGS="-O3 -DNDEBUG -fomit-frame-pointer" \
|
|
-DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -fomit-frame-pointer" && make -j$(NPROC)
|
|
@echo "$(OK) Native libraries built (release)"
|
|
|
|
native-debug:
|
|
@mkdir -p native/build
|
|
@cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON && make -j$(NPROC)
|
|
@echo "$(OK) Native libraries built (debug + ASan)"
|
|
|
|
native-test: native-build
|
|
@cd native/build && ctest --output-on-failure
|
|
@echo "$(OK) Native tests passed"
|
|
|
|
native-smoke:
|
|
@bash ./scripts/dev/smoke-test.sh --native
|
|
@echo "$(OK) Native smoke test passed"
|
|
|
|
native-clean:
|
|
@rm -rf native/build
|
|
@echo "$(OK) Native build cleaned"
|
|
|
|
prod-with-native: native-release
|
|
@mkdir -p bin/server bin/native
|
|
@cp native/build/lib*.so native/build/lib*.dylib bin/native/ 2>/dev/null || true
|
|
go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/api-server ./cmd/api-server/main.go
|
|
go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/worker ./cmd/worker/worker_server.go
|
|
@echo "$(OK) Production binaries built (with native libs)"
|
|
|
|
cross-platform:
|
|
@rm -rf dist && mkdir -p dist
|
|
@echo "Building Linux x86_64 static binaries..."
|
|
@for bin in \
|
|
"fetchml_api-server:cmd/api-server/main.go" \
|
|
"fetchml_worker:cmd/worker/worker_server.go" \
|
|
"fetchml_data_manager:./cmd/data_manager" \
|
|
"fetchml_user_manager:./cmd/user_manager" \
|
|
"fetchml_tui:./cmd/tui"; do \
|
|
name=$${bin%%:*}; src=$${bin##*:}; \
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false \
|
|
-ldflags="-s -w -buildid=" -o dist/$${name}_linux_amd64 $$src; \
|
|
done
|
|
@echo "$(OK) Cross-platform binaries in dist/"
|
|
|
|
build-cli:
|
|
$(MAKE) -C cli all
|
|
@echo "$(OK) CLI built"
|
|
|
|
verify-build:
|
|
@$(MAKE) build && shasum -a 256 bin/server/* bin/cli/* > /tmp/build_hash_1.txt 2>/dev/null || true
|
|
@$(MAKE) build && shasum -a 256 bin/server/* bin/cli/* > /tmp/build_hash_2.txt 2>/dev/null || true
|
|
@diff /tmp/build_hash_1.txt /tmp/build_hash_2.txt > /dev/null \
|
|
&& echo "$(OK) Build is reproducible" \
|
|
|| (echo "Build differs (expected with timestamps):"; diff /tmp/build_hash_1.txt /tmp/build_hash_2.txt || true)
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Tests
|
|
# -----------------------------------------------------------------------------
|
|
|
|
test: test-infra-up
|
|
@[ -f bin/cli/ml ] || $(MAKE) build-cli
|
|
@go test -v ./tests/unit/... ./tests/integration/... ./tests/e2e/... 2>&1 | grep -v "redis: connection pool" | tee /tmp/test-all.txt || true
|
|
@echo "\n=== Test Summary ==="
|
|
$(call test_summary,/tmp/test-all.txt)
|
|
@$(MAKE) test-infra-down
|
|
@cd cli && zig build test
|
|
|
|
test-unit:
|
|
@go test -v -short ./tests/unit/... 2>&1 | tee /tmp/test-unit.txt || true
|
|
@echo "\n=== Unit Test Summary ==="
|
|
$(call test_summary,/tmp/test-unit.txt)
|
|
@cd cli && zig build test
|
|
|
|
test-integration: test-infra-up
|
|
@go test -v ./tests/integration/... 2>&1 | tee /tmp/test-integration.txt || true
|
|
@echo "\n=== Integration Test Summary ==="
|
|
$(call test_summary,/tmp/test-integration.txt)
|
|
@$(MAKE) test-infra-down
|
|
|
|
test-e2e: test-infra-up
|
|
@[ -f bin/cli/ml ] || $(MAKE) build-cli
|
|
@go test -v ./tests/e2e/... 2>&1 | tee /tmp/test-e2e.txt || true
|
|
@echo "\n=== E2E Test Summary ==="
|
|
$(call test_summary,/tmp/test-e2e.txt)
|
|
@$(MAKE) test-infra-down
|
|
|
|
test-coverage:
|
|
@mkdir -p coverage
|
|
go test -coverprofile=coverage/coverage.out ./...
|
|
go tool cover -html=coverage/coverage.out -o coverage/coverage.html
|
|
@echo "$(OK) Coverage report: coverage/coverage.html"
|
|
|
|
test-infra-up:
|
|
@echo "Starting test infrastructure..."
|
|
@$(DC) -f $(TEST_COMPOSE) up -d
|
|
@echo "$(OK) Test infrastructure started"
|
|
|
|
test-infra-down:
|
|
@$(DC) -f $(TEST_COMPOSE) down 2>/dev/null || true
|
|
@echo "$(OK) Test infrastructure stopped"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Lint & Clean
|
|
# -----------------------------------------------------------------------------
|
|
|
|
lint:
|
|
gofmt -w ./cmd ./internal ./tests || true
|
|
go vet ./...
|
|
cd cli && zig fmt .
|
|
@echo "$(OK) Lint complete"
|
|
|
|
configlint:
|
|
go run ./cmd/configlint --schema configs/schema/api_server_config.yaml \
|
|
configs/api/dev.yaml \
|
|
configs/api/homelab-secure.yaml \
|
|
configs/api/multi-user.yaml \
|
|
configs/api/prod.yaml
|
|
|
|
worker-configlint:
|
|
go run ./cmd/configlint --schema configs/schema/worker_config_schema.yaml \
|
|
configs/workers/worker-prod.toml \
|
|
configs/workers/docker.yaml \
|
|
configs/workers/docker-dev.yaml \
|
|
configs/workers/docker-prod.yaml \
|
|
configs/workers/homelab-secure.yaml
|
|
|
|
ci-checks:
|
|
@bash ./scripts/ci/checks.sh
|
|
|
|
ci-local: lint configlint worker-configlint ci-checks test
|
|
@mkdir -p coverage
|
|
@echo "Running queue package tests with race detector..."
|
|
go test -v -race -coverprofile=coverage/queue-coverage.out ./internal/queue/...
|
|
$(MAKE) test-coverage
|
|
|
|
clean:
|
|
rm -rf bin/ coverage/ tests/bin/ dist/
|
|
rm -rf cli/zig-out/ cli/.zig-cache/ .zig-cache/
|
|
go clean
|
|
@echo "$(OK) Cleaned"
|
|
|
|
clean-release: clean
|
|
rm -rf native/build/
|
|
go clean -cache -testcache
|
|
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
|
|
find . -name "*.pyc" -delete 2>/dev/null || true
|
|
@./scripts/release/cleanup.sh testdata 2>/dev/null || true
|
|
@./scripts/release/cleanup.sh logs 2>/dev/null || true
|
|
@./scripts/release/cleanup.sh state 2>/dev/null || true
|
|
@echo "$(OK) Release cleanup complete"
|
|
|
|
prepare-release: clean-release
|
|
@./scripts/release/verify.sh
|
|
@echo "$(OK) Release preparation complete"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Verification
|
|
# -----------------------------------------------------------------------------
|
|
|
|
verify-schema:
|
|
@go test ./internal/manifest/... -run TestSchemaUnchanged -v
|
|
@echo "$(OK) Schema validation passed"
|
|
|
|
test-schema-validation:
|
|
@go test ./internal/manifest/... -run TestSchemaValidatesExampleManifest -v
|
|
@go test ./internal/manifest/... -run TestSchemaRejectsInvalidManifest -v
|
|
@echo "$(OK) Schema tests passed"
|
|
|
|
lint-custom:
|
|
@mkdir -p bin/tools
|
|
go build -ldflags="-s -w" -o bin/tools/fetchml-vet ./tools/fetchml-vet/cmd/fetchml-vet/
|
|
go vet -vettool=bin/tools/fetchml-vet ./internal/... ./cmd/... 2>/dev/null || true
|
|
@echo "$(OK) Custom lint complete"
|
|
|
|
verify-audit:
|
|
@go test ./tests/unit/audit/... -run TestChainVerifier -v
|
|
@echo "$(OK) Audit chain verification passed"
|
|
|
|
verify-audit-chain:
|
|
@if [ -z "$(AUDIT_LOG_PATH)" ]; then \
|
|
echo "Usage: make verify-audit-chain AUDIT_LOG_PATH=/path/to/audit.log"; exit 1; \
|
|
fi
|
|
@mkdir -p bin/tools
|
|
go build -ldflags="-s -w" -o bin/tools/audit-verifier ./cmd/audit-verifier/
|
|
./bin/tools/audit-verifier -log-path=$(AUDIT_LOG_PATH)
|
|
@echo "$(OK) Audit chain integrity verified"
|
|
|
|
verify-quick: verify-schema
|
|
|
|
verify-all: verify-schema test-schema-validation lint-custom verify-audit
|
|
@echo "$(OK) All verification checks passed"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Security
|
|
# -----------------------------------------------------------------------------
|
|
|
|
security-scan: gosec govulncheck check-unsafe
|
|
@echo "$(OK) Security scan complete"
|
|
|
|
gosec:
|
|
$(call ensure_tool,gosec,github.com/securego/gosec/v2/cmd/gosec@latest)
|
|
@mkdir -p reports
|
|
gosec -fmt=json -out=reports/gosec-results.json ./... 2>/dev/null || true
|
|
gosec -fmt=sarif -out=reports/gosec-results.sarif ./... 2>/dev/null || true
|
|
gosec ./... 2>/dev/null || echo "Note: gosec found issues (see reports/gosec-results.json)"
|
|
@echo "$(OK) gosec scan complete"
|
|
|
|
govulncheck:
|
|
$(call ensure_tool,govulncheck,golang.org/x/vuln/cmd/govulncheck@latest)
|
|
govulncheck ./...
|
|
@echo "$(OK) govulncheck complete"
|
|
|
|
check-unsafe:
|
|
@if grep -r "unsafe\." --include="*.go" ./internal ./cmd 2>/dev/null | grep -v "_test.go"; then \
|
|
echo "WARNING: unsafe package usage found — review required"; exit 1; \
|
|
else \
|
|
echo "$(OK) No unsafe package usage"; \
|
|
fi
|
|
|
|
security-audit: security-scan
|
|
@go test -v ./tests/security/... 2>/dev/null || echo "Note: No security tests yet"
|
|
@echo "$(OK) Full security audit complete"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# OpenAPI
|
|
# -----------------------------------------------------------------------------
|
|
|
|
_ensure_oapi:
|
|
$(call ensure_tool,oapi-codegen,github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest)
|
|
|
|
openapi-generate: _ensure_oapi
|
|
oapi-codegen -package api -generate types api/openapi.yaml > internal/api/types.go
|
|
@echo "$(OK) Generated internal/api/types.go"
|
|
|
|
openapi-generate-server: _ensure_oapi
|
|
oapi-codegen -package api -generate types,server api/openapi.yaml > internal/api/server_gen.go
|
|
@echo "$(OK) Generated internal/api/server_gen.go"
|
|
|
|
openapi-validate:
|
|
@command -v openapi-generator >/dev/null 2>&1 \
|
|
&& openapi-generator validate -i api/openapi.yaml 2>/dev/null \
|
|
|| echo "Note: Install openapi-generator for validation"
|
|
|
|
openapi-check-ci: openapi-generate
|
|
@git diff --exit-code internal/api/types.go 2>/dev/null \
|
|
|| (echo "ERROR: Run 'make openapi-generate' to sync" && exit 1)
|
|
@echo "$(OK) OpenAPI types up to date"
|
|
|
|
openapi-check-implementation: openapi-generate-server
|
|
@git diff --exit-code internal/api/server_gen.go 2>/dev/null \
|
|
|| (echo "ERROR: Run 'make openapi-generate-server' to sync" && exit 1)
|
|
@echo "$(OK) Spec and implementation in sync"
|
|
|
|
openapi-generate-clients: openapi-generate-ts openapi-generate-python
|
|
@echo "$(OK) All client SDKs generated"
|
|
|
|
openapi-generate-ts:
|
|
@mkdir -p sdk/typescript
|
|
@command -v npx >/dev/null 2>&1 || (echo "Note: npx not available" && exit 0)
|
|
npx @openapitools/openapi-generator-cli generate \
|
|
-i api/openapi.yaml -g typescript-fetch -o sdk/typescript \
|
|
--additional-properties=supportsES6=true,npmName=fetchml-client 2>/dev/null \
|
|
|| echo "Note: npm install -g @openapitools/openapi-generator-cli"
|
|
|
|
openapi-generate-python:
|
|
@mkdir -p sdk/python
|
|
@command -v npx >/dev/null 2>&1 || (echo "Note: npx not available" && exit 0)
|
|
npx @openapitools/openapi-generator-cli generate \
|
|
-i api/openapi.yaml -g python -o sdk/python \
|
|
--additional-properties=packageName=fetchml_client 2>/dev/null \
|
|
|| echo "Note: npm install -g @openapitools/openapi-generator-cli"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Documentation
|
|
# -----------------------------------------------------------------------------
|
|
|
|
docs-setup:
|
|
@command -v hugo >/dev/null 2>&1 \
|
|
|| (printf "Hugo not found.\n macOS: brew install hugo\n Linux: https://gohugo.io/installation/\n" && exit 1)
|
|
@echo "$(OK) Hugo available"
|
|
|
|
docs: docs-setup
|
|
cd docs && hugo server --bind "$(DOCS_BIND)" --port "$(DOCS_PORT)" --baseURL "$(DOCS_BASEURL)"
|
|
|
|
docs-build:
|
|
cd docs && hugo
|
|
|
|
docs-build-prod:
|
|
cd docs && hugo --minify --baseURL "$(DOCS_PROD_BASEURL)"
|
|
|
|
docs-generate:
|
|
@mkdir -p docs/api
|
|
@command -v npx >/dev/null 2>&1 \
|
|
&& npx @redocly/cli build-docs api/openapi.yaml \
|
|
--output docs/api/index.html --title "FetchML API" 2>/dev/null \
|
|
|| echo "Note: npm install -g @redocly/cli"
|
|
|
|
docs-serve:
|
|
@command -v npx >/dev/null 2>&1 \
|
|
&& npx @redocly/cli preview-docs api/openapi.yaml \
|
|
|| echo "Note: npx not available"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Performance
|
|
# -----------------------------------------------------------------------------
|
|
|
|
benchmark:
|
|
go test -bench=. -benchmem ./tests/benchmarks/...
|
|
|
|
benchmark-local:
|
|
@./scripts/benchmarks/run-benchmarks-local.sh
|
|
|
|
benchmark-native:
|
|
go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/...
|
|
|
|
benchmark-compare:
|
|
@echo "=== Go ==="
|
|
@go test -bench=. -benchmem ./tests/benchmarks/... 2>&1 \
|
|
| grep -E '(Benchmark|ns/op|allocs/op)' || true
|
|
@echo "\n=== Native ==="
|
|
@go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... 2>&1 \
|
|
| grep -E '(Benchmark|ns/op|allocs/op)' \
|
|
|| echo "Native not available (run: make native-build)"
|
|
|
|
load-test:
|
|
go test -v ./tests/load/...
|
|
|
|
chaos-test:
|
|
go test -v ./tests/chaos/...
|
|
|
|
profile-load:
|
|
@mkdir -p tests/bin
|
|
go test ./tests/load -run TestLoadProfile_Medium -count=1 -cpuprofile tests/bin/cpu_load.out
|
|
@echo "$(OK) Profile → tests/bin/cpu_load.out"
|
|
|
|
profile-load-norate:
|
|
@mkdir -p tests/bin
|
|
go test ./tests/load -run TestLoadProfile_Medium -count=1 \
|
|
-cpuprofile tests/bin/cpu_load.out -v -args -profile-norate
|
|
|
|
profile-ws-queue:
|
|
@mkdir -p tests/bin
|
|
go test ./tests/integration -run WebSocketQueue -count=2 -cpuprofile tests/bin/cpu_ws.out
|
|
@echo "$(OK) Profile → tests/bin/cpu_ws.out"
|
|
|
|
profile-tools:
|
|
@mkdir -p bin/tools
|
|
go build -ldflags="-s -w" -o bin/tools/performance-regression-detector \
|
|
./cmd/performance-regression-detector
|
|
go build -ldflags="-s -w" -o bin/tools/profiler ./cmd/profiler
|
|
@echo "$(OK) Profiling tools in bin/tools/"
|
|
|
|
detect-regressions: profile-tools
|
|
@mkdir -p tests/bin
|
|
@if [ ! -f tests/bin/baseline.bench.txt ]; then \
|
|
echo "Creating baseline..."; \
|
|
go test -bench=. -benchmem ./tests/benchmarks/... | tee tests/bin/baseline.bench.txt; \
|
|
fi
|
|
go test -bench=. -benchmem ./tests/benchmarks/... | tee tests/bin/current.bench.txt
|
|
./bin/tools/performance-regression-detector \
|
|
-baseline tests/bin/baseline.bench.txt \
|
|
-current tests/bin/current.bench.txt \
|
|
-threshold 10.0
|
|
|
|
detect-regressions-native: native-build profile-tools
|
|
@mkdir -p tests/bin
|
|
@if [ ! -f tests/bin/baseline-native.bench.txt ]; then \
|
|
echo "Creating native baseline..."; \
|
|
go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... \
|
|
| tee tests/bin/baseline-native.bench.txt; \
|
|
fi
|
|
go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... \
|
|
| tee tests/bin/current-native.bench.txt
|
|
./bin/tools/performance-regression-detector \
|
|
-baseline tests/bin/baseline-native.bench.txt \
|
|
-current tests/bin/current-native.bench.txt \
|
|
-threshold 10.0
|
|
|
|
clean-benchmarks:
|
|
@./scripts/maintenance/cleanup-benchmarks.sh benchmarks
|
|
|
|
status:
|
|
@./scripts/maintenance/cleanup-benchmarks.sh status
|
|
|
|
size:
|
|
@ls -lh bin/server/* bin/cli/* bin/tools/* 2>/dev/null || true
|
|
|
|
complete-suite: benchmark load-test chaos-test profile-tools
|
|
@echo "$(OK) Performance suite complete"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Deployment
|
|
# -----------------------------------------------------------------------------
|
|
|
|
dev-up:
|
|
$(DC) -f deployments/docker-compose.dev.yml up -d
|
|
@echo "$(OK) Dev environment up (Caddy: 8080/8443 Redis: 6379 Prometheus: 9090 Grafana: 3000)"
|
|
|
|
dev-down:
|
|
$(DC) -f deployments/docker-compose.dev.yml down
|
|
|
|
dev-logs:
|
|
$(DC) -f deployments/docker-compose.dev.yml logs -f
|
|
|
|
dev-restart:
|
|
$(DC) -f deployments/docker-compose.dev.yml restart
|
|
|
|
staging-up:
|
|
@if [ ! -f deployments/.env.staging ]; then \
|
|
printf 'DATA_DIR=./data/staging\nLOG_LEVEL=info\nCOMPLIANCE_MODE=standard\n' \
|
|
> deployments/.env.staging; \
|
|
echo "Created deployments/.env.staging with defaults"; \
|
|
fi
|
|
$(DC) -f deployments/docker-compose.staging.yml up -d
|
|
|
|
staging-down:
|
|
$(DC) -f deployments/docker-compose.staging.yml down
|
|
|
|
staging-logs:
|
|
$(DC) -f deployments/docker-compose.staging.yml logs -f
|
|
|
|
staging-restart:
|
|
$(DC) -f deployments/docker-compose.staging.yml restart
|
|
|
|
staging-status:
|
|
$(DC) -f deployments/docker-compose.staging.yml ps
|
|
|
|
homelab-secure-up:
|
|
$(DC) -f deployments/docker-compose.homelab-secure.yml up -d
|
|
|
|
homelab-secure-down:
|
|
$(DC) -f deployments/docker-compose.homelab-secure.yml down
|
|
|
|
prod-up:
|
|
@echo "⚠ WARNING: This is production. Ensure you have proper backups."
|
|
@read -p "Continue? [y/N] " c && [ "$$c" = "y" ] || exit 1
|
|
$(DC) -f deployments/docker-compose.prod.yml up -d
|
|
|
|
prod-down:
|
|
$(DC) -f deployments/docker-compose.prod.yml down
|
|
|
|
prod-logs:
|
|
$(DC) -f deployments/docker-compose.prod.yml logs -f
|
|
|
|
prod-restart:
|
|
@read -p "Restart production? [y/N] " c && [ "$$c" = "y" ] || exit 1
|
|
$(DC) -f deployments/docker-compose.prod.yml restart
|
|
|
|
prod-status:
|
|
$(DC) -f deployments/docker-compose.prod.yml ps
|
|
|
|
status-all:
|
|
@for env in dev staging homelab-secure prod; do \
|
|
f="deployments/docker-compose.$$env.yml"; \
|
|
echo "=== $$env ==="; \
|
|
[ -f "$$f" ] && $(DC) -f "$$f" ps 2>/dev/null || echo "Not running"; \
|
|
echo; \
|
|
done
|
|
|
|
clean-deploy:
|
|
@echo "Removes all containers and volumes for every environment. Continue? [y/N]"
|
|
@read -r c && [ "$$c" = "y" ] || exit 1
|
|
@for env in dev staging homelab-secure prod; do \
|
|
f="deployments/docker-compose.$$env.yml"; \
|
|
[ -f "$$f" ] && $(DC) -f "$$f" down -v 2>/dev/null || true; \
|
|
done
|
|
docker system prune -f
|
|
@echo "$(OK) All deployments cleaned"
|
|
|
|
rollback-staging:
|
|
@echo "⚠ Rolls back image only — queue state and audit log are NOT rolled back."
|
|
@read -p "Continue? [y/N] " c && [ "$$c" = "y" ] || exit 1
|
|
$(DC) -f deployments/docker-compose.staging.yml down
|
|
$(DC) -f deployments/docker-compose.staging.yml up -d
|
|
@echo "$$(date -Iseconds) | rollback | staging | actor=$$(whoami)" \
|
|
>> deployments/.staging-audit.log
|
|
|
|
rollback-prod:
|
|
@echo "⚠ CRITICAL: Image rollback only."
|
|
@echo " Queue state, audit chain, and storage artifacts are NOT rolled back."
|
|
@read -p "CONFIRM PRODUCTION ROLLBACK? [yes/N] " c && [ "$$c" = "yes" ] || exit 1
|
|
$(DC) -f deployments/docker-compose.prod.yml down
|
|
$(DC) -f deployments/docker-compose.prod.yml up -d
|
|
@echo "$$(date -Iseconds) | rollback | prod | actor=$$(whoami)" \
|
|
>> deployments/.prod-audit.log
|
|
@echo "$(OK) Rollback complete — verify: make prod-status"
|
|
|
|
deploy-health-check:
|
|
@echo "=== Health Checks ==="
|
|
@for item in "Development=9101" "Staging=9102" "Production=9101"; do \
|
|
label=$${item%%=*}; port=$${item##*=}; \
|
|
printf "%-16s (localhost:$$port): " "$$label"; \
|
|
curl -fsS http://localhost:$$port/health 2>/dev/null && echo "✓" || echo "✗ not responding"; \
|
|
done
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Install & Misc
|
|
# -----------------------------------------------------------------------------
|
|
|
|
install: prod
|
|
sudo cp bin/server/api-server /usr/local/bin/fetchml-api
|
|
sudo cp bin/server/worker /usr/local/bin/fetchml-worker
|
|
sudo cp bin/server/tui /usr/local/bin/fetchml-tui
|
|
sudo cp bin/cli/ml /usr/local/bin/ml
|
|
@echo "$(OK) Installed"
|
|
|
|
docker-build:
|
|
docker build -f build/docker/simple.Dockerfile -t fetchml:latest .
|
|
@echo "$(OK) Docker image built"
|
|
|
|
dev-smoke:
|
|
@bash ./scripts/dev/smoke-test.sh dev
|
|
|
|
prod-smoke:
|
|
@bash ./scripts/dev/smoke-test.sh prod
|
|
|
|
test-auth:
|
|
@for role in admin researcher analyst; do \
|
|
echo "Testing $$role user..."; \
|
|
cp ~/.ml/config-$$role.toml ~/.ml/config.toml && ./bin/cli/ml status; \
|
|
done
|
|
|
|
install-tools:
|
|
$(call ensure_tool,gosec,github.com/securego/gosec/v2/cmd/gosec@latest)
|
|
$(call ensure_tool,govulncheck,golang.org/x/vuln/cmd/govulncheck@latest)
|
|
$(call ensure_tool,go-mutesting,github.com/zimmski/go-mutesting/cmd/go-mutesting@latest)
|
|
$(call ensure_tool,scorecard,github.com/ossf/scorecard/v4/cmd/scorecard@latest)
|
|
$(call ensure_tool,oapi-codegen,github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest)
|
|
@echo "$(OK) All tools installed"
|
|
|
|
help:
|
|
@printf "FetchML Build System\n\n"
|
|
@printf "Build\n"
|
|
@printf " build Build all components (default)\n"
|
|
@printf " prod Production-optimized binaries\n"
|
|
@printf " prod-with-native Production binaries + native C++ libs\n"
|
|
@printf " dev Fast development build\n"
|
|
@printf " cross-platform Linux x86_64 static binaries in dist/\n"
|
|
@printf " build-cli Build Zig CLI only\n"
|
|
@printf " clean Remove all build artifacts\n"
|
|
@printf " clean-release Thorough pre-release cleanup\n"
|
|
@printf " prepare-release clean-release + release verification\n"
|
|
@printf " verify-build Check build reproducibility\n"
|
|
@printf "\n"
|
|
@printf "Native Libraries\n"
|
|
@printf " native-build C++ libs (release)\n"
|
|
@printf " native-release C++ libs (fully optimized)\n"
|
|
@printf " native-debug C++ libs (debug + ASan)\n"
|
|
@printf " native-test Run C++ unit tests\n"
|
|
@printf " native-smoke C++ + Go integration smoke test\n"
|
|
@printf " native-clean Remove native build artifacts\n"
|
|
@printf "\n"
|
|
@printf "Tests\n"
|
|
@printf " test All tests with infrastructure (CI default)\n"
|
|
@printf " test-unit Fast unit tests, no infrastructure\n"
|
|
@printf " test-integration Integration tests (infra auto-managed)\n"
|
|
@printf " test-e2e E2E tests (CLI auto-built, infra auto-managed)\n"
|
|
@printf " test-coverage Generate HTML coverage report\n"
|
|
@printf " test-infra-up Start Redis + SSH test containers\n"
|
|
@printf " test-infra-down Stop test containers\n"
|
|
@printf "\n"
|
|
@printf "Lint & CI\n"
|
|
@printf " lint gofmt + go vet + zig fmt\n"
|
|
@printf " configlint Validate API YAML configs\n"
|
|
@printf " worker-configlint Validate worker configs\n"
|
|
@printf " ci-checks Maintainability checks\n"
|
|
@printf " ci-local Full local CI (lint → config → test → coverage)\n"
|
|
@printf "\n"
|
|
@printf "Verification\n"
|
|
@printf " verify-quick Schema check only\n"
|
|
@printf " verify-all Schema + custom lint + audit chain\n"
|
|
@printf " verify-audit-chain Verify live audit log AUDIT_LOG_PATH=...\n"
|
|
@printf " install-tools Install all dev/CI tools in one shot\n"
|
|
@printf "\n"
|
|
@printf "Security\n"
|
|
@printf " security-scan gosec + govulncheck + unsafe check\n"
|
|
@printf " security-audit security-scan + security tests\n"
|
|
@printf "\n"
|
|
@printf "OpenAPI\n"
|
|
@printf " openapi-generate Regenerate internal/api/types.go\n"
|
|
@printf " openapi-generate-server Regenerate internal/api/server_gen.go\n"
|
|
@printf " openapi-generate-clients TypeScript + Python SDKs\n"
|
|
@printf " openapi-check-ci Fail if types.go out of sync\n"
|
|
@printf " openapi-check-implementation Fail if server_gen.go out of sync\n"
|
|
@printf "\n"
|
|
@printf "Performance\n"
|
|
@printf " benchmark Go benchmarks\n"
|
|
@printf " benchmark-native Benchmarks with native libs\n"
|
|
@printf " benchmark-compare Side-by-side Go vs native\n"
|
|
@printf " load-test / chaos-test Load and chaos suites\n"
|
|
@printf " detect-regressions Compare against saved baseline\n"
|
|
@printf " complete-suite benchmark + load + chaos + profile tools\n"
|
|
@printf "\n"
|
|
@printf "Deployment\n"
|
|
@printf " dev-up / dev-down Development environment\n"
|
|
@printf " staging-up / staging-down Staging environment\n"
|
|
@printf " prod-up / prod-down Production (confirmation required)\n"
|
|
@printf " status-all Status across all environments\n"
|
|
@printf " deploy-health-check HTTP health checks for all environments\n"
|
|
@printf " rollback-staging Roll back staging image\n"
|
|
@printf " rollback-prod Roll back production image (double-confirmed)\n"
|
|
@printf " clean-deploy Tear down all environments + prune Docker\n"
|
|
@printf "\n"
|
|
@printf "Install\n"
|
|
@printf " install Install binaries to /usr/local/bin\n"
|
|
@printf " docker-build Build Docker image\n"
|
|
@printf " install-tools Install all dev/CI tools\n"
|
|
@printf " size Show binary sizes\n"
|
|
@printf " help This message\n"
|