#!/usr/bin/env bash # Shortcuts for the development environment (docs/development.md). Each command prints the # docker compose command it runs, so it can always be used without this script. # Nothing here deletes data: no "down -v", no database reset. set -euo pipefail cd "$(dirname "$0")" die() { echo "dev: $*" >&2; exit 1; } # Only the development environment: its .env loads docker-compose.dev.yml. if ! grep -Eq '^COMPOSE_FILE=.*docker-compose\.dev\.yml' .env 2>/dev/null; then die "./dev is for the development environment only, and this .env is not the development one (no COMPOSE_FILE with docker-compose.dev.yml). On an installation use ./vhs (docs/installation.md); to develop, see docs/development.md: cp .env.dev.example .env" fi run() { echo "+ $*" >&2 "$@" } usage() { cat <<'EOF' Usage: ./dev [arguments] start start the environment (http://localhost:8081) stop stop the environment (data and videos are kept) restart [service] restart all services or one (to apply a changed .env, use start) status show the services logs [service] follow the logs (all services or one) build rebuild the images and restart (after changing dependencies or Dockerfiles) test [arguments] backend tests (pytest) test-frontend frontend tests (vitest) lint ruff on the backend, lint and type-check on the frontend manage Django command (manage.py) migrate apply migrations makemigrations create migrations shell Django shell after-debug bring backend and worker back after debugging from PyCharm check-config check the merged configuration of the Compose files check-symlinks check that Nginx never serves a symlink from the library sync after a pull request is merged: update main, delete merged branches help this list EOF } command=${1:-help} [ $# -gt 0 ] && shift case "$command" in start) run docker compose up -d ;; stop) run docker compose stop ;; restart) run docker compose restart "$@" ;; status) run docker compose ps ;; logs) run docker compose logs -f "$@" ;; build) run docker compose up -d --build ;; test) run docker compose exec backend pytest "$@" ;; test-frontend) run docker compose exec frontend npm run test:unit -- --run "$@" ;; lint) run docker compose exec backend sh -c 'cd /app && ruff check . && ruff format --check .' run docker compose exec frontend npm run lint run docker compose exec frontend npm run type-check ;; manage) [ $# -gt 0 ] || die "usage: ./dev manage [arguments]" run docker compose exec backend python manage.py "$@" ;; migrate) run docker compose exec backend python manage.py migrate "$@" ;; makemigrations) run docker compose exec backend python manage.py makemigrations "$@" ;; shell) run docker compose exec backend python manage.py shell "$@" ;; after-debug) # --no-deps: do not rerun the migrate service (and its reconciliation). run docker compose up -d --no-deps backend worker ;; check-symlinks) run scripts/check-nginx-symlinks.sh ;; check-config) run scripts/check-dev-config.sh ;; sync) # After a pull request is merged on GitHub (docs/development.md): main up to date, the local # branches deleted on GitHub removed, and what to rebuild. [ -z "$(git status --porcelain --untracked-files=no)" ] \ || die "there are uncommitted changes: commit or stash them first." before=$(git rev-parse main) run git checkout -q main run git fetch --prune run git merge --ff-only origin/main # "gone": the branch on GitHub was deleted, usually after its pull request was merged, # but also when it was closed without merging: ask before deleting. gone=$(git for-each-ref --format='%(refname:short) %(upstream:track)' refs/heads \ | awk '$2 == "[gone]" { print $1 }') if [ -n "$gone" ]; then echo "Deleted on GitHub (merged, or closed without merging): $(printf '%s\n' "$gone" | tr '\n' ' ')" read -r -p "Delete these local branches? [y/N] " answer || answer="" case "$answer" in y | Y | yes | YES) for branch in $gone; do run git branch -D "$branch"; done ;; *) echo "Local branches kept." ;; esac fi changed=$(git diff --name-only "$before" HEAD) todo="" hint() { if printf '%s\n' "$changed" | grep -Eq "$1"; then echo "Changed: $2 -> run $3" todo=yes fi } hint '^(uv\.lock|pyproject\.toml|docker/Dockerfile\.(backend|frontend-dev))$' \ "Python dependencies or Dockerfiles" "./dev build" hint '^frontend/package-lock\.json$' "frontend dependencies" "./dev restart frontend" hint '/migrations/' "database migrations" "./dev migrate" [ -n "$todo" ] || echo "Nothing to rebuild." ;; help | -h | --help) usage ;; *) usage >&2 die "unknown command: $command" ;; esac