-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathMakefile
More file actions
262 lines (199 loc) · 11.9 KB
/
Copy pathMakefile
File metadata and controls
262 lines (199 loc) · 11.9 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
VERSION := $(shell ./scripts/version.sh)
GIT_SHA := $(shell git rev-parse --short HEAD)
IMG_PREFIX := jentic-one
SERVICES := app registry admin control broker
BUILD_DIR := build
.PHONY: help install sync lock upgrade fmt format fix lint typecheck test test-unit test-fast test-integration test-integration-sqlite test-integration-all test-arch test-smoke cov cov-all check score openapi openapi-parity config-schema config-reference endpoints cli-reference broker-reference skills hooks clean dev start-fixtures stop-fixtures destroy-fixtures start-app start-registry start-admin start-control start-broker build-wheel build-base build-all save-all images release-image $(addprefix build-,$(SERVICES)) $(addprefix push-,$(SERVICES)) $(addprefix save-,$(SERVICES))
help: ## Show this help
@awk 'BEGIN {FS = ":.*##"; printf "Usage: make <target>\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-13s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
install: sync ui-setup hooks ## Full dev setup: sync deps, install UI deps, install lefthook hooks
sync: ## Install/sync project + dev dependencies (includes all extras)
uv sync --dev --all-extras
lock: ## Refresh the lockfile
uv lock
upgrade: ## Upgrade locked dependencies
uv lock --upgrade
uv sync --dev
fmt format: ## Format code with ruff
uv run ruff format .
uv run ruff check . --fix
fix: ## Auto-fix lint issues and reformat code
uv run ruff check --fix .
uv run ruff format .
lint: ## Lint (ruff check + format check + mypy)
uv run ruff check .
uv run ruff format --check .
uv run mypy
typecheck: ## Run mypy
uv run mypy
test: test-unit ## Run tests (unit only by default)
test-unit: ## Run unit tests
uv run pytest tests/unit/
test-fast: ## Run unit + arch tests (no external services)
uv run pytest tests/unit/ tests/arch/
test-integration: ## Run all integration tests against PostgreSQL (requires running fixtures)
uv run pytest tests/ -m integration --no-cov
test-integration-sqlite: ## Run backend-agnostic integration tests against SQLite (no external services)
JENTIC_TEST_BACKEND=sqlite uv run pytest tests/integration/ -m integration --no-cov
test-integration-all: test-integration test-integration-sqlite ## Run integration tests on both backends
test-arch: ## Run architecture enforcement tests
uv run pytest tests/arch/ -m arch --no-cov
test-smoke: ## Run smoke tests (requires running services)
uv run pytest tests/smoke/ -m smoke --no-cov
smoke-packaging: ## Build UI+wheel, install in a clean venv, verify the SPA is packaged & served (DB-free)
./scripts/spa_packaging_smoke.sh
cov: ## Run unit + arch tests with coverage report
uv run pytest tests/unit/ tests/arch/ --cov-report=term-missing --cov-report=html
cov-all: ## Run all tests with coverage (requires running fixtures/services)
uv run pytest tests/ --cov-report=term-missing --cov-report=html
openapi: ## Regenerate the control-plane OpenAPI spec (+ UI client schema) from code
uv run python -m tools.openapi_export
uv run python -m tools.openapi_export --output ui/openapi.json
@echo "Regenerated openapi/control/control.openapi.yaml and ui/openapi.json."
@echo "If working on the UI, run 'cd ui && npm run codegen' to refresh the client."
openapi-parity: ## Print the reference-vs-generated OpenAPI coverage report
uv run python -m tools.openapi_parity
config-schema: ## Regenerate the backend config JSON Schema (config/config-schema.json) from the AppConfig model
uv run python -m tools.config_schema_export
@echo "Regenerated config/config-schema.json."
@echo "Run 'cd cli && make generate-config' to refresh the generated installer config struct."
@echo "Run 'make config-reference' to refresh the configuration reference doc."
config-reference: ## Regenerate the configuration reference (docs/reference/config.md) from the AppConfig model
uv run python -m tools.config_reference
@echo "Regenerated docs/reference/config.md."
endpoints: ## Regenerate the endpoint + scope reference (docs/reference/endpoints.{md,json}) from code
uv run python -m tools.endpoint_tree
@echo "Regenerated docs/reference/endpoints.md and docs/reference/endpoints.json."
cli-reference: ## Regenerate the CLI command reference (ui/public/cli-reference.json) from the cobra command tree
cd cli && go run ./cmd/clidocs -o ../ui/public/cli-reference.json
@echo "Regenerated ui/public/cli-reference.json."
broker-reference: ## Regenerate the Broker OpenAPI artifact (ui/public/broker-openapi.json) from the hand-curated spec
uv run python -m tools.broker_reference
@echo "Regenerated ui/public/broker-openapi.json."
skills: ## Mirror skills/<name>/SKILL.md into both content/ dirs (CLI embed + wheel-served copies)
uv run python -m tools.skills_sync
@echo "Mirrored the served skill set; run 'go build ./...' in cli/ to re-embed."
score: ## Validate OpenAPI specs with the Jentic API Scorecard CLI (requires 80+)
# control.openapi.yaml is generated from code (make openapi) and carries the
# full metadata catalogue, so it must clear the 80+ scorecard floor.
npx --yes @jentic/api-scorecard-cli@1.0.0-alpha.29 score openapi/control/control.openapi.yaml --quiet
# broker.openapi.yaml is still hand-curated; re-enable once it is brought up to floor.
# npx --yes @jentic/api-scorecard-cli@1.0.0-alpha.29 score openapi/broker/broker.openapi.yaml --quiet
detect-secrets: ## Check for new secrets not in baseline
uv run detect-secrets scan --baseline .secrets.baseline --exclude-files '\.git/'
check: lint detect-secrets test-arch score ## Run lint, secrets audit, arch-tests, and score (score last: it needs npx/network and shouldn't block the offline gates)
hooks: ## Install lefthook git hooks (pre-commit + commit-msg)
uv run lefthook install
clean: ## Remove caches and build artifacts
rm -rf .pytest_cache .mypy_cache .ruff_cache .coverage htmlcov coverage.xml build dist *.egg-info $(BUILD_DIR)
find . -type d -name __pycache__ -prune -exec rm -rf {} +
find deploy/helm -name "*.tgz" -delete 2>/dev/null || true
find deploy/helm -name "Chart.lock" -delete 2>/dev/null || true
JENTIC_CONFIG_FILE ?= config/local.yaml
export JENTIC_CONFIG_FILE
dev: ## One-command local bring-up (idempotent): fixtures + migrations + UI, then start the app
@./scripts/dev-up.sh
@$(MAKE) --no-print-directory start-app
start-fixtures: ## Start Docker database fixtures and apply migrations
@./scripts/setup.sh
stop-fixtures: ## Stop Docker database fixtures
docker compose -f docker/local-setup/docker-compose.yaml stop
destroy-fixtures: ## Remove Docker database fixtures and volumes
docker compose -f docker/local-setup/docker-compose.yaml down -v
start-app: ## Start combined app (all surfaces)
uv run python -m jentic_one
start-registry: ## Start registry surface standalone
JENTIC__APPS=registry uv run python -m jentic_one
start-admin: ## Start admin surface standalone
JENTIC__APPS=admin uv run python -m jentic_one
start-control: ## Start control surface standalone
JENTIC__APPS=control uv run python -m jentic_one
start-broker: ## Start broker surface standalone
JENTIC__APPS=broker uv run python -m jentic_one
migrate-sqlite: ## Apply all migrations to the local SQLite databases (config/local-sqlite.yaml)
@mkdir -p .data
JENTIC_CONFIG_FILE=config/local-sqlite.yaml uv run python -m jentic_one.migrations.run
start-app-sqlite: migrate-sqlite ## Start combined app on local SQLite (ingest only; search disabled)
JENTIC_CONFIG_FILE=config/local-sqlite.yaml uv run python -m jentic_one
build-wheel: ## Build Python wheel (packaging TEST ONLY — never published; the container image is the canonical backend distribution)
uv build --wheel
# ─── UI (frontend) ───────────────────────────────────────────────────────
UI_DIR := ui
ui-setup: ## Install UI deps for local dev (no-op when node is unavailable)
@if command -v node >/dev/null 2>&1; then \
echo "Installing UI dependencies…"; \
cd $(UI_DIR) && npm ci; \
else \
echo "node not found — skipping UI deps (backend-only setup)."; \
echo "Install Node.js if you intend to work on the UI."; \
fi
ui-install: ## Install UI dependencies
cd $(UI_DIR) && npm ci
ui-build: ## Build the UI bundle into ui/dist
cd $(UI_DIR) && npm ci && npm run build
ui-lint: ## Lint the UI
cd $(UI_DIR) && npm ci && npm run lint
ui-test: ## Run UI unit/component tests
cd $(UI_DIR) && npm ci && npm run test:run
build-base: ## Build the Python base Docker image (builder + runtime stages)
docker build -f deploy/docker/python-base.Dockerfile --target builder -t python-base:builder .
docker build -f deploy/docker/python-base.Dockerfile --target runtime -t python-base:runtime .
# Per-service build / push / save rules generated explicitly (no pattern rules,
# so this works on GNU Make 3.81 — Apple's bundled version).
# NOTE: push-<svc> pushes the local per-service names ($(IMG_PREFIX)/<svc>) for
# dev/fork registries; the published-release path is `release-image` below,
# which pushes the differently named <REGISTRY>/jentic-one-app.
define SERVICE_RULES
build-$(1): build-base ## Build Docker image for $(1)
docker build -f deploy/docker/$(1).Dockerfile -t $(IMG_PREFIX)/$(1):$(VERSION) -t $(IMG_PREFIX)/$(1):$(GIT_SHA) .
push-$(1): ## Push $(1) image to the registry
docker push $(IMG_PREFIX)/$(1):$(VERSION)
docker push $(IMG_PREFIX)/$(1):$(GIT_SHA)
save-$(1): ## Save $(1) image to build/jentic-$(1)-$(VERSION).tar
@mkdir -p $(BUILD_DIR)
docker save $(IMG_PREFIX)/$(1):$(VERSION) -o $(BUILD_DIR)/jentic-$(1)-$(VERSION).tar
@echo "Wrote $(BUILD_DIR)/jentic-$(1)-$(VERSION).tar"
endef
$(foreach svc,$(SERVICES),$(eval $(call SERVICE_RULES,$(svc))))
build-all: build-base $(addprefix build-,$(SERVICES)) ## Build all Docker images
save-all: $(addprefix save-,$(SERVICES)) ## Save all built images as tarballs under build/
images: ## List locally built jentic-one images
@docker images "$(IMG_PREFIX)/*"
# ─── Release (publish the app image to a real registry) ───────────────────
# One `app` image serves every surface — the surface set is chosen at runtime
# via JENTIC__APPS (see deploy/README.md "One image, runtime surfaces"). So
# publishing the single `app` image is enough for a self-hosted app + broker
# deployment.
#
# make release-image REGISTRY=ghcr.io/jentic
#
# builds deploy/docker/app.multiarch.Dockerfile for linux/amd64 + linux/arm64
# with `docker buildx` and pushes the OCI index to $(REGISTRY)/jentic-one-app
# tagged with the pyproject version and the short git SHA. `latest` only moves
# when the version is a stable X.Y.Z (no prerelease suffix), mirroring CI's
# guard so a dev/rc push can never hijack the tag self-hosters float on.
# Requires `docker login <registry>` first AND a buildx builder that can build
# both arches (`docker buildx create --use` + QEMU for the non-native leg). CI
# does this on a vX.Y.Z tag (see .github/workflows/release.yml) with its own
# inline script rather than this target: CI must scan each arch, interleave
# cosign signing between the version and :latest tags, and lower-case the GHCR
# owner — which this all-in-one target can't express.
REGISTRY ?=
RELEASE_IMAGE := $(REGISTRY)/jentic-one-app
RELEASE_PLATFORMS ?= linux/amd64,linux/arm64
release-image: ## Build + push the multi-arch app image to REGISTRY (e.g. REGISTRY=ghcr.io/jentic)
@if [ -z "$(REGISTRY)" ]; then \
echo "ERROR: set REGISTRY, e.g. make release-image REGISTRY=ghcr.io/jentic"; exit 1; \
fi
docker buildx build -f deploy/docker/app.multiarch.Dockerfile \
--platform $(RELEASE_PLATFORMS) \
-t $(RELEASE_IMAGE):$(VERSION) \
-t $(RELEASE_IMAGE):$(GIT_SHA) \
--push .
@if echo "$(VERSION)" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$$'; then \
docker buildx imagetools create -t $(RELEASE_IMAGE):latest $(RELEASE_IMAGE):$(VERSION); \
echo "Pushed $(RELEASE_IMAGE) ($(VERSION), $(GIT_SHA), latest) [$(RELEASE_PLATFORMS)]"; \
else \
echo "Prerelease version — not moving :latest"; \
echo "Pushed $(RELEASE_IMAGE) ($(VERSION), $(GIT_SHA)) [$(RELEASE_PLATFORMS)]"; \
fi