rdev/cookbooks/scripts/fullstack-test.sh
jordan c59d348040 chore: prepare for composable monorepo template implementation
This commit captures the current state before implementing the composable
monorepo template system. Key changes included:

Infrastructure:
- Add CockroachDB provisioner adapter for database provisioning
- Add Redis provisioner adapter for cache provisioning
- Add build events system with PostgreSQL storage
- Add WebSocket endpoint for real-time build progress

Code agent improvements:
- Fix Claude Code adapter to use default allowed tools instead of dangerously-skip-permissions
- Add context-aware stream closing for cancellation support
- Improve parser tests for edge cases

Build system:
- Add build event constants and metrics
- Remove deprecated git_operations.go (replaced by pod_git_operations.go)
- Add rollback logic for multi-step provisioning operations

Documentation:
- Add composable-monorepo feature documentation
- Add DNS/Cloudflare service documentation
- Update deployment and troubleshooting guides

Cookbooks:
- Add fullstack-app cookbook
- Refactor landing-test with shared library

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 11:39:28 -07:00

203 lines
5.6 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
# Full-Stack App E2E Test Script
# Usage: ./cookbooks/scripts/fullstack-test.sh <command> <project-name>
# Commands: run, status, teardown
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
COMMAND="${1:-}"
PROJECT_NAME="${2:-}"
if [[ -z "$COMMAND" || -z "$PROJECT_NAME" ]]; then
echo "Usage: $0 <command> <project-name>"
echo "Commands:"
echo " run - Create project and run full-stack build"
echo " status - Check build and deployment status"
echo " teardown - Delete the project"
exit 1
fi
# Full-stack app build prompt
FULLSTACK_PROMPT='Build a full-stack task management application with the following structure:
FRONTEND (Next.js 14 + shadcn/ui):
- Create a Next.js 14 app with App Router in /frontend
- Use shadcn/ui for all components (install with npx shadcn-ui@latest init)
- Dark theme with modern aesthetic
- Pages: Dashboard showing tasks, Add Task form, Task detail view
- Use Tailwind CSS for styling
- Connect to backend API at /api proxy
BACKEND (Go):
- Create a Go HTTP server in /backend using chi router
- Endpoints: GET /api/tasks, POST /api/tasks, GET /api/tasks/{id}, DELETE /api/tasks/{id}
- In-memory task storage (no database needed)
- Structured JSON responses
- CORS middleware for frontend
DOCKER:
- /frontend/Dockerfile: Multi-stage build for Next.js (node:20-alpine)
- /backend/Dockerfile: Multi-stage build for Go (golang:1.22-alpine)
- /docker-compose.yml: Run both services, frontend proxies to backend
CI/CD:
- /.woodpecker.yml: Build both images, push to registry, deploy to k8s
Create all necessary files including package.json, go.mod, and configuration files.'
# Test backend API
test_backend_api() {
local domain="$1"
echo "Testing backend API..."
# Test GET /api/tasks
local response
response=$(curl -s "https://$domain/api/tasks" 2>/dev/null || echo '{"error":"failed"}')
if echo "$response" | jq -e '.' > /dev/null 2>&1; then
echo " GET /api/tasks: OK"
echo " Response: $response"
return 0
else
echo " GET /api/tasks: FAILED"
echo " Response: $response"
return 1
fi
}
run_flow() {
echo "=== Full-Stack App E2E Test ==="
echo "Project: $PROJECT_NAME"
echo ""
# Step 1: Create project with build
echo "Step 1: Creating project and submitting full-stack build..."
local create_result
# Build the JSON payload (prompt, auto_commit, auto_push are top-level fields)
local payload
payload=$(jq -n \
--arg name "$PROJECT_NAME" \
--arg desc "Full-stack app E2E test" \
--arg prompt "$FULLSTACK_PROMPT" \
'{
name: $name,
description: $desc,
prompt: $prompt,
auto_commit: true,
auto_push: true
}')
create_result=$(api_call POST "/project/create-and-build" "$payload")
echo "$create_result" | jq '.'
local domain
domain=$(echo "$create_result" | jq -r '.data.domain // .domain // ""')
local task_id
task_id=$(echo "$create_result" | jq -r '.data.task_id // .task_id // ""')
if [[ -z "$domain" || -z "$task_id" ]]; then
echo "ERROR: Failed to create project"
exit 1
fi
echo ""
echo "Domain: $domain"
echo "Build Task: $task_id"
echo ""
# Step 2: Wait for build
echo "Step 2: Waiting for Claude to build the full-stack app..."
if ! wait_for_build "$task_id"; then
echo "ERROR: Build failed"
exit 1
fi
echo ""
# Step 3: Wait for CI pipeline
echo "Step 3: Waiting for CI pipeline to build and deploy..."
if ! wait_for_pipeline "$PROJECT_NAME"; then
echo "WARNING: Pipeline may have failed, continuing to check site..."
fi
echo ""
# Step 4: Wait for site
echo "Step 4: Verifying site is accessible..."
if ! wait_for_site "$domain"; then
echo "ERROR: Site not accessible"
exit 1
fi
echo ""
# Step 5: Test backend API
echo "Step 5: Testing backend API..."
if ! test_backend_api "$domain"; then
echo "WARNING: Backend API test failed"
fi
echo ""
# Summary
echo "=== E2E Test Results ==="
echo "Project created: PASS"
echo "Build completed: PASS"
echo "CI Pipeline: $(wait_for_pipeline "$PROJECT_NAME" > /dev/null 2>&1 && echo "PASS" || echo "CHECK")"
echo "Site accessible: PASS"
echo "Backend API: $(test_backend_api "$domain" > /dev/null 2>&1 && echo "PASS" || echo "CHECK")"
echo ""
echo "Site URL: https://$domain"
echo "Git repo: https://git.threesix.ai/jordan/$PROJECT_NAME"
echo "CI: https://ci.threesix.ai/jordan/$PROJECT_NAME"
}
check_status() {
echo "=== Project Status: $PROJECT_NAME ==="
echo ""
# Get project info
local project_result
project_result=$(api_call GET "/projects/$PROJECT_NAME")
echo "Project:"
echo "$project_result" | jq '.'
echo ""
# Get latest build
echo "Latest Builds:"
api_call GET "/projects/$PROJECT_NAME/builds" | jq '.data[:3]'
echo ""
# Get latest pipeline
echo "Latest Pipelines:"
api_call GET "/projects/$PROJECT_NAME/pipelines" | jq '.data[:3]'
}
teardown() {
echo "=== Tearing down: $PROJECT_NAME ==="
local result
result=$(api_call DELETE "/project/$PROJECT_NAME")
echo "$result" | jq '.'
echo ""
echo "Project deleted. Gitea repo preserved."
}
case "$COMMAND" in
run)
run_flow
;;
status)
check_status
;;
teardown)
teardown
;;
*)
echo "Unknown command: $COMMAND"
echo "Valid commands: run, status, teardown"
exit 1
;;
esac