152 lines
5.3 KiB
Makefile
152 lines
5.3 KiB
Makefile
.DEFAULT_GOAL := help
|
|
|
|
UV := $(shell command -v uv 2>/dev/null)
|
|
PROJECT_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
|
|
USER := $(shell id -un)
|
|
PORT ?= 8000
|
|
SERVICE := osiris
|
|
UNIT_FILE := /etc/systemd/system/$(SERVICE).service
|
|
REMINDER_SH := $(PROJECT_DIR)/deploy/send-reminders.sh
|
|
CRON_SCHED ?= */10 * * * *
|
|
CRON_LOG ?= $(PROJECT_DIR)/reminders.log
|
|
MANAGE := $(UV) run python manage.py
|
|
|
|
.PHONY: help
|
|
help: ## Show this help
|
|
@grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) \
|
|
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}'
|
|
|
|
# --- Setup -----------------------------------------------------------------
|
|
|
|
.PHONY: install
|
|
install: check-uv frontend ## Install dependencies, build the frontend, migrate, collect static files
|
|
$(UV) sync
|
|
@$(MAKE) --no-print-directory env # after sync: it needs Django importable
|
|
$(MANAGE) migrate
|
|
$(MANAGE) collectstatic --noinput
|
|
@echo "Installed. Next: 'make superuser' (once), then 'make service' and 'make cron'."
|
|
|
|
.PHONY: check-uv
|
|
check-uv:
|
|
@test -n "$(UV)" || { echo "uv is not installed: https://docs.astral.sh/uv/"; exit 1; }
|
|
|
|
.PHONY: env
|
|
env: ## Create .env with a fresh SECRET_KEY and VAPID keys (keeps an existing one)
|
|
@if [ -f .env ]; then \
|
|
echo ".env already exists — leaving it alone."; \
|
|
else \
|
|
cp .env.example .env; \
|
|
secret=$$($(UV) run python -c "import secrets; print(secrets.token_urlsafe(64))"); \
|
|
sed -i "s|^DJANGO_SECRET_KEY=.*|DJANGO_SECRET_KEY=$$secret|" .env; \
|
|
$(MAKE) --no-print-directory vapid; \
|
|
echo "Wrote .env — review DJANGO_ALLOWED_HOSTS before going live."; \
|
|
fi
|
|
|
|
.PHONY: vapid
|
|
vapid: ## Generate VAPID keys and write them into .env
|
|
@test -f .env || cp .env.example .env
|
|
@keys=$$($(MANAGE) generate_vapid_keys 2>/dev/null | grep '^VAPID_'); \
|
|
pub=$$(echo "$$keys" | grep '^VAPID_PUBLIC_KEY=' | cut -d= -f2); \
|
|
priv=$$(echo "$$keys" | grep '^VAPID_PRIVATE_KEY=' | cut -d= -f2); \
|
|
test -n "$$pub" || { echo "Key generation failed."; exit 1; }; \
|
|
sed -i "s|^VAPID_PUBLIC_KEY=.*|VAPID_PUBLIC_KEY=$$pub|" .env; \
|
|
sed -i "s|^VAPID_PRIVATE_KEY=.*|VAPID_PRIVATE_KEY=$$priv|" .env; \
|
|
echo "VAPID keys written to .env. Restart the service, then re-enable reminders on each device."
|
|
|
|
.PHONY: superuser
|
|
superuser: ## Create the login account (there is no registration)
|
|
$(MANAGE) createsuperuser
|
|
|
|
# --- systemd ---------------------------------------------------------------
|
|
|
|
.PHONY: service
|
|
service: ## Install, enable and start the systemd service (needs sudo)
|
|
@sed -e 's|__USER__|$(USER)|g' \
|
|
-e 's|__PROJECT_DIR__|$(PROJECT_DIR)|g' \
|
|
-e 's|__UV__|$(UV)|g' \
|
|
-e 's|__PORT__|$(PORT)|g' \
|
|
deploy/osiris.service.template > /tmp/$(SERVICE).service
|
|
sudo install -m 644 /tmp/$(SERVICE).service $(UNIT_FILE)
|
|
@rm -f /tmp/$(SERVICE).service
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now $(SERVICE)
|
|
@sudo systemctl --no-pager --lines=0 status $(SERVICE) || true
|
|
|
|
.PHONY: restart
|
|
restart: ## Restart the service (do this after changing .env)
|
|
sudo systemctl restart $(SERVICE)
|
|
|
|
.PHONY: logs
|
|
logs: ## Follow the service log
|
|
journalctl -u $(SERVICE) -f
|
|
|
|
.PHONY: service-uninstall
|
|
service-uninstall: ## Stop and remove the systemd service
|
|
-sudo systemctl disable --now $(SERVICE)
|
|
sudo rm -f $(UNIT_FILE)
|
|
sudo systemctl daemon-reload
|
|
|
|
# --- cron ------------------------------------------------------------------
|
|
|
|
# The script path is the marker: it identifies our line without needing a literal
|
|
# '#' comment, which make would strip as a comment of its own.
|
|
.PHONY: cron
|
|
cron: ## Install the reminder cron job (every 10 minutes, idempotent)
|
|
@chmod +x $(REMINDER_SH)
|
|
@( crontab -l 2>/dev/null | grep -vF '$(REMINDER_SH)' ; \
|
|
echo "$(CRON_SCHED) $(REMINDER_SH) >> $(CRON_LOG) 2>&1" ) | crontab -
|
|
@echo "Installed:"
|
|
@crontab -l | grep -F '$(REMINDER_SH)'
|
|
|
|
.PHONY: cron-remove
|
|
cron-remove: ## Remove the reminder cron job
|
|
@crontab -l 2>/dev/null | grep -vF '$(REMINDER_SH)' | crontab -
|
|
@echo "Removed."
|
|
|
|
.PHONY: cron-test
|
|
cron-test: ## Run the reminder job once, reporting what it would send
|
|
$(REMINDER_SH) --dry-run
|
|
|
|
# --- Frontend --------------------------------------------------------------
|
|
|
|
.PHONY: frontend
|
|
frontend: ## Install frontend dependencies (pnpm) and build the Vue frontend
|
|
cd frontend && pnpm install && pnpm run build
|
|
|
|
# Only build when no bundle exists yet: tests render the shell template, which
|
|
# needs the Vite manifest, but should not pay for a rebuild on every run.
|
|
frontend/dist/.vite/manifest.json:
|
|
@$(MAKE) --no-print-directory frontend
|
|
|
|
.PHONY: front-dev
|
|
front-dev: ## Run the Vite dev server with hot reload (pair with: DJANGO_VITE_DEV=1 make run)
|
|
cd frontend && pnpm run dev
|
|
|
|
.PHONY: api-client
|
|
api-client: ## Regenerate the typed TS API client (needs 'make run' in another terminal)
|
|
cd frontend && pnpm run generate:api
|
|
|
|
# --- Development -----------------------------------------------------------
|
|
|
|
.PHONY: run
|
|
run: ## Run the development server
|
|
$(MANAGE) runserver $(PORT)
|
|
|
|
.PHONY: test
|
|
test: frontend/dist/.vite/manifest.json ## Run the test suite
|
|
$(MANAGE) test
|
|
|
|
.PHONY: lint
|
|
lint: ## Check formatting and lints
|
|
$(UV) run ruff format --check .
|
|
$(UV) run ruff check .
|
|
|
|
.PHONY: format
|
|
format: ## Reformat and autofix
|
|
$(UV) run ruff format .
|
|
$(UV) run ruff check --fix .
|
|
|
|
.PHONY: deploy
|
|
deploy: install restart ## Pull dependencies, migrate, collect static, restart
|
|
@echo "Deployed."
|