Ctrl K
ComunidadGuías…

Makefile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
.PHONY: all build run demo clean tidy mod-check frontend frontend-check frontend-stub test test-race test-dashboard test-e2e test-integration test-contract test-live test-all lint lint-fix fix fix-check record-api swagger docs-openapi helm-lint install-tools perf-check perf-bench fuzz infra image seed-demo-data build-plugins image-plugins example-plugins

all: frontend build

# Get version info
VERSION ?= $(shell git describe --tags --always --dirty)
COMMIT ?= $(shell git rev-parse --short HEAD)
DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
DOCS_API_SERVERS ?= http://localhost:8080
LOG_LEVEL ?= debug
SWAGGER_ENABLED ?= true

# Build tags covering every file the linter and fixers must see. Without these,
# tag-gated files (tests/e2e, tests/integration, tests/contract, live provider
# tests) are skipped.
BUILD_TAGS ?= swagger,e2e,integration,contract,live
GOLANGCI_LINT_VERSION := 2.14.0
GOLANGCI_LINT ?= $(shell go env GOPATH)/bin/golangci-lint

# Linker flags to inject version info
LDFLAGS := -X "github.com/enterpilot/gomodel/internal/version.Version=$(VERSION)" \
           -X "github.com/enterpilot/gomodel/internal/version.Commit=$(COMMIT)" \
           -X "github.com/enterpilot/gomodel/internal/version.Date=$(DATE)"

install-tools:
	@installed_version="$$($(GOLANGCI_LINT) version 2>/dev/null || true)"; \
	case "$$installed_version" in \
		*"version $(GOLANGCI_LINT_VERSION) "*) ;; \
		*) echo "Installing golangci-lint v$(GOLANGCI_LINT_VERSION)..."; \
			GOBIN="$(dir $(GOLANGCI_LINT))" go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v$(GOLANGCI_LINT_VERSION) ;; \
	esac
	@command -v pre-commit > /dev/null 2>&1 || (echo "Installing pre-commit..." && pip install pre-commit==4.5.1)
	@echo "All tools are ready"

# Compiles the gateway. The dashboard must be built first (see `frontend`);
# the binary embeds internal/admin/dashboard/static/dist.
build: frontend
	go build -ldflags '$(LDFLAGS)' -o bin/gomodel ./cmd/gomodel
# Run the application.
#
# Built and exec'd rather than `go run`: `go run` exits 1 when it is
# interrupted, even after the program it supervises shuts down cleanly, so
# Ctrl+C always ended in a bogus "make: *** [run] Error 1". exec replaces the
# recipe shell, which also puts the gateway directly under make's signal
# handling instead of behind a supervisor.
run:
	go build -tags=swagger -ldflags '$(LDFLAGS)' -o bin/gomodel ./cmd/gomodel
	LOG_LEVEL="$(LOG_LEVEL)" SWAGGER_ENABLED="$(SWAGGER_ENABLED)" exec ./bin/gomodel

# Seed the local SQLite database and start GoModel with a populated dashboard.
# Guardrails (which imply plugins) are on so the seeded guardrail instances and
# the workflows referencing them are live rather than capped off at runtime.
# Audit retention is raised to the seeded window: the 30-day default would
# delete two thirds of the demo audit log on the first startup sweep.
# Exported so the seeder reads the same window as the retention settings: a
# maintainer changing this default must not leave them out of step.
# The allowlist mode serves the seeded providers' model lists without calling
# upstream /models with their placeholder keys.
export DEMO_DAYS ?= 90
demo: seed-demo-data
	$(MAKE) run GOMODEL_DEMO_MODE=true GUARDRAILS_ENABLED=true \
		CONFIGURED_PROVIDER_MODELS_MODE=allowlist \
		LOGGING_RETENTION_DAYS=$(DEMO_DAYS) USAGE_RETENTION_DAYS=$(DEMO_DAYS)

# Clean build artifacts
clean:
	rm -rf bin/

# Tidy dependencies
tidy:
	go mod tidy

# Verify dependencies are tidy and match downloaded module checksums without
# mutating the working tree. CI and release builds use this target.
mod-check:
	go mod tidy -diff
	go mod verify

# Docker Compose: Redis, PostgreSQL, MongoDB, Adminer (no app image build)
infra:
	docker compose up -d

