`make setup` exited 0 whether or not the environment it produced was usable — per D-24, a step whose job is to not fail has a passing state indistinguishable from its broken state. Adds two cheap checks at the end: `pip check` for version drift between installed packages, and `pytest --collect-only` to walk the full src/ import graph and catch a missing declared dependency, which is what core-api's undetected missing sqlalchemy looked like (T-47). Neither needs any of the five backing services running — dependencies.py only constructs clients inside lru_cache getters, never at import/collection time. Also fixes `setup` to install requirements-dev.txt rather than requirements.txt. It only ever installed the latter since the Makefile's introduction, so `make test` and `make lint` — both of which need pytest and ruff — were never actually reachable from a clean `make setup`. requirements-dev.txt pulls in requirements.txt via -r, so the runtime set installed is unchanged; only the tooling to prove it is added. Found because the new check failed honestly on its first clean-tree run, before this fix. Verified: clean-tree run installs everything and passes (455 tests collected); a second run is a fast no-op; uninstalling a declared runtime dependency (asyncpg) makes the check fail with ModuleNotFoundError, and rerunning setup restores and re-passes it. Co-Authored-By: Claude <noreply@anthropic.com>
84 lines
3.9 KiB
Makefile
84 lines
3.9 KiB
Makefile
# library-desk — the repo's command surface (D-27).
|
|
#
|
|
# Note the port split, which is the trap this repo's CLAUDE.md leads with:
|
|
# `make run` serves on 8778 with reload, while 8089 is the *container*. Testing
|
|
# localhost:8089 on this box hits the deployed service, not your dev server.
|
|
#
|
|
# Paths resolve here (D-10): `python3` is 3.8 on this host and a bare `pytest`
|
|
# resolves only in a login shell, so both go through the venv explicitly.
|
|
|
|
VENV := $(CURDIR)/.venv
|
|
PYTHON ?= python3.12
|
|
|
|
.DEFAULT_GOAL := help
|
|
|
|
.PHONY: help
|
|
help: ## Show this help
|
|
@grep -hE '^[a-z][a-z0-9_-]*:.*?## ' $(MAKEFILE_LIST) \
|
|
| awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
|
|
|
|
.PHONY: setup
|
|
setup: ## Create the venv, install dependencies, and prove the result works
|
|
$(PYTHON) -m venv .venv
|
|
# requirements-dev.txt pulls in requirements.txt via -r, so this is still
|
|
# the full runtime set plus pytest/ruff. Installing only requirements.txt
|
|
# here (as this line originally did) left `make test` and `make lint`
|
|
# unreachable from a clean `make setup` since the Makefile's introduction
|
|
# in b9f55cb — pytest was never installed by setup at all. Found by the
|
|
# check below failing on its first clean-tree run; fixed in the same
|
|
# commit rather than filed separately, since the new check cannot pass
|
|
# honestly against the old line.
|
|
$(VENV)/bin/pip install -r requirements-dev.txt
|
|
# Exit 0 from pip install is not evidence (D-24) — it is the same exit code
|
|
# whether requirements.txt matches what's on disk or a dependency silently
|
|
# failed to install. Two cheap checks, for two different drift modes:
|
|
# pip check - installed packages satisfy each other's declared
|
|
# version constraints (a stale/partial install).
|
|
# pytest --collect-only - every test module actually imports, which
|
|
# walks the full src/ import graph and is exactly
|
|
# what catches a *missing* declared dependency
|
|
# (core-api's sqlalchemy case in T-47). It builds
|
|
# no client and opens no socket - dependencies.py
|
|
# wraps client construction in lru_cache getters,
|
|
# never called at collection time - so this needs
|
|
# none of the five backing services running.
|
|
$(VENV)/bin/pip check
|
|
$(VENV)/bin/python -m pytest tests/ --collect-only -q
|
|
|
|
.PHONY: run
|
|
run: ## Dev server on :8778 with reload (8089 is the container, not this)
|
|
./wakeup.sh
|
|
|
|
.PHONY: test
|
|
test: ## Run the test suite
|
|
@test -x $(VENV)/bin/python || { echo "FAIL — no venv; run: make setup"; exit 69; }
|
|
$(VENV)/bin/python -m pytest tests/
|
|
|
|
.PHONY: lint
|
|
lint: ## ruff check over the sources
|
|
@test -x $(VENV)/bin/ruff || { echo "FAIL — ruff not installed; run: make setup"; exit 69; }
|
|
$(VENV)/bin/ruff check src tests
|
|
|
|
# git hands a hook a non-login shell, which never sees ~/.local/bin — where
|
|
# gitleaks lands. Without this the scan reports "not installed" on every push,
|
|
# which is a check that fails open (D-24).
|
|
export PATH := $(HOME)/.local/bin:/usr/local/bin:$(PATH)
|
|
|
|
.PHONY: secrets
|
|
secrets: ## Scan the commits about to be pushed for credentials
|
|
@ci/secrets.sh
|
|
|
|
# The call surface is identical in every repo; what it runs is not.
|
|
#
|
|
# `secrets` runs first, deliberately: it is the only failure here that cannot be
|
|
# undone by fixing it afterwards. A failed lint costs another commit; a pushed
|
|
# credential is cached and indexed whether or not it is later deleted.
|
|
#
|
|
# Some of these fail today, and are left wired anyway. The state was measured
|
|
# once and written down in T-56 rather than being worked around here — a gate
|
|
# quietly narrowed to what already passes is a gate that reports success for
|
|
# doing nothing, which is the failure this workspace keeps rediscovering.
|
|
.PHONY: pre-push
|
|
pre-push: secrets lint ## Everything the pre-push hook runs
|
|
@echo " -- not gated here yet: test (T-56)"
|