Common Scripts¶
Ready-to-use script templates for development.
Development Setup¶
Project Setup¶
#!/bin/bash
# scripts/setup.sh - Initial project setup
set -euo pipefail
echo "Setting up development environment..."
# Check prerequisites
command -v docker >/dev/null 2>&1 || { echo "Docker required but not installed."; exit 1; }
command -v uv >/dev/null 2>&1 || { echo "uv required but not installed."; exit 1; }
# Create environment file
if [[ ! -f .env ]]; then
echo "Creating .env from template..."
cp .env.example .env
echo "Please update .env with your settings"
fi
# Install Python dependencies
echo "Installing Python dependencies..."
uv sync
# Start services
echo "Starting Docker services..."
docker compose up -d db redis
# Wait for database
echo "Waiting for database..."
sleep 5
# Run migrations
echo "Running migrations..."
uv run alembic upgrade head
# Seed development data
if [[ "${1:-}" == "--seed" ]]; then
echo "Seeding development data..."
uv run python scripts/seed.py
fi
echo "Setup complete!"
echo "Run 'uv run uvicorn app.main:app --reload' to start the server"
Development Start¶
#!/bin/bash
# scripts/dev.sh - Start development environment
set -euo pipefail
# Start Docker services
docker compose up -d db redis
# Wait for services
echo "Waiting for services..."
until docker compose exec -T db pg_isready -U postgres > /dev/null 2>&1; do
sleep 1
done
# Run any pending migrations
uv run alembic upgrade head
# Start the application
echo "Starting application..."
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
Database Scripts¶
Database Reset¶
#!/bin/bash
# scripts/reset-db.sh - Reset database to clean state
set -euo pipefail
DB_NAME="${DB_NAME:-sartiq}"
DB_USER="${DB_USER:-postgres}"
DB_HOST="${DB_HOST:-localhost}"
echo "This will DELETE ALL DATA in $DB_NAME"
read -p "Continue? [y/N] " confirm
if [[ "$confirm" != "y" ]]; then
echo "Aborted."
exit 0
fi
echo "Terminating connections..."
psql -h "$DB_HOST" -U "$DB_USER" -d postgres -c "
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = '$DB_NAME' AND pid != pg_backend_pid();
" 2>/dev/null || true
echo "Dropping database..."
dropdb -h "$DB_HOST" -U "$DB_USER" --if-exists "$DB_NAME"
echo "Creating database..."
createdb -h "$DB_HOST" -U "$DB_USER" "$DB_NAME"
echo "Running migrations..."
uv run alembic upgrade head
echo "Database reset complete!"
Database Backup¶
#!/bin/bash
# scripts/backup-db.sh - Backup database
set -euo pipefail
DB_NAME="${DB_NAME:-sartiq}"
DB_USER="${DB_USER:-postgres}"
DB_HOST="${DB_HOST:-localhost}"
BACKUP_DIR="${BACKUP_DIR:-./backups}"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.dump"
echo "Backing up $DB_NAME to $BACKUP_FILE..."
pg_dump -h "$DB_HOST" -U "$DB_USER" -Fc "$DB_NAME" > "$BACKUP_FILE"
# Compress
gzip "$BACKUP_FILE"
# Clean old backups (keep last 7)
find "$BACKUP_DIR" -name "*.dump.gz" -mtime +7 -delete
echo "Backup complete: ${BACKUP_FILE}.gz"
ls -lh "${BACKUP_FILE}.gz"
Seed Data¶
#!/bin/bash
# scripts/seed.sh - Seed development data
set -euo pipefail
echo "Seeding development data..."
# Option 1: SQL file
psql -h localhost -U postgres -d sartiq -f seeds/dev_data.sql
# Option 2: Python script
# uv run python seeds/run.py
echo "Seeding complete!"
Testing Scripts¶
Run Tests¶
#!/bin/bash
# scripts/test.sh - Run tests with options
set -euo pipefail
# Default values
COVERAGE=false
VERBOSE=false
WATCH=false
FILTER=""
usage() {
echo "Usage: $0 [-c|--coverage] [-v|--verbose] [-w|--watch] [filter]"
exit 1
}
while [[ $# -gt 0 ]]; do
case $1 in
-c|--coverage) COVERAGE=true; shift ;;
-v|--verbose) VERBOSE=true; shift ;;
-w|--watch) WATCH=true; shift ;;
-h|--help) usage ;;
*) FILTER="$1"; shift ;;
esac
done
# Build pytest arguments
ARGS=()
if $COVERAGE; then
ARGS+=("--cov=app" "--cov-report=html" "--cov-report=term-missing")
fi
if $VERBOSE; then
ARGS+=("-v")
fi
if [[ -n "$FILTER" ]]; then
ARGS+=("-k" "$FILTER")
fi
if $WATCH; then
# Use pytest-watch
uv run ptw -- "${ARGS[@]}"
else
uv run pytest "${ARGS[@]}"
fi
CI Test Script¶
#!/bin/bash
# scripts/ci-test.sh - CI testing with proper setup
set -euo pipefail
echo "=== Setting up test environment ==="
# Start test database
docker compose -f docker-compose.test.yml up -d
# Wait for database
echo "Waiting for database..."
until docker compose -f docker-compose.test.yml exec -T db pg_isready -U postgres > /dev/null 2>&1; do
sleep 1
done
# Run migrations on test database
DATABASE_URL="postgresql://postgres:postgres@localhost:5433/test" \
uv run alembic upgrade head
echo "=== Running tests ==="
# Run tests
DATABASE_URL="postgresql://postgres:postgres@localhost:5433/test" \
uv run pytest --cov=app --cov-report=xml -v
EXIT_CODE=$?
echo "=== Cleanup ==="
docker compose -f docker-compose.test.yml down -v
exit $EXIT_CODE
Deployment Scripts¶
Build and Push¶
#!/bin/bash
# scripts/build.sh - Build and push Docker image
set -euo pipefail
REGISTRY="${REGISTRY:-ghcr.io/yourorg}"
IMAGE_NAME="${IMAGE_NAME:-sartiq}"
VERSION="${VERSION:-$(git rev-parse --short HEAD)}"
# Build image
echo "Building $REGISTRY/$IMAGE_NAME:$VERSION..."
docker build -t "$REGISTRY/$IMAGE_NAME:$VERSION" .
docker tag "$REGISTRY/$IMAGE_NAME:$VERSION" "$REGISTRY/$IMAGE_NAME:latest"
# Push image
if [[ "${PUSH:-false}" == "true" ]]; then
echo "Pushing image..."
docker push "$REGISTRY/$IMAGE_NAME:$VERSION"
docker push "$REGISTRY/$IMAGE_NAME:latest"
fi
echo "Build complete: $REGISTRY/$IMAGE_NAME:$VERSION"
Deploy¶
#!/bin/bash
# scripts/deploy.sh - Deploy to environment
set -euo pipefail
ENVIRONMENT="${1:-}"
if [[ -z "$ENVIRONMENT" ]]; then
echo "Usage: $0 <environment>"
echo " environment: staging, production"
exit 1
fi
case "$ENVIRONMENT" in
staging)
DEPLOY_HOST="staging.example.com"
;;
production)
read -p "Deploy to PRODUCTION? [y/N] " confirm
if [[ "$confirm" != "y" ]]; then
echo "Aborted."
exit 0
fi
DEPLOY_HOST="prod.example.com"
;;
*)
echo "Unknown environment: $ENVIRONMENT"
exit 1
;;
esac
VERSION=$(git rev-parse --short HEAD)
echo "Deploying $VERSION to $ENVIRONMENT..."
# SSH deploy (example)
ssh "deploy@$DEPLOY_HOST" << EOF
cd /app
docker compose pull
docker compose up -d
docker compose exec -T api alembic upgrade head
EOF
echo "Deployed $VERSION to $ENVIRONMENT"
Utility Scripts¶
Cleanup¶
#!/bin/bash
# scripts/cleanup.sh - Clean temporary files and caches
set -euo pipefail
echo "Cleaning up..."
# Python cache
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
find . -type f -name "*.pyc" -delete 2>/dev/null || true
# Coverage
rm -rf htmlcov .coverage coverage.xml 2>/dev/null || true
# Node
rm -rf node_modules/.cache 2>/dev/null || true
# Build artifacts
rm -rf dist build .next out 2>/dev/null || true
# Docker
if [[ "${DOCKER:-false}" == "true" ]]; then
echo "Pruning Docker..."
docker system prune -f
fi
echo "Cleanup complete!"
Health Check¶
#!/bin/bash
# scripts/health.sh - Check service health
set -euo pipefail
API_URL="${API_URL:-http://localhost:8000}"
DB_HOST="${DB_HOST:-localhost}"
echo "Checking services..."
# API health
if curl -sf "$API_URL/health" > /dev/null; then
echo "✓ API is healthy"
else
echo "✗ API is down"
fi
# Database
if pg_isready -h "$DB_HOST" -U postgres > /dev/null 2>&1; then
echo "✓ Database is healthy"
else
echo "✗ Database is down"
fi
# Redis
if redis-cli -h localhost ping > /dev/null 2>&1; then
echo "✓ Redis is healthy"
else
echo "✗ Redis is down"
fi
# Docker services
echo ""
echo "Docker containers:"
docker compose ps
Generate API Client¶
#!/bin/bash
# scripts/generate-client.sh - Generate TypeScript API client
set -euo pipefail
API_URL="${API_URL:-http://localhost:8000}"
OUTPUT_DIR="${OUTPUT_DIR:-./frontend/src/api}"
echo "Fetching OpenAPI spec..."
curl -s "$API_URL/openapi.json" > /tmp/openapi.json
echo "Generating TypeScript client..."
npx openapi-typescript-codegen \
--input /tmp/openapi.json \
--output "$OUTPUT_DIR" \
--client fetch
echo "Client generated at $OUTPUT_DIR"
Make Integration¶
If you prefer Makefiles:
# Makefile
.PHONY: dev test lint format migrate seed
dev:
./scripts/dev.sh
test:
./scripts/test.sh
test-cov:
./scripts/test.sh --coverage
lint:
uv run ruff check .
format:
uv run ruff format .
migrate:
uv run alembic upgrade head
seed:
./scripts/seed.sh
reset-db:
./scripts/reset-db.sh
clean:
./scripts/cleanup.sh
Usage: