#!/bin/bash # Fission Python Project Creator # Creates a new fission python project from template set -euo pipefail # Get the directory where this script is located SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TEMPLATE_DIR="$SCRIPT_DIR/template" usage() { echo "Usage: $0 [destination-directory]" echo " project-name: Name for the new fission project" echo " destination-directory: Optional directory where project should be created (default: current directory)" exit 1 } if [[ $# -lt 1 || $# -gt 2 ]]; then usage fi PROJECT_NAME="$1" DEST_DIR="${2:-./}" # Validate project name if [[ ! "$PROJECT_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then echo "Error: Project name can only contain letters, numbers, hyphens, and underscores" exit 1 fi # Create destination directory if it doesn't exist mkdir -p "$DEST_DIR" PROJECT_PATH="$DEST_DIR/$PROJECT_NAME" # Check if project already exists if [[ -d "$PROJECT_PATH" ]]; then echo "Error: Project directory '$PROJECT_PATH' already exists" exit 1 fi # Check if template exists if [[ ! -d "$TEMPLATE_DIR" ]]; then echo "Error: Template directory not found at '$TEMPLATE_DIR'" exit 1 fi echo "Creating fission python project '$PROJECT_NAME' in '$PROJECT_PATH'..." # Copy template excluding unwanted files/directories rsync -av --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' --exclude='.env' \ "$TEMPLATE_DIR/" "$PROJECT_PATH/" # Replace placeholder values in configuration files # 1. deployment.json - replace ${PROJECT_NAME} and old eom-quota references if [[ -f "$PROJECT_PATH/.fission/deployment.json" ]]; then sed -i "s/\${PROJECT_NAME}/$PROJECT_NAME/g" "$PROJECT_PATH/.fission/deployment.json" sed -i "s/eom-quota/$PROJECT_NAME/g" "$PROJECT_PATH/.fission/deployment.json" sed -i "s/fission-eom-quota/fission-$PROJECT_NAME/g" "$PROJECT_PATH/.fission/deployment.json" fi # 2. Override files - dev-deployment.json and local-deployment.json for override in dev-deployment.json local-deployment.json; do if [[ -f "$PROJECT_PATH/.fission/$override" ]]; then sed -i "s/\${PROJECT_NAME}/$PROJECT_NAME/g" "$PROJECT_PATH/.fission/$override" sed -i "s/eom-quota/$PROJECT_NAME/g" "$PROJECT_PATH/.fission/$override" sed -i "s/fission-eom-quota/fission-$PROJECT_NAME/g" "$PROJECT_PATH/.fission/$override" fi done # 3. helpers.py - update SECRET_NAME and CONFIG_NAME if [[ -f "$PROJECT_PATH/src/helpers.py" ]]; then sed -i "s/\${PROJECT_NAME}/$PROJECT_NAME/g" "$PROJECT_PATH/src/helpers.py" fi # 4. README.md - update with project name and clean up if [[ -f "$PROJECT_PATH/README.md" ]]; then sed -i "s/\${PROJECT_NAME}/$PROJECT_NAME/g" "$PROJECT_PATH/README.md" sed -i "s/^# Fission Python Template/# $PROJECT_NAME/g" "$PROJECT_PATH/README.md" sed -i "s/your-service-py/$PROJECT_NAME-py/g" "$PROJECT_PATH/README.md" sed -i "s/your-package/$PROJECT_NAME/g" "$PROJECT_PATH/README.md" fi # ========== VALIDATION ========== echo "" echo "🔍 Validating project structure..." validation_errors=0 validation_warnings=0 # 1. Check build.sh exists and is executable if [[ -f "$PROJECT_PATH/src/build.sh" ]]; then if [[ -x "$PROJECT_PATH/src/build.sh" ]]; then echo " ✓ build.sh exists and is executable" else echo " ⚠ build.sh exists but is not executable. Fixing with chmod +x..." chmod +x "$PROJECT_PATH/src/build.sh" validation_warnings=$((validation_warnings + 1)) fi else echo " ✗ ERROR: src/build.sh is missing (required)" validation_errors=$((validation_errors + 1)) fi # 2. Check deployment.json references ./build.sh if [[ -f "$PROJECT_PATH/.fission/deployment.json" ]]; then if grep -q '"./build.sh"' "$PROJECT_PATH/.fission/deployment.json" 2>/dev/null; then echo " ✓ deployment.json references ./build.sh" else echo " ⚠ deployment.json does not reference './build.sh' in buildcmd" validation_warnings=$((validation_warnings + 1)) fi else echo " ✗ ERROR: .fission/deployment.json is missing" validation_errors=$((validation_errors + 1)) fi # 3. Check requirements.txt exists if [[ -f "$PROJECT_PATH/src/requirements.txt" ]]; then echo " ✓ requirements.txt exists" # Check for essential dependencies missing_deps=() if ! grep -qi 'pydantic' "$PROJECT_PATH/src/requirements.txt"; then missing_deps+=("pydantic") fi if ! grep -qi 'flask' "$PROJECT_PATH/src/requirements.txt"; then missing_deps+=("flask") fi if [[ ${#missing_deps[@]} -gt 0 ]]; then echo " ⚠ requirements.txt missing recommended dependencies: ${missing_deps[*]}" validation_warnings=$((validation_warnings + 1)) else echo " ✓ Contains essential dependencies (pydantic, flask)" fi else echo " ✗ ERROR: src/requirements.txt is missing (required)" validation_errors=$((validation_errors + 1)) fi # 4. Check .gitea/workflows directory exists if [[ -d "$PROJECT_PATH/.gitea/workflows" ]]; then echo " ✓ .gitea/workflows directory exists" # Count workflow files workflow_count=$(find "$PROJECT_PATH/.gitea/workflows" -type f -name "*.yaml" 2>/dev/null | wc -l) if [[ $workflow_count -ge 4 ]]; then echo " ✓ Found $workflow_count workflow files" else echo " ⚠ Only found $workflow_count workflow files (expected at least 4)" validation_warnings=$((validation_warnings + 1)) fi else echo " ⚠ .gitea/workflows directory is missing (recommended for CI/CD)" validation_warnings=$((validation_warnings + 1)) fi # 5. Check for Python files with docstrings (basic check, excluding __init__.py) python_files=$(find "$PROJECT_PATH/src" -type f -name "*.py" ! -name "__init__.py" 2>/dev/null | wc -l) if [[ $python_files -gt 0 ]]; then files_with_docstrings=$(grep -l '"""' "$PROJECT_PATH/src/"*.py 2>/dev/null | grep -v '__init__.py' | wc -l) if [[ $files_with_docstrings -eq $python_files ]]; then echo " ✓ All Python files contain docstrings" else echo " ⚠ Only $files_with_docstrings/$python_files Python files have docstrings" validation_warnings=$((validation_warnings + 1)) fi else echo " ⚠ No Python files found in src/ to check docstrings" fi # 6. Check for pydantic BaseModel usage in models.py (if exists) if [[ -f "$PROJECT_PATH/src/models.py" ]]; then if grep -q "pydantic.BaseModel" "$PROJECT_PATH/src/models.py"; then echo " ✓ models.py uses pydantic.BaseModel" else echo " ⚠ models.py does not appear to use pydantic.BaseModel (recommended for HTTP triggers)" validation_warnings=$((validation_warnings + 1)) fi fi # Summary echo "" if [[ $validation_errors -eq 0 && $validation_warnings -eq 0 ]]; then echo "✅ All validations passed!" elif [[ $validation_errors -eq 0 ]]; then echo "⚠️ $validation_warnings validation warning(s). Project is usable but review above." else echo "❌ $validation_errors validation error(s) and $validation_warnings warning(s)." echo " The project was created but may have issues. Review the messages above." fi # Create basic .env file if it doesn't exist if [[ ! -f "$PROJECT_PATH/.env" ]]; then cat > "$PROJECT_PATH/.env" << EOF # Environment variables for $PROJECT_NAME # Copy this to .env.local for local overrides FISSION_ROUTE_SERVICE_ENDPOINT=http://router.fission.svc.cluster.local EOF fi echo "" echo "🎉 Project '$PROJECT_NAME' created!" if [[ $validation_errors -eq 0 && $validation_warnings -eq 0 ]]; then echo "✅ All validations passed!" elif [[ $validation_errors -eq 0 ]]; then echo "⚠️ $validation_warnings warning(s) found - review above." else echo "❌ $validation_errors error(s) and $validation_warnings warning(s) - review above." fi echo echo "Next steps:" echo "1. cd $PROJECT_PATH" echo "2. Review and update configuration in .fission/deployment.json" echo "3. Install dependencies: pip install --upgrade --force-reinstall -r dev-requirements.txt" echo "4. Customize your functions in the src/ directory (see examples/ for patterns)" echo "5. Ensure HTTP trigger functions have proper fission config in docstrings" echo "6. Write tests in test/ directory" echo "7. Create Kubernetes secrets: kubectl create secret generic fission-$PROJECT_NAME-env --from-literal=... (see docs/SECRETS.md)" echo "8. Build and deploy: ./src/build.sh && fission deploy"