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>
214 lines
6.2 KiB
Bash
Executable File
214 lines
6.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Common utilities for rdev cookbook scripts
|
|
#
|
|
# Usage:
|
|
# source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
|
|
#
|
|
# Provides:
|
|
# - api_call() - Make authenticated API calls
|
|
# - wait_for_build() - Poll for build completion
|
|
# - wait_for_pipeline() - Poll for CI pipeline completion
|
|
# - wait_for_site() - Wait for site to respond
|
|
# - Colors for output
|
|
|
|
set -euo pipefail
|
|
|
|
# Require environment variables
|
|
: "${RDEV_API_URL:?RDEV_API_URL must be set}"
|
|
: "${RDEV_API_KEY:?RDEV_API_KEY must be set}"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Make an authenticated API call
|
|
# Arguments: method endpoint [data]
|
|
# Example: api_call GET "/projects"
|
|
# Example: api_call POST "/projects" '{"name": "test"}'
|
|
api_call() {
|
|
local method="$1"
|
|
local endpoint="$2"
|
|
local data="${3:-}"
|
|
|
|
if [[ -n "$data" ]]; then
|
|
curl -s -X "$method" "$RDEV_API_URL$endpoint" \
|
|
-H "X-API-Key: $RDEV_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$data"
|
|
else
|
|
curl -s -X "$method" "$RDEV_API_URL$endpoint" \
|
|
-H "X-API-Key: $RDEV_API_KEY"
|
|
fi
|
|
}
|
|
|
|
# Wait for a build to complete
|
|
# Arguments: task_id [max_attempts] [poll_interval]
|
|
# Returns: 0 on success, 1 on failure, 2 on timeout
|
|
wait_for_build() {
|
|
local task_id="$1"
|
|
local max_attempts="${2:-60}" # 5 minutes default (5s * 60)
|
|
local poll_interval="${3:-5}"
|
|
local attempt=0
|
|
|
|
echo -e "${CYAN}Waiting for build to complete (task: $task_id)...${NC}"
|
|
|
|
while [[ $attempt -lt $max_attempts ]]; do
|
|
local result
|
|
result=$(api_call GET "/builds/$task_id")
|
|
local status
|
|
status=$(echo "$result" | jq -r '.status // .data.status // "unknown"')
|
|
|
|
case "$status" in
|
|
completed)
|
|
local success
|
|
success=$(echo "$result" | jq -r '.result.success // .data.result.success // false')
|
|
if [[ "$success" == "true" ]]; then
|
|
echo -e "${GREEN}Build completed successfully!${NC}"
|
|
echo "$result" | jq '.result // .data.result'
|
|
return 0
|
|
else
|
|
echo -e "${RED}Build completed but failed:${NC}"
|
|
echo "$result" | jq '.result // .data.result'
|
|
return 1
|
|
fi
|
|
;;
|
|
failed)
|
|
echo -e "${RED}Build failed:${NC}"
|
|
echo "$result" | jq '.'
|
|
return 1
|
|
;;
|
|
running)
|
|
echo " Build running... (attempt $((attempt + 1))/$max_attempts)"
|
|
;;
|
|
pending)
|
|
echo " Build pending... (attempt $((attempt + 1))/$max_attempts)"
|
|
;;
|
|
*)
|
|
echo " Unknown status: $status (attempt $((attempt + 1))/$max_attempts)"
|
|
;;
|
|
esac
|
|
|
|
sleep "$poll_interval"
|
|
((attempt++))
|
|
done
|
|
|
|
echo -e "${YELLOW}Timeout waiting for build to complete${NC}"
|
|
return 2
|
|
}
|
|
|
|
# Wait for CI pipeline to complete
|
|
# Arguments: project_id [max_attempts] [poll_interval]
|
|
# Returns: 0 on success, 1 on failure, 2 on timeout
|
|
wait_for_pipeline() {
|
|
local project_id="$1"
|
|
local max_attempts="${2:-60}" # 5 minutes default
|
|
local poll_interval="${3:-5}"
|
|
local attempt=0
|
|
|
|
echo -e "${CYAN}Waiting for CI pipeline...${NC}"
|
|
|
|
# Wait a bit for pipeline to be created
|
|
sleep 5
|
|
|
|
while [[ $attempt -lt $max_attempts ]]; do
|
|
local result
|
|
result=$(api_call GET "/projects/$project_id/pipelines")
|
|
|
|
# Check if we have any pipelines
|
|
local pipeline_count
|
|
pipeline_count=$(echo "$result" | jq '.data | length // 0')
|
|
|
|
if [[ "$pipeline_count" -eq 0 ]]; then
|
|
echo " No pipelines yet... (attempt $((attempt + 1))/$max_attempts)"
|
|
sleep "$poll_interval"
|
|
((attempt++))
|
|
continue
|
|
fi
|
|
|
|
# Get latest pipeline status
|
|
local status
|
|
status=$(echo "$result" | jq -r '.data[0].status // "unknown"')
|
|
local pipeline_number
|
|
pipeline_number=$(echo "$result" | jq -r '.data[0].number // "?"')
|
|
|
|
case "$status" in
|
|
success)
|
|
echo -e "${GREEN}Pipeline #$pipeline_number completed successfully!${NC}"
|
|
return 0
|
|
;;
|
|
failure|error|killed)
|
|
echo -e "${RED}Pipeline #$pipeline_number failed with status: $status${NC}"
|
|
return 1
|
|
;;
|
|
running|pending)
|
|
echo " Pipeline #$pipeline_number $status... (attempt $((attempt + 1))/$max_attempts)"
|
|
;;
|
|
*)
|
|
echo " Pipeline #$pipeline_number status: $status (attempt $((attempt + 1))/$max_attempts)"
|
|
;;
|
|
esac
|
|
|
|
sleep "$poll_interval"
|
|
((attempt++))
|
|
done
|
|
|
|
echo -e "${YELLOW}Timeout waiting for pipeline to complete${NC}"
|
|
return 2
|
|
}
|
|
|
|
# Wait for site to be accessible
|
|
# Arguments: domain [max_attempts] [poll_interval]
|
|
# Returns: 0 on success, 1 on timeout
|
|
wait_for_site() {
|
|
local domain="$1"
|
|
local max_attempts="${2:-30}"
|
|
local poll_interval="${3:-5}"
|
|
local attempt=0
|
|
|
|
echo -e "${CYAN}Waiting for site to be accessible at https://$domain...${NC}"
|
|
|
|
while [[ $attempt -lt $max_attempts ]]; do
|
|
local http_code
|
|
http_code=$(curl -s -o /dev/null -w "%{http_code}" "https://$domain" 2>/dev/null || echo "000")
|
|
|
|
if [[ "$http_code" == "200" ]]; then
|
|
echo -e "${GREEN}Site is live! (HTTP $http_code)${NC}"
|
|
return 0
|
|
fi
|
|
|
|
echo " HTTP $http_code... (attempt $((attempt + 1))/$max_attempts)"
|
|
sleep "$poll_interval"
|
|
((attempt++))
|
|
done
|
|
|
|
echo -e "${YELLOW}Timeout waiting for site to respond${NC}"
|
|
return 1
|
|
}
|
|
|
|
# Print a section header
|
|
print_header() {
|
|
local title="$1"
|
|
echo ""
|
|
echo -e "${BLUE}=== $title ===${NC}"
|
|
echo ""
|
|
}
|
|
|
|
# Print success message
|
|
print_success() {
|
|
echo -e "${GREEN}✓ $1${NC}"
|
|
}
|
|
|
|
# Print error message
|
|
print_error() {
|
|
echo -e "${RED}✗ $1${NC}"
|
|
}
|
|
|
|
# Print warning message
|
|
print_warning() {
|
|
echo -e "${YELLOW}⚠ $1${NC}"
|
|
}
|