# Docker Compose: full stack (GoModel + Prometheus; builds app image when needed)
image: frontend
	docker compose --profile app up -d

# Shared-object plugin support (Go's plugin package) needs a cgo-enabled
# binary; the default `build` and the release binaries are static. These
# targets produce the cgo variants. Plugins must be built with the same Go
# toolchain and flags as the binary that loads them: `gomodel plugin build`
# copies the flags of the gomodel binary that runs it.
build-plugins: frontend
	CGO_ENABLED=1 go build -ldflags '$(LDFLAGS)' -o bin/gomodel-plugins ./cmd/gomodel

# Docker image with plugin support (Dockerfile.plugins). Tag: gomodel:<version>-plugins.
image-plugins: frontend
	docker build -f Dockerfile.plugins -t gomodel:$(VERSION)-plugins -t gomodel:plugins \
		--build-arg VERSION=$(VERSION) --build-arg COMMIT=$(COMMIT) --build-arg DATE=$(DATE) .

# Build every example plugin under docs/example_plugins into ./plugins/<name>.so
# using the toolchain of this checkout (matches `make build-plugins`).
example-plugins:
	@mkdir -p plugins
	@for dir in docs/example_plugins/*/; do \
		name=$$(basename $$dir); \
		echo "building $$dir -> plugins/$$name.so"; \
		go run ./cmd/gomodel plugin build -o plugins/$$name.so $$dir || exit 1; \
	done

# Seed rolling demo telemetry and dashboard configuration into SQLite.
# Usage: SQLITE_PATH=data/gomodel.db make seed-demo-data
seed-demo-data:
	bash tools/seed-demo-data.sh

# Run unit tests only
test: frontend-check
	go test ./cmd/... ./config/... ./ext/... ./internal/... ./run/... -v

# Run unit tests with race detection and coverage
test-race: frontend-check
	go test -v -race -coverprofile=coverage.out ./cmd/... ./config/... ./ext/... ./internal/... ./run/...

# Build the Svelte dashboard into internal/admin/dashboard/static/dist, which
# the Go binary embeds. The output is not committed: CI builds it in a
# secretless job (docs/adr/0010-dashboard-built-in-ci.md). --ignore-scripts
# keeps npm lifecycle scripts from running; the build does not need them.
frontend:
	cd web/dashboard && npm ci --no-audit --no-fund --ignore-scripts && npm run build

# The Go suites embed the dashboard, so they need a build in place. This only
# checks; it does not build, because CI supplies static/dist as an artifact
# from the secretless `frontend` job and must not rebuild it here.
frontend-check:
	@test -f internal/admin/dashboard/static/dist/index.html || { \
		echo "internal/admin/dashboard/static/dist is missing: run 'make frontend' first." >&2; exit 1; }

# Write a placeholder bundle so the Go suites compile and pass without Node.
# CI test jobs use this instead of waiting for the `frontend` job; the Build
# job and releases still embed the real bundle. A no-op when a bundle exists.
frontend-stub:
	sh tools/frontend-stub.sh

# Run dashboard JavaScript unit tests
test-dashboard:
	cd web/dashboard && npm test

# Run e2e tests (uses an in-process mock LLM server; no Docker required)
test-e2e: frontend-check
	go test -v -tags=e2e ./tests/e2e/...

# Run integration tests (requires Docker)
test-integration:
	go test -v -tags=integration -timeout=10m ./tests/integration/...

# Run contract tests (validates API response structures against golden files)
test-contract:
	go test -v -tags=contract -timeout=5m ./tests/contract/...

# Live provider tests call real upstreams and spend quota. Each one skips unless
# its credential is set, e.g. CHATGPT_API_KEY for the ChatGPT prompt-cache check.
test-live:
	go test -count=1 -v -tags=live -timeout=10m -run TestLive ./internal/providers/...

# Run all tests including dashboard, e2e, integration, and contract tests
test-all: test test-dashboard test-e2e test-integration test-contract

# Every guard in tests/perf, with no -run filter: the name list this used to
# carry had to be edited by hand for each new guard, and silently left the ones
# nobody remembered to add (TestFormatPerfGuardResult,
# TestSessionIDVisibilityByBodySize) running nowhere. A guard that CI does not
# execute is worse than no guard, because it reads as covered.
perf-check:
	go test -count=1 -v ./tests/perf/...

perf-bench:
	go test -bench=. -benchmem ./tests/perf/...

# Run each fuzz target for FUZZTIME. The seed corpora already run as plain
# tests under `make test`; this explores beyond them and is not part of CI.
# Usage: make fuzz FUZZTIME=5m
FUZZTIME ?= 30s
fuzz:
	go test -run='^$$' -fuzz='^FuzzRequestDecompression$$' -fuzztime=$(FUZZTIME) ./internal/server
	go test -run='^$$' -fuzz='^FuzzRewriteBatchSource$$' -fuzztime=$(FUZZTIME) ./internal/core
	go test -run='^$$' -fuzz='^FuzzUnknownJSONFieldsRoundTrip$$' -fuzztime=$(FUZZTIME) ./internal/core

# Record API responses for contract tests
# Usage: OPENAI_API_KEY=sk-xxx make record-api
record-api:
	@echo "Recording OpenAI chat completion..."
	go run ./cmd/recordapi -provider=openai -endpoint=chat \
		-output=tests/contract/testdata/openai/chat_completion.json
	@echo "Recording OpenAI models..."
	go run ./cmd/recordapi -provider=openai -endpoint=models \
		-output=tests/contract/testdata/openai/models.json
	@echo "Done! Golden files saved to tests/contract/testdata/"

swagger:
	go run github.com/swaggo/swag/v2/cmd/swag init --generalInfo main.go \
		--dir cmd/gomodel,internal \
		--output cmd/gomodel/docs \
		--outputTypes go \
		--parseDependency
	@command -v node >/dev/null 2>&1 || { echo "node is required to build docs; install from https://nodejs.org" >&2; exit 1; }
	node tools/swagger-postprocess.mjs cmd/gomodel/docs/docs.go
	$(MAKE) docs-openapi

docs-openapi:
	@command -v node >/dev/null 2>&1 || { echo "node is required to build docs; install from https://nodejs.org" >&2; exit 1; }
	@command -v npx >/dev/null 2>&1 || { echo "npx is required; install npm (includes npx)" >&2; exit 1; }
	@tmp_dir=$$(mktemp -d); \
	trap 'rm -rf "$$tmp_dir"' EXIT; \
	go run github.com/swaggo/swag/v2/cmd/swag init --quiet --generalInfo main.go \
		--dir cmd/gomodel,internal \
		--output "$$tmp_dir" \
		--outputTypes json \
		--parseDependency; \
	npx -y swagger2openapi@7.0.8 --patch -o docs/openapi.json "$$tmp_dir/swagger.json"; \
	DOCS_API_SERVERS="$(DOCS_API_SERVERS)" node tools/openapi-postprocess.mjs docs/openapi.json

# Run linter
lint:
	$(GOLANGCI_LINT) run --build-tags=$(BUILD_TAGS) ./cmd/... ./config/... ./ext/... ./internal/... ./run/... ./tests/...

# Lint the Helm chart with every CI values profile and validate the rendered
# manifests against the Kubernetes schemas (requires helm and kubeconform).
helm-lint:
	helm lint --strict helm
	for values in helm/ci/*-values.yaml; do helm lint --strict helm -f "$$values"; done
	rendered=$$(mktemp); trap 'rm -f "$$rendered"' EXIT; \
	for values in helm/ci/*-values.yaml; do \
		helm template gomodel helm -f "$$values" --namespace gomodel > "$$rendered" || exit 1; \
		kubeconform -strict -summary -schema-location default -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' < "$$rendered" || exit 1; \
	done

# Run linter with auto-fix. Mirrors `lint`: same tags, same packages, so the
# autofix pass cannot silently skip the tag-gated files under tests/.
lint-fix:
	$(GOLANGCI_LINT) run --fix --build-tags=$(BUILD_TAGS) ./cmd/... ./config/... ./ext/... ./internal/... ./run/... ./tests/...

# Report modernizations go fix would apply, without touching the tree.
# Exits non-zero when the tree has drifted; run `make fix` to apply.
fix-check:
	go fix -diff -tags=$(BUILD_TAGS) ./...

# Apply go fix modernizations in place.
#
# Not idempotent in one pass: when go fix marks a helper `//go:fix inline` it
# inlines the callers on the *next* run, which can leave the helper orphaned.
# Re-run until `make fix-check` is clean, then delete any helper `make lint`
# now reports as unused.
fix:
	go fix -tags=$(BUILD_TAGS) ./...