forked from xprilion/OpenMLR
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
314 lines (240 loc) · 11.1 KB
/
Makefile
File metadata and controls
314 lines (240 loc) · 11.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
# OpenMLR Makefile
# Backend: Python / FastAPI (backend/)
# Frontend: React / Vite (frontend/)
SHELL := /bin/bash
BACKEND := backend
FRONTEND := frontend
PORT ?= 3000
DOCKER_USER ?= xprilion
VERSION ?= 0.3.0
DOCKER_COMPOSE := docker compose
LOGO_SRC := assets/full-logo.png
# ─── Setup ────────────────────────────────────────────────
.PHONY: install
install: install-backend install-frontend ## Install all dependencies
.PHONY: install-backend
install-backend: ## Install Python backend dependencies
cd $(BACKEND) && uv sync
.PHONY: install-frontend
install-frontend: ## Install frontend dependencies
cd $(FRONTEND) && pnpm install
# ─── Git Hooks ────────────────────────────────────────────
.PHONY: hooks
hooks: ## Install pre-commit hooks (ruff + eslint)
cd $(BACKEND) && uv run pre-commit install
.PHONY: hooks-run
hooks-run: ## Run all pre-commit hooks on entire repo
cd $(BACKEND) && uv run pre-commit run --all-files
.PHONY: hooks-update
hooks-update: ## Update pre-commit hook versions
cd $(BACKEND) && uv run pre-commit autoupdate
# ─── Development ──────────────────────────────────────────
.PHONY: dev
dev: ## Run backend + frontend dev servers in parallel
@trap 'kill 0' EXIT; \
$(MAKE) dev-backend & \
$(MAKE) dev-frontend & \
wait
.PHONY: dev-backend
dev-backend: ## Start backend with auto-reload (port=$(PORT))
cd $(BACKEND) && uv run uvicorn openmlr.app:app \
--host 0.0.0.0 --port $(PORT) --reload --reload-dir openmlr
.PHONY: dev-frontend
dev-frontend: ## Start Vite dev server (proxies /api to backend)
cd $(FRONTEND) && pnpm dev
.PHONY: dev-full
dev-full: ## Run backend + frontend + celery worker (requires Redis)
@trap 'kill 0' EXIT; \
USE_BACKGROUND_JOBS=true USE_REDIS_PUBSUB=true $(MAKE) dev-backend & \
$(MAKE) dev-frontend & \
$(MAKE) worker & \
wait
.PHONY: worker
worker: ## Start Celery worker for background jobs
cd $(BACKEND) && uv run celery -A openmlr.celery_app worker \
--loglevel=info --concurrency=2 -Q default,agent
# ─── Build & Production ──────────────────────────────────
.PHONY: build
build: build-frontend ## Build production frontend bundle
.PHONY: build-frontend
build-frontend: ## Compile frontend to frontend/dist/
cd $(FRONTEND) && pnpm build
.PHONY: start
start: build ## Build frontend, then start production server
cd $(BACKEND) && uv run uvicorn openmlr.app:app \
--host 0.0.0.0 --port $(PORT)
# ─── Database ─────────────────────────────────────────────
.PHONY: db-create
db-create: ## Create missing tables (safe, no-op on existing)
cd $(BACKEND) && uv run python -m openmlr.db.create_tables
.PHONY: db-fresh
db-fresh: ## Drop ALL tables and recreate (destroys data!)
cd $(BACKEND) && uv run python -m openmlr.db.create_tables --fresh
.PHONY: db-migrate
db-migrate: ## Generate Alembic migration (MSG="add users table")
cd $(BACKEND) && uv run alembic revision --autogenerate -m "$(MSG)"
.PHONY: db-upgrade
db-upgrade: ## Apply pending Alembic migrations
cd $(BACKEND) && uv run alembic upgrade head
# ─── Checks ──────────────────────────────────────────────
.PHONY: check
check: check-backend check-frontend ## Run all checks
.PHONY: check-backend
check-backend: ## Verify backend loads without errors
cd $(BACKEND) && uv run python -c \
"from openmlr.app import app; print(f'Backend OK: {app.title} v{app.version}, {len(app.routes)} routes')"
.PHONY: check-frontend
check-frontend: ## Type-check the frontend (tsc --noEmit)
cd $(FRONTEND) && npx tsc --noEmit
# ─── Linting ─────────────────────────────────────────────
.PHONY: lint
lint: lint-backend lint-frontend ## Run all linters
.PHONY: lint-backend
lint-backend: ## Lint backend with ruff
cd $(BACKEND) && uv run ruff check openmlr/ tests/
.PHONY: lint-frontend
lint-frontend: ## Lint frontend with ESLint
cd $(FRONTEND) && pnpm lint
.PHONY: lint-fix
lint-fix: lint-fix-backend lint-fix-frontend ## Auto-fix linting issues
.PHONY: lint-fix-backend
lint-fix-backend: ## Auto-fix backend linting issues
cd $(BACKEND) && uv run ruff check openmlr/ tests/ --fix
.PHONY: lint-fix-frontend
lint-fix-frontend: ## Auto-fix frontend linting issues
cd $(FRONTEND) && pnpm lint:fix
# ─── Testing ─────────────────────────────────────────────
.PHONY: test
test: test-backend test-frontend test-docs ## Run all tests (backend + frontend + docs)
.PHONY: test-backend
test-backend: ## Run backend pytest suite
cd $(BACKEND) && uv run pytest tests/ -q
.PHONY: test-frontend
test-frontend: ## Run frontend vitest suite
cd $(FRONTEND) && pnpm test
.PHONY: test-docs
test-docs: ## Verify docs site builds cleanly
cd site && npx vitepress build docs
.PHONY: test-coverage
test-coverage: test-coverage-backend test-coverage-frontend ## Run all tests with coverage reports
.PHONY: test-coverage-backend
test-coverage-backend: ## Backend tests with coverage
cd $(BACKEND) && uv run pytest tests/ --cov --cov-report=term-missing --tb=short -v
.PHONY: test-coverage-frontend
test-coverage-frontend: ## Frontend tests with coverage
cd $(FRONTEND) && pnpm test --coverage
cd $(FRONTEND) && pnpm test
# ─── Docker (Development) ──────────────────────────────────
# Default: docker-compose.yml (development with live reload)
.PHONY: dev-up
dev-up: ## Start development stack with live reload
$(DOCKER_COMPOSE) up -d
.PHONY: dev-build
dev-build: ## Build development images
$(DOCKER_COMPOSE) build
.PHONY: dev-down
dev-down: ## Stop development stack
$(DOCKER_COMPOSE) down
.PHONY: dev-logs
dev-logs: ## Tail development logs
$(DOCKER_COMPOSE) logs -f
.PHONY: dev-clean
dev-clean: ## Stop development stack and remove volumes
$(DOCKER_COMPOSE) down -v
.PHONY: infra
infra: ## Start only db + redis (for local dev without Docker app)
$(DOCKER_COMPOSE) up -d db redis
# ─── Docker (Production) ───────────────────────────────────
# Uses docker-compose.prod.yml with pre-built images
PROD_COMPOSE := $(DOCKER_COMPOSE) -f docker-compose.prod.yml
.PHONY: up
up: ## Start production stack (pulls xprilion/openmlr)
$(PROD_COMPOSE) up -d
.PHONY: down
down: ## Stop production stack
$(PROD_COMPOSE) down
.PHONY: restart
restart: ## Restart production web + worker
$(PROD_COMPOSE) up -d --build web worker
.PHONY: logs
logs: ## Tail production logs
$(PROD_COMPOSE) logs -f
.PHONY: docker-build
docker-build: ## Build production Docker image
docker build -t openmlr .
.PHONY: docker-run
docker-run: ## Run local production image (requires .env)
docker run --rm -p $(PORT):$(PORT) --env-file .env openmlr
.PHONY: docker-tag
docker-tag: ## Tag production image for Docker Hub
docker tag openmlr $(DOCKER_USER)/openmlr:$(VERSION)
docker tag openmlr $(DOCKER_USER)/openmlr:latest
.PHONY: docker-push
docker-push: ## Push production tags to Docker Hub
docker push $(DOCKER_USER)/openmlr:$(VERSION)
docker push $(DOCKER_USER)/openmlr:latest
.PHONY: docker-publish
docker-publish: docker-build docker-tag docker-push ## Build, tag, and push to Docker Hub
# ─── Docs ─────────────────────────────────────────────────
.PHONY: docs-install
docs-install: ## Install docs site dependencies
cd site && npm install
.PHONY: docs-dev
docs-dev: ## Preview docs locally (port 4000)
cd site && npx vitepress dev docs --port 4000
.PHONY: docs-docker
docs-docker: ## Run docs in Docker (port 4000)
$(DOCKER_COMPOSE) --profile docs up -d docs
.PHONY: docs-build
docs-build: ## Build docs to site/docs/.vitepress/dist
cd site && npx vitepress build docs
# ─── Logo Generation ─────────────────────────────────────
.PHONY: logo
logo: ## Generate all logo sizes from assets/full-logo.png
@echo "Generating logo sizes from $(LOGO_SRC)..."
@mkdir -p $(FRONTEND)/public site/docs/public
@# Favicons for webapp
sips -z 16 16 $(LOGO_SRC) --out $(FRONTEND)/public/favicon-16x16.png
sips -z 32 32 $(LOGO_SRC) --out $(FRONTEND)/public/favicon-32x32.png
sips -z 180 180 $(LOGO_SRC) --out $(FRONTEND)/public/apple-touch-icon.png
sips -z 192 192 $(LOGO_SRC) --out $(FRONTEND)/public/logo-192.png
sips -z 512 512 $(LOGO_SRC) --out $(FRONTEND)/public/logo-512.png
@# Generate .ico from 32x32 (copy as favicon.ico for browsers)
cp $(FRONTEND)/public/favicon-32x32.png $(FRONTEND)/public/favicon.ico
@# Logo for header/nav
sips -z 64 64 $(LOGO_SRC) --out $(FRONTEND)/public/logo-64.png
@# OG image (1200x630 for social sharing - pad/crop as needed)
sips -z 630 630 $(LOGO_SRC) --out $(FRONTEND)/public/og-image-square.png
sips -p 630 1200 $(FRONTEND)/public/og-image-square.png --out $(FRONTEND)/public/og-image.png
rm $(FRONTEND)/public/og-image-square.png
@# Copy to docs site
cp $(FRONTEND)/public/favicon-16x16.png site/docs/public/
cp $(FRONTEND)/public/favicon-32x32.png site/docs/public/
cp $(FRONTEND)/public/favicon.ico site/docs/public/
cp $(FRONTEND)/public/apple-touch-icon.png site/docs/public/
cp $(FRONTEND)/public/logo-64.png site/docs/public/
cp $(FRONTEND)/public/logo-192.png site/docs/public/
cp $(FRONTEND)/public/logo-512.png site/docs/public/
cp $(FRONTEND)/public/og-image.png site/docs/public/
@# Full logo for README
cp $(LOGO_SRC) assets/logo.png
sips -z 200 200 $(LOGO_SRC) --out assets/logo-200.png
@echo "Done! Logo sizes generated in frontend/public/, site/docs/public/, and assets/"
# ─── Cleanup ─────────────────────────────────────────────
.PHONY: clean
clean: ## Remove build artifacts and caches
rm -rf $(FRONTEND)/dist
find $(BACKEND) -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find $(BACKEND) -name '*.pyc' -delete 2>/dev/null || true
.PHONY: clean-all
clean-all: clean ## Remove all deps + build artifacts
rm -rf $(FRONTEND)/node_modules
rm -rf $(BACKEND)/.venv
rm -rf node_modules
rm -rf site/node_modules site/docs/.vitepress/dist site/docs/.vitepress/cache
# ─── Help ─────────────────────────────────────────────────
.PHONY: help
help: ## Show available targets
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
.DEFAULT_GOAL := help