rdev/cookbooks/scripts/landing-test.sh
jordan c280a92012 feat: add operations audit system and template improvements
Operations Audit (new feature):
- Add Operation domain model with status tracking (pending, running, completed, failed, cancelled)
- Add OperationRepository with PostgreSQL implementation
- Add OperationService for CRUD and lifecycle management
- Add operations handlers (list, get, cancel endpoints)
- Add migration 015_operations.sql for operations table
- Add operation cleanup worker for stale operation handling
- Add ErrOperationNotFound to domain errors

Template Improvements:
- Add CLAUDE.md configuration files to astro-landing, default, and go-api templates
- Fix PORT template variable usage in nginx configs for app templates
- Add replace directives for local pkg module in Go templates
- Simplify Go service/worker Dockerfiles for workspace builds
- Fix TypeScript error in logger template

Other:
- Refactor landing-test.sh cookbook script
- Update CLAUDE.md version reference

Note: Some files exceed 500-line limit (pre-existing debt + new feature)
- component.go: 550 lines (unchanged, pre-existing)
- main.go: 522 lines (added operations wiring)
- operation_repo.go: 569 lines (new, needs splitting)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 19:08:57 -07:00

198 lines
5.7 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
# Landing Page Cookbook Test Script
# Tests the composable landing page flow from cookbooks/landing-page.md
#
# Flow:
# 1. Create project (monorepo skeleton)
# 2. Add app-astro component
# 3. Wait for CI pipeline
# 4. Verify site is live
#
# Usage:
# ./cookbooks/scripts/landing-test.sh run [name] # Run the full flow
# ./cookbooks/scripts/landing-test.sh status [name] # Check current status
# ./cookbooks/scripts/landing-test.sh diagnose [name] # Deep diagnostic analysis
# ./cookbooks/scripts/landing-test.sh teardown [name] # Clean up test resources
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
COMMAND="${1:-}"
PROJECT_NAME="${2:-landing-test-$(date +%s)}"
if [[ -z "$COMMAND" ]]; then
echo "Landing Page E2E Test Script"
echo ""
echo "Usage: $0 <command> [project-name]"
echo ""
echo "Commands:"
echo " run - Run the full composable landing page flow"
echo " status - Check project and component status"
echo " diagnose - Deep diagnostic of pipeline and site issues"
echo " teardown - Delete project (preserves git repo)"
echo ""
echo "Examples:"
echo " $0 run my-landing"
echo " $0 status my-landing"
echo " $0 diagnose my-landing"
echo " $0 teardown my-landing"
echo ""
exit 1
fi
# Main run flow
run_flow() {
print_header "Landing Page E2E Test (Composable)"
echo "Project: $PROJECT_NAME"
# Step 1: Create project (monorepo skeleton)
print_header "Step 1: Creating project skeleton"
local create_response
create_response=$(api_call POST "/project" "{\"name\": \"$PROJECT_NAME\", \"description\": \"Landing page E2E test\"}")
echo "$create_response" | jq '.'
local domain
domain=$(echo "$create_response" | jq -r '.data.domain // ""')
if [[ -z "$domain" || "$domain" == "null" ]]; then
print_error "Failed to create project"
exit 1
fi
print_success "Project created: $PROJECT_NAME"
echo " Domain: $domain"
echo " Git: https://git.threesix.ai/$(get_git_owner)/$PROJECT_NAME"
# Step 2: Add app-astro component
print_header "Step 2: Adding landing page component (app-astro)"
local component_response
component_response=$(api_call POST "/projects/$PROJECT_NAME/components" '{"type": "app-astro", "name": "landing", "template": "app-astro"}')
local component_path
component_path=$(echo "$component_response" | jq -r '.data.path // ""')
if [[ -z "$component_path" || "$component_path" == "null" ]]; then
print_error "Failed to add component"
echo "$component_response" | jq '.'
exit 1
fi
local component_port
component_port=$(echo "$component_response" | jq -r '.data.port // "N/A"')
print_success "Component added: $component_path (port: $component_port)"
# Step 3: Wait for pipeline (auto-diagnoses on failure)
print_header "Step 3: Waiting for CI pipeline"
if ! wait_for_pipeline "$PROJECT_NAME"; then
print_warning "Pipeline failed, continuing to check site..."
fi
# Step 4: Wait for site (auto-diagnoses on timeout)
print_header "Step 4: Verifying site is accessible"
if ! wait_for_site "$domain" 30 5 "$PROJECT_NAME"; then
print_error "Site not accessible"
exit 1
fi
# Summary
print_header "Test Complete"
print_success "Project created: $PROJECT_NAME"
print_success "Landing page deployed"
echo ""
echo "Site URL: https://$domain"
echo "Git repo: https://git.threesix.ai/$(get_git_owner)/$PROJECT_NAME"
echo "CI: https://ci.threesix.ai/$(get_git_owner)/$PROJECT_NAME"
echo ""
echo "To customize: POST /projects/$PROJECT_NAME/builds with a prompt"
echo "To teardown: $0 teardown $PROJECT_NAME"
}
# Check status
check_status() {
print_header "Project Status: $PROJECT_NAME"
echo "Project:"
api_call GET "/project/$PROJECT_NAME" | jq '.data // .'
echo ""
echo "Components:"
api_call GET "/projects/$PROJECT_NAME/components" | jq '.data // .'
echo ""
echo "Latest Pipelines:"
api_call GET "/projects/$PROJECT_NAME/pipelines" | jq '.data[:3] // .'
}
# Deep diagnostic
diagnose() {
print_header "Diagnostic: $PROJECT_NAME"
# Get project info for domain
local project
project=$(api_call GET "/project/$PROJECT_NAME")
local domain
domain=$(echo "$project" | jq -r '.data.domain // ""')
if [[ -z "$domain" || "$domain" == "null" ]]; then
print_error "Project not found or no domain assigned"
echo "$project" | jq '.'
return 1
fi
echo "Project: $PROJECT_NAME"
echo "Domain: https://$domain"
echo "Git: https://git.threesix.ai/$(get_git_owner)/$PROJECT_NAME"
echo "CI: https://ci.threesix.ai/$(get_git_owner)/$PROJECT_NAME"
# Run pipeline diagnostics
diagnose_pipeline_failure "$PROJECT_NAME"
# Run site diagnostics
diagnose_site_failure "$domain" "$PROJECT_NAME"
print_header "Summary"
echo "To retry the pipeline:"
print_cmd "Push a commit to trigger CI, or manually trigger from Woodpecker UI"
echo ""
echo "To check real-time logs:"
print_cmd "kubectl logs -n projects -l app=$PROJECT_NAME -f"
}
# Teardown
teardown() {
print_header "Tearing down: $PROJECT_NAME"
local result
result=$(api_call DELETE "/project/$PROJECT_NAME")
echo "$result" | jq '.'
echo ""
print_success "Project deleted. Gitea repo preserved."
}
case "$COMMAND" in
run)
run_flow
;;
status)
check_status
;;
diagnose)
diagnose
;;
teardown)
teardown
;;
*)
echo "Unknown command: $COMMAND"
echo "Valid commands: run, status, diagnose, teardown"
exit 1
;;
esac