set dotenv-load := true set export := true # Prepend asdf paths so recipes work without sourcing ~/.asdf/asdf.sh in the shell. # Caller PATH is preserved (Homebrew asdf, docker CLI, etc.). See CODE_GUIDELINES §3.13. home := env_var("HOME") asdf_paths := home + "/.asdf/shims:" + home + "/.asdf/bin:" + home + "/.asdf:" PATH := asdf_paths + env_var("PATH") MIX_QUIET := "1" run: install-dependencies start-database migrate-database seed-database mix phx.server install-dependencies: mix deps.get migrate-database: mix compile mix ash.setup reset-database: mix ash.reset MIX_ENV=test mix ash.reset seed-database: mix run priv/repo/seeds.exs start-database: docker compose up -d # Full check suite: lint + audit + the fast tests (slow/ui excluded). No Dialyzer. ci-dev: install-dependencies lint audit test-fast # Fast pre-commit check: lint + sobelow + only the affected tests (mix test --stale) # with reduced property runs. Run the full `ci-dev` before pushing. check: install-dependencies lint sobelow test-stale # Build the Dialyzer PLT. Idempotent — no-op once the PLT is up to date. # First build takes 5–15 min; subsequent runs are seconds. PLT files live in # priv/plts/ and are gitignored. plt: install-dependencies @mkdir -p priv/plts mix dialyzer --plt # Typecheck via Dialyzer. Slow stage, NOT part of ci-dev. typecheck: plt mix dialyzer --format short # Full CI: inner loop plus typecheck. Use locally before pushing; Drone CI # runs equivalent steps with PLT caching. ci: ci-dev typecheck gettext: mix gettext.extract mix gettext.merge priv/gettext --on-obsolete=mark_as_obsolete lint: mix format --check-formatted mix compile --warnings-as-errors mix credo --strict # Check that all German translations are filled (UI must be in German) @bash -c 'for file in priv/gettext/de/LC_MESSAGES/*.po; do awk "/^msgid \"\"$/{header=1; next} /^msgid /{header=0} /^msgstr \"\"$/ && !header{print FILENAME\":\"NR\": \" \$0; exit 1}" "$file" || exit 1; done' mix gettext.extract --check-up-to-date # Static security scan (Sobelow). sobelow: mix sobelow --config # Full security audit: Sobelow + dependency advisory scans. audit: sobelow mix deps.audit --ignore-file .deps_audit_ignore mix hex.audit # Run all tests. No install-dependencies prerequisite so single-file runs stay # fast; run `just install-dependencies` once on a fresh checkout. test *args: mix test {{args}} # Fast tests only (excludes slow/performance and UI tests). test-fast *args: mix test --exclude slow --exclude ui {{args}} # Affected fast tests only (mix test --stale) with reduced property runs. test-stale *args: PROPERTY_RUNS=25 mix test --stale --exclude slow --exclude ui {{args}} # Run only UI tests ui *args: install-dependencies mix test --only ui {{args}} # Run only slow/performance tests slow *args: install-dependencies mix test --only slow {{args}} # Run only slow/performance tests (alias for consistency) test-slow *args: install-dependencies mix test --only slow {{args}} # Run all tests (fast + slow + ui) test-all *args: install-dependencies mix test {{args}} format: mix format # Catch-all wrapper for arbitrary mix commands not exposed as their own recipe. mix *args: mix {{args}} build-docker-container: docker build --tag mitgliederverwaltung . # This is meant for debugging the container build process only. run-docker-container: build-docker-container docker run -e "SECRET_KEY_BASE=ahK8BeiDaibaige1ahkooS0chie9lo7the7uuzar0eeBeeCh2iereteshee2Oosu" -e='DATABASE_URL=postgres://postgres@localhost:5432/mv_dev' -e='PORT=4040' -e='PHX_HOST=localhost' --network=host mitgliederverwaltung # Usage: # just regen-migrations migration_name [commit_hash] # If commit_hash is given, rollback & delete the migrations from that commit. # Otherwise, rollback & delete all untracked migrations. regen-migrations migration_name commit_hash='': #!/usr/bin/env bash set -euo pipefail # Pick migrations either from the given commit or untracked files if [ -n "{{commit_hash}}" ]; then echo "→ Rolling back migrations from commit {{commit_hash}}" MIG_FILES=$(git show --name-only --pretty=format: "{{commit_hash}}" \ | grep -E "^priv/repo/migrations/|^priv/resource_snapshots") else echo "→ Rolling back all untracked migrations" MIG_FILES=$(git ls-files --others priv/repo/migrations) fi # Roll back in Ash COUNT=$(echo "$MIG_FILES" | wc -l) mix ash_postgres.rollback -n "$COUNT" # Remove the migration files echo removing $MIG_FILES echo "$MIG_FILES" | xargs rm -f # Also clean up any untracked resource snapshots git ls-files --others priv/resource_snapshots | xargs rm -f # Generate a fresh migration mix ash.codegen --name "{{migration_name}}" # Remove all build artifacts clean: mix clean rm -rf .elixir_ls rm -rf _build # Remove Git merge conflict markers from gettext files remove-gettext-conflicts: #!/usr/bin/env bash set -euo pipefail find priv/gettext -type f -exec sed -i '/^<<<<<<>>>>>>/d; /^%%%%%%%/d; /^++++++/d; s/^+//; s/^-//' {} \; # Production environment commands # ================================ # Initialize secrets directory with generated secrets (only if not exists) init-prod-secrets: #!/usr/bin/env bash set -euo pipefail if [ -d "secrets" ]; then echo "Secrets directory already exists. Skipping generation." exit 0 fi echo "Creating secrets directory and generating secrets..." mkdir -p secrets mix phx.gen.secret > secrets/secret_key_base.txt mix phx.gen.secret > secrets/token_signing_secret.txt openssl rand -base64 32 | tr -d '\n' > secrets/db_password.txt touch secrets/oidc_client_secret.txt echo "Secrets generated in ./secrets/" # Start production environment with Docker Compose start-prod: init-prod-secrets docker compose -f docker-compose.prod.yml up -d