buckets/shell.nix

308 lines
10 KiB
Nix

{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
# PHP and tools
php84
php84Packages.composer
symfony-cli
# Node.js and npm (React/Vite SPA)
nodejs_22
# Container tools
podman
podman-compose
# Database client (for direct DB access)
postgresql
# Utilities
git
curl
gnumake
];
shellHook = ''
export USER_ID=$(id -u)
export GROUP_ID=$(id -g)
export PODMAN_USERNS=keep-id
# Compose files (symfony-docker convention: root compose.yaml + compose.override.yaml).
# Both must be passed explicitly so the dev override is merged.
# NOTE: $COMPOSE is invoked unquoted (word-split into args) assumes the repo path
# contains no spaces. Fine here; would break if checked out under a path with spaces.
COMPOSE="podman-compose -f $PWD/compose.yaml -f $PWD/compose.override.yaml"
# ===================
# ALIASES
# ===================
alias pc="$COMPOSE"
# ===================
# DEV COMMANDS
# ===================
dev-up() {
echo "Starting services..."
PODMAN_USERNS=keep-id $COMPOSE up -d "$@"
echo ""
$COMPOSE ps
echo ""
echo "App available at: http://localhost:8100"
}
dev-down() {
if [[ "$1" == "-v" ]]; then
echo "Stopping services and removing volumes..."
$COMPOSE down -v
else
echo "Stopping services..."
$COMPOSE down
fi
}
dev-restart() {
echo "Restarting services..."
$COMPOSE restart "$@"
}
dev-rebuild() {
echo "Rebuilding services (down -v + up)..."
$COMPOSE down -v
PODMAN_USERNS=keep-id $COMPOSE up -d "$@"
echo ""
$COMPOSE ps
echo ""
echo "App available at: http://localhost:8100"
}
dev-logs() {
$COMPOSE logs -f php "$@"
}
dev-logs-db() {
$COMPOSE logs -f database "$@"
}
dev-shell() {
$COMPOSE exec php sh
}
dev-console() {
$COMPOSE exec php php bin/console "$@"
}
dev-composer() {
$COMPOSE exec php composer "$@"
}
# ===================
# QA COMMANDS (run in the php container)
# ===================
dev-test() {
$COMPOSE exec php php bin/phpunit "$@"
}
dev-coverage() {
# Code coverage as a plain text table in the terminal (needs Xdebug, which is installed).
# --colors=never keeps the table readable (the ANSI colors garble it).
# Pass-through args, e.g. scope to one class: dev-coverage --filter BucketRoomCalculator
$COMPOSE exec -e XDEBUG_MODE=coverage php php bin/phpunit --coverage-text --colors=never "$@"
}
dev-stan() {
# Warm the dev cache so phpstan-symfony can read the compiled container, then analyse.
$COMPOSE exec php php bin/console cache:warmup --quiet
$COMPOSE exec php vendor/bin/phpstan analyse --memory-limit=512M "$@"
}
dev-cs() {
# Dry-run code-style check (no changes). Use for CI / verification.
$COMPOSE exec php vendor/bin/php-cs-fixer check --diff "$@"
}
dev-cs-fix() {
# Apply code-style fixes in place.
$COMPOSE exec php vendor/bin/php-cs-fixer fix "$@"
}
# ===================
# FRONTEND COMMANDS (run in the frontend/Vite container)
# ===================
dev-fe-test() {
# Run the Vitest suite once. Pass-through args, e.g.: dev-fe-test src/auth
$COMPOSE exec frontend npm test "$@"
}
dev-fe-test-watch() {
$COMPOSE exec frontend npm run test:watch "$@"
}
dev-fe-lint() {
$COMPOSE exec frontend npm run lint "$@"
}
dev-fe-cs() {
# Prettier formatting check (no changes).
$COMPOSE exec frontend npm run format:check "$@"
}
dev-fe-cs-fix() {
$COMPOSE exec frontend npm run format "$@"
}
dev-fe-build() {
$COMPOSE exec frontend npm run build "$@"
}
dev-e2e() {
# Run the Playwright e2e smoke suite in the `playwright` compose service
# (browsers preinstalled). Needs the stack up (dev-up). NOT the Vitest
# suite that's dev-fe-test. Pass-through args, e.g.: dev-e2e --headed
PODMAN_USERNS=keep-id $COMPOSE --profile e2e run --rm playwright npm test -- "$@"
}
dev-check() {
# Fast pre-commit gate: all static/unit checks, back + front. Fail-fast
# (stops at the first failure). No coverage, no e2e use dev-check-all
# for the thorough version.
echo " backend: tests" && dev-test \
&& echo " backend: phpstan" && dev-stan \
&& echo " backend: cs" && dev-cs \
&& echo " frontend: tests" && dev-fe-test \
&& echo " frontend: lint" && dev-fe-lint \
&& echo " frontend: cs" && dev-fe-cs \
&& echo " frontend: build" && dev-fe-build \
&& echo " dev-check passed"
}
dev-check-all() {
# Thorough gate: everything in dev-check, but with COVERAGE instead of the
# plain test runs, plus the Playwright e2e. Slow; needs the stack up.
# NOTE: frontend coverage (dev-fe-coverage) is not wired yet added in #62
# alongside the @vitest/coverage-v8 setup; until then this runs the plain
# frontend test suite for the frontend leg.
echo " backend: coverage" && dev-coverage \
&& echo " backend: phpstan" && dev-stan \
&& echo " backend: cs" && dev-cs \
&& echo " frontend: tests (coverage pending #62)" && dev-fe-test \
&& echo " frontend: lint" && dev-fe-lint \
&& echo " frontend: cs" && dev-fe-cs \
&& echo " frontend: build" && dev-fe-build \
&& echo " e2e" && dev-e2e \
&& echo " dev-check-all passed"
}
# ===================
# DATABASE / MIGRATION COMMANDS
# ===================
# The Doctrine migration workflow, simplified. Typical loop:
# 1. change an entity mapping
# 2. dev-migrate-diff -> generate ONE migration from the mapping (review it!)
# 3. dev-migrate -> apply to BOTH dev and test DBs
# If you generated/applied a wrong migration: dev-migrate-prev rolls back BOTH DBs,
# then delete the bad migrations/Version*.php file and re-run dev-migrate-diff.
dev-migrate-diff() {
# Generate a migration from the diff between entity mappings and the dev DB schema.
# ALWAYS read the generated migrations/Version*.php before applying it.
echo "Generating migration from entity mapping diff..."
$COMPOSE exec php php bin/console doctrine:migrations:diff "$@"
echo ""
echo ">> Review the new file in migrations/ before running dev-migrate."
}
dev-migrate() {
# Apply pending migrations to BOTH the dev and test databases.
# Interactive: Doctrine will prompt before destructive/unregistered changes read them.
echo "=== Migrating DEV database (buckets) ==="
$COMPOSE exec php php bin/console doctrine:migrations:migrate "$@"
echo ""
echo "=== Migrating TEST database (buckets_test) ==="
$COMPOSE exec php php bin/console doctrine:migrations:migrate --env=test "$@"
}
dev-migrate-prev() {
# Roll back the most recent migration on BOTH the dev and test databases.
echo "=== Rolling back DEV database (buckets) one step ==="
$COMPOSE exec php php bin/console doctrine:migrations:migrate prev "$@"
echo ""
echo "=== Rolling back TEST database (buckets_test) one step ==="
$COMPOSE exec php php bin/console doctrine:migrations:migrate prev --env=test "$@"
}
# ===================
# BUILD COMMANDS
# ===================
base-build() {
local image="forge.lvl0.xyz/lvl0/buckets:latest"
# Check if logged in, prompt if not
if ! podman login --get-login forge.lvl0.xyz &>/dev/null; then
echo "Not logged in to forge.lvl0.xyz"
podman login forge.lvl0.xyz || return 1
fi
echo "Building image: $image"
if ! podman build -t "$image" -f Dockerfile .; then
echo "Build failed!"
return 1
fi
echo ""
echo "Pushing to registry..."
if ! podman push "$image"; then
echo "Push failed!"
return 1
fi
echo ""
echo "Done! Image pushed: $image"
}
# ===================
# WELCOME MESSAGE
# ===================
echo ""
echo "================================================="
echo " Buckets Dev Environment "
echo "================================================="
echo ""
echo " PHP: $(php --version | head -1 | cut -d' ' -f2)"
echo " Symfony: $(symfony version 2>/dev/null | head -1 || echo 'symfony-cli')"
echo " Podman: $(podman --version | cut -d' ' -f3)"
echo ""
echo "Commands:"
echo " dev-up [services] Start all or specific services"
echo " dev-down [-v] Stop services (-v removes volumes)"
echo " dev-rebuild Fresh start (down -v + up)"
echo " dev-restart Restart services"
echo " dev-logs Tail app logs"
echo " dev-logs-db Tail database logs"
echo " dev-shell Shell into app container"
echo " dev-console <cmd> Run Symfony console command"
echo " dev-composer <cmd> Run composer in the container"
echo " dev-test [args] Run PHPUnit (bin/phpunit)"
echo " dev-stan [args] Run PHPStan static analysis"
echo " dev-cs [args] Check code style (dry-run)"
echo " dev-cs-fix [args] Apply code style fixes"
echo " dev-fe-test [args] Run frontend Vitest suite"
echo " dev-fe-lint [args] Lint frontend (oxlint)"
echo " dev-fe-cs [args] Check frontend formatting (Prettier)"
echo " dev-fe-cs-fix Apply frontend formatting"
echo " dev-fe-build Build the frontend (tsc + vite build)"
echo " dev-e2e [args] Run Playwright e2e smoke suite (container)"
echo " dev-check Fast gate: all back+front tests/stan/cs/build"
echo " dev-check-all Thorough gate: dev-check + coverage + e2e"
echo " dev-migrate-diff Generate a migration from entity mappings"
echo " dev-migrate Apply migrations to dev + test DBs"
echo " dev-migrate-prev Roll back one migration on dev + test DBs"
echo " base-build Build and push image"
echo ""
echo "Services:"
echo " php Symfony/FrankenPHP http://localhost:8100"
echo " frontend React/Vite SPA http://localhost:5173"
echo " database Postgres 16 localhost:5433"
echo ""
'';
}