# retoor SHELL := /bin/bash export PYTHONDONTWRITEBYTECODE := 1 PY := .venv/bin/python PIP := .venv/bin/pip STAMP := .venv/.stamp PKG := molodetz HOST ?= 127.0.0.1 PORT ?= 8088 WORKERS ?= 2 LOCUST_PORT ?= 8097 LOCUST_DATA := /tmp/molodetz-locust-data PYTEST := $(PY) -m pytest .PHONY: install dev prod test test-headed test-unit test-api test-e2e test-fast test-failed \ test-first-failure test-slowest test-cache-clean check-ui preflight coverage coverage-headed \ coverage-html locust locust-headless prune prune-dry-run tree tree-loc zip delete-pyc clean $(STAMP): pyproject.toml python3 -m venv .venv $(PIP) install --upgrade pip $(PIP) install -e ".[dev]" $(PY) -m playwright install chromium touch $(STAMP) install: $(STAMP) git config core.hooksPath .githooks || true dev: $(STAMP) $(PY) -m uvicorn $(PKG).main:app --host $(HOST) --port $(PORT) --reload --reload-dir $(PKG) --backlog 4096 prod: $(STAMP) MOLODETZ_STATIC_VERSION=$$(date +%s) MOLODETZ_TEMPLATE_AUTO_RELOAD=0 $(PY) -m uvicorn $(PKG).main:app --host $(HOST) --port $(PORT) \ --workers $(WORKERS) --backlog 8192 --proxy-headers --forwarded-allow-ips='*' test: $(STAMP) $(PYTEST) test-headed: $(STAMP) PLAYWRIGHT_HEADLESS=0 PLAYWRIGHT_SLOW_MO=150 $(PYTEST) test-unit: $(STAMP) $(PYTEST) tests/unit test-api: $(STAMP) $(PYTEST) tests/api test-e2e: $(STAMP) $(PYTEST) tests/e2e test-fast: $(STAMP) $(PYTEST) tests/unit tests/api test-failed: $(STAMP) $(PYTEST) --lf test-first-failure: $(STAMP) $(PYTEST) -x test-slowest: $(STAMP) $(PYTEST) --durations=40 test-cache-clean: rm -rf .pytest_cache check-ui: $(STAMP) $(PY) -m $(PKG).gates preflight: $(STAMP) $(PY) -c "import $(PKG).main; print('import ok')" $(PY) -m pyflakes $(PKG) tests for f in $$(find $(PKG)/static/js -name '*.js'); do node --check "$$f" 2>/dev/null || node --input-type=module --check < "$$f" || exit 1; done $(PY) -m $(PKG).cli system sql-lint $(MAKE) check-ui coverage: $(STAMP) rm -f .coverage .coverage.* COVERAGE_PROCESS_START=$(CURDIR)/.coveragerc PYTHONPATH=$(CURDIR) $(PY) -m coverage run -m pytest $(PY) -m coverage combine || true $(PY) -m coverage report coverage-headed: $(STAMP) PLAYWRIGHT_HEADLESS=0 $(MAKE) coverage coverage-html: coverage $(PY) -m coverage html -d out/coverage locust: $(STAMP) $(MAKE) locust-run LOCUST_ARGS="" locust-headless: $(STAMP) $(MAKE) locust-run LOCUST_ARGS="--headless -u 20 -r 5 -t 120s --html out/locust.html" locust-run: rm -rf $(LOCUST_DATA); mkdir -p $(LOCUST_DATA) out -fuser -k $(LOCUST_PORT)/tcp 2>/dev/null MOLODETZ_DATA_DIR=$(LOCUST_DATA) MOLODETZ_ADMIN_PASSWORD=locust-$$RANDOM$$RANDOM MOLODETZ_DISABLE_RATE_LIMIT=1 \ $(PY) -m uvicorn $(PKG).main:app --host 127.0.0.1 --port $(LOCUST_PORT) --workers 2 & echo $$! > $(LOCUST_DATA)/server.pid for i in $$(seq 1 60); do curl -fs http://127.0.0.1:$(LOCUST_PORT)/health >/dev/null && break; sleep 0.5; done -$(PY) -m locust -f locustfile.py --host http://127.0.0.1:$(LOCUST_PORT) $(LOCUST_ARGS) -kill $$(cat $(LOCUST_DATA)/server.pid) -for i in $$(seq 1 40); do kill -0 $$(cat $(LOCUST_DATA)/server.pid) 2>/dev/null || break; sleep 0.25; done rm -rf $(LOCUST_DATA) prune: $(STAMP) bin/maintenance.sh prune-dry-run: $(STAMP) bin/maintenance.sh --dry-run tree: find . -path ./.venv -prune -o -path ./.git -prune -o -path ./data -prune -o -type f -print | sort tree-loc: find $(PKG) tests -name '*.py' -o -name '*.js' -not -path '*/vendor/*' -not -path '*/generated/*' | xargs wc -l | sort -n zip: mkdir -p out && git archive --format=zip -o out/$(PKG).zip HEAD delete-pyc: find . -path ./.venv -prune -o \( -name '__pycache__' -o -name '*.pyc' \) -exec rm -rf {} + clean: delete-pyc rm -rf .venv build dist *.egg-info .pytest_cache .coverage .coverage.* out/coverage