#!/bin/bash set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Function to print colored output print_status() { echo -e "${GREEN}[INFO]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Cleanup function cleanup() { # Optional cleanup - can be commented out to keep build directory for inspection # if [ -n "${TEMP_DIR:-}" ] && [ -d "$TEMP_DIR" ]; then # print_status "Keeping build directory for inspection: $TEMP_DIR" # fi print_status "Test completed. Build directory: ${TEMP_DIR:-}" } # Set up trap for cleanup on exit trap cleanup EXIT # Check for required tools check_tool() { if ! command -v "$1" &> /dev/null; then print_error "$1 is not installed. Please install it first." exit 1 fi } # Main test function main() { print_status "Starting template test..." # Get the template directory TEMPLATE_DIR="$(cd "$(dirname "$0")" && pwd)" # Check which template tool is available CRUFT_AVAILABLE=0 COOKIECUTTER_AVAILABLE=0 if command -v cruft &> /dev/null; then CRUFT_AVAILABLE=1 fi if command -v cookiecutter &> /dev/null; then COOKIECUTTER_AVAILABLE=1 fi if [ "$CRUFT_AVAILABLE" -eq 0 ] && [ "$COOKIECUTTER_AVAILABLE" -eq 0 ]; then print_error "Neither cruft nor cookiecutter is installed. Please install one of them." print_status "Install with: pip install cruft or pip install cookiecutter" exit 1 fi if git -C "$TEMPLATE_DIR" rev-parse --is-inside-work-tree &> /dev/null; then if [ -n "$(git -C "$TEMPLATE_DIR" status --porcelain)" ]; then if [ "$COOKIECUTTER_AVAILABLE" -eq 1 ]; then TEMPLATE_TOOL="cookiecutter" print_warning "Working tree is dirty; using cookiecutter to include local changes" else TEMPLATE_TOOL="cruft" print_warning "Working tree is dirty but cookiecutter is unavailable; using cruft" fi fi fi if [ -z "${TEMPLATE_TOOL:-}" ]; then if [ "$CRUFT_AVAILABLE" -eq 1 ]; then TEMPLATE_TOOL="cruft" print_status "Using cruft for template generation" else TEMPLATE_TOOL="cookiecutter" print_status "Using cookiecutter for template generation" fi fi # Check for uv check_tool "uv" print_status "Template directory: $TEMPLATE_DIR" # Set up build directory TEMP_DIR="$TEMPLATE_DIR/build" # Check if build directory exists and ask for confirmation if [ -d "$TEMP_DIR" ]; then print_warning "Build directory already exists: $TEMP_DIR" read -p "Remove existing build directory and continue? (y/n) [y]: " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]] && [[ ! -z $REPLY ]]; then print_status "Aborted by user" exit 0 fi print_status "Removing existing build directory..." rm -rf "$TEMP_DIR" fi # Create build directory mkdir -p "$TEMP_DIR" print_status "Created build directory: $TEMP_DIR" # Generate project from template print_status "Generating example project from template..." # Default values for the template PROJECT_NAME="test-project" if [ "$TEMPLATE_TOOL" = "cruft" ]; then cd "$TEMP_DIR" cruft create "$TEMPLATE_DIR" \ --no-input \ --extra-context '{"project_name": "Test Project", "project_slug": "test-project", "package_name": "test_project", "description": "A test project", "author_name": "Test Author", "author_email": "test@example.com", "version": "0.1.0"}' \ || { print_error "Failed to generate project with cruft"; exit 1; } else cd "$TEMP_DIR" cookiecutter "$TEMPLATE_DIR" \ --no-input \ project_name="Test Project" \ project_slug="test-project" \ package_name="test_project" \ description="A test project" \ author_name="Test Author" \ author_email="test@example.com" \ version="0.1.0" \ || { print_error "Failed to generate project with cookiecutter"; exit 1; } fi # Navigate to generated project cd "$TEMP_DIR/$PROJECT_NAME" print_status "Generated project at: $(pwd)" # List generated files print_status "Generated files:" ls -la # Ensure lockfile exists and install dependencies print_status "Checking for generated uv.lock..." [ -f "uv.lock" ] || { print_error "uv.lock was not generated"; exit 1; } print_status "Installing dependencies with uv (frozen)..." uv sync --frozen --group dev || { print_error "Failed to install dependencies"; exit 1; } # Run ruff check print_status "Running ruff check..." uv run ruff check src tests || { print_error "Ruff check failed"; exit 1; } # Run ruff format check print_status "Running ruff format check..." uv run ruff format --check src tests || { print_error "Ruff format check failed"; exit 1; } # Run mypy print_status "Running mypy type checking..." uv run mypy src || { print_error "Mypy type checking failed"; exit 1; } # Run tests print_status "Running tests..." uv run pytest || { print_error "Tests failed"; exit 1; } # Run tests with coverage print_status "Running tests with coverage..." uv run pytest --cov=src --cov-report=term-missing || { print_error "Tests with coverage failed"; exit 1; } # Try running invoke tasks print_status "Testing invoke lint task..." uv run invoke lint || { print_error "Invoke lint task failed"; exit 1; } print_status "Testing invoke test task..." uv run invoke test || { print_error "Invoke test task failed"; exit 1; } print_status "✅ All tests passed successfully!" print_status "Template is working correctly." } # Run main function main "$@"