The hook carried ~50 lines of gitleaks logic and a comment explaining it was self-contained because "this repo has no Makefile". It has one now, so the reason is gone and the arrangement is backwards: a hook is a trigger, and logic belongs where it can be read, run by hand, and changed under review. .githooks/pre-push is now a byte-identical shim onto `make pre-push` in every repo in the workspace. The scan itself moves to ci/secrets.sh unchanged, and `make secrets` runs it on its own. The call surface is identical everywhere; what it runs is not, and should not be — each repo gates what it actually has. That is the point of standardising the name rather than the contents: nobody has to read a repo to find out how to check it. 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 gates fail today, on lint debt that predates them, and they are left wired anyway. The board was measured once and written down in T-56 instead of being worked around here. Narrowing each gate to whatever already passes would produce a gate that reports success for doing nothing, which is the failure this workspace keeps rediscovering. Co-Authored-By: Claude <noreply@anthropic.com>
121 lines
5.0 KiB
Makefile
121 lines
5.0 KiB
Makefile
# desklock — one entry point for a three-component repo.
|
|
#
|
|
# firmware/ ESP-IDF application for the device. No tests, no release flow.
|
|
# gateway/ Python service on :8600. The only component with a test suite.
|
|
# sim/ a static page that mimics the device face in a browser.
|
|
#
|
|
# This lives at the root and the components have no Makefiles of their own, so
|
|
# `make test` means the same thing wherever you are standing. A per-component
|
|
# Makefile makes it mean "some of the tests" depending on your working
|
|
# directory, which is the `git -C` failure in another costume (D-27).
|
|
#
|
|
# Paths resolve here rather than in callers (D-10). Two of them bite:
|
|
#
|
|
# ESP-IDF is invisible until export.sh is sourced, so `idf.py` is
|
|
# "command not found" for anyone who forgets — the same class of failure as
|
|
# the four tool-resolution misses recorded in D-24. The firmware targets
|
|
# source it themselves.
|
|
#
|
|
# `python3` on this host is 3.8, which cannot parse the gateway's sources.
|
|
# PYTHON names 3.12 explicitly and is overridable for other machines.
|
|
|
|
PYTHON ?= python3.12
|
|
IDF_EXPORT ?= $(HOME)/esp-idf/export.sh
|
|
GATEWAY := $(CURDIR)/gateway
|
|
VENV := $(GATEWAY)/.venv
|
|
|
|
.DEFAULT_GOAL := help
|
|
|
|
.PHONY: help
|
|
help: ## Show this help
|
|
@grep -hE '^[a-z][a-z0-9_-]*:.*?## ' $(MAKEFILE_LIST) \
|
|
| awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}'
|
|
|
|
# --- the three D-27 required targets -----------------------------------------
|
|
|
|
.PHONY: test
|
|
test: test-gateway ## Run every component's tests that exist
|
|
@echo " -- firmware: no test suite (undetermined, not passing)"
|
|
@echo " -- sim: a static page, nothing to test"
|
|
|
|
.PHONY: lint
|
|
lint: lint-gateway ## Lint every component that has a linter
|
|
|
|
# --- gateway ------------------------------------------------------------------
|
|
|
|
.PHONY: setup
|
|
setup: ## Create the gateway venv and install dev deps (no ML models)
|
|
cd $(GATEWAY) && $(PYTHON) -m venv .venv && .venv/bin/pip install -e ".[dev]"
|
|
|
|
.PHONY: setup-speech
|
|
setup-speech: ## Additionally install faster-whisper and piper
|
|
cd $(GATEWAY) && .venv/bin/pip install -e ".[dev,speech]"
|
|
|
|
.PHONY: run
|
|
run: ## Run the gateway on :8600 with reload
|
|
cd $(GATEWAY) && .venv/bin/uvicorn desklock_gateway.main:app --host 0.0.0.0 --port 8600 --reload
|
|
|
|
.PHONY: test-gateway
|
|
test-gateway: ## Gateway pytest suite
|
|
@cd $(GATEWAY) && .venv/bin/pytest
|
|
|
|
.PHONY: lint-gateway
|
|
lint-gateway: ## ruff check and format --check over the gateway
|
|
cd $(GATEWAY) && .venv/bin/ruff check src tests && .venv/bin/ruff format --check src tests
|
|
|
|
.PHONY: typecheck
|
|
typecheck: ## mypy over the gateway sources
|
|
cd $(GATEWAY) && .venv/bin/mypy src
|
|
|
|
# --- firmware -----------------------------------------------------------------
|
|
#
|
|
# Each target sources export.sh in its own shell. That is deliberate: make runs
|
|
# every recipe line in a fresh shell, so exporting in one target would not carry
|
|
# to the next, and a caller who sources it by hand still works because sourcing
|
|
# twice is harmless.
|
|
|
|
.PHONY: build-firmware
|
|
build-firmware: ## Build the ESP-IDF firmware (sources export.sh for you)
|
|
@test -f $(IDF_EXPORT) || { echo "FAIL — no ESP-IDF at $(IDF_EXPORT); set IDF_EXPORT=<path>/export.sh"; exit 69; }
|
|
. $(IDF_EXPORT) && cd firmware && idf.py build
|
|
|
|
.PHONY: flash
|
|
flash: ## Flash and monitor the device (PORT=/dev/ttyACM0 by default)
|
|
@test -f $(IDF_EXPORT) || { echo "FAIL — no ESP-IDF at $(IDF_EXPORT); set IDF_EXPORT=<path>/export.sh"; exit 69; }
|
|
. $(IDF_EXPORT) && cd firmware && idf.py -p $(or $(PORT),/dev/ttyACM0) flash monitor
|
|
|
|
# --- sim ----------------------------------------------------------------------
|
|
|
|
.PHONY: serve-sim
|
|
serve-sim: ## Serve the face simulator on :8601
|
|
cd sim/face && $(PYTHON) -m http.server 8601
|
|
|
|
# --- housekeeping -------------------------------------------------------------
|
|
|
|
.PHONY: clean
|
|
clean: ## Remove the gateway venv and caches
|
|
rm -rf $(VENV) $(GATEWAY)/.pytest_cache $(GATEWAY)/.ruff_cache $(GATEWAY)/.mypy_cache
|
|
find $(GATEWAY) -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
|
|
# 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 typecheck test ## Everything the pre-push hook runs
|