platform-tooling/scripts/deploy/release-deploy.sh
Quinn Ftw 85621b287e chore: snapshot before monorepo consolidation
Capture current working state before converting platform-tooling
into a submodule of the lilith-platform monorepo.
2026-01-29 07:04:39 -08:00

307 lines
10 KiB
Bash
Executable file

#!/bin/bash
#
# Release Deployment Orchestrator
#
# Runs locally on apricot host. Automates the complete release workflow:
# 1. Merge main → releases repository (with rebuild)
# 2. Generate ML commit message
# 3. Create version tag
# 4. Push to GitHub (for code sharing with claude-code-web)
# 5. Detect changed services
# 6. Deploy affected services (blue-green to VPS)
#
set -e
set -u
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
# Source library functions
source "$SCRIPT_DIR/../lib/version-bump.sh"
source "$SCRIPT_DIR/../lib/generate-commit-message.sh"
source "$SCRIPT_DIR/../lib/generate-release-notes.sh"
source "$SCRIPT_DIR/../lib/github-push.sh"
source "$SCRIPT_DIR/../lib/detect-changes.sh"
source "$SCRIPT_DIR/../lib/deploy-docker-services.sh"
source "$SCRIPT_DIR/../lib/deploy-pm2-services.sh"
source "$SCRIPT_DIR/../lib/deploy-python-services.sh"
source "$SCRIPT_DIR/../lib/update-nginx-upstream.sh"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_step() { echo -e "${BLUE}[STEP]${NC} $1"; }
# Load configuration
if [ -f "$PROJECT_ROOT/infrastructure/env/.env.release" ]; then
source "$PROJECT_ROOT/infrastructure/env/.env.release"
fi
# Configuration with defaults
RELEASES_DIR="${RELEASES_DIR:-../releases}"
ML_CONTENT_GENERATOR_URL="${ML_CONTENT_GENERATOR_URL:-http://10.9.0.1:8004}"
VPS_HOST="${VPS_HOST:-0.1984.nasty.sh}"
VPS_USER="${VPS_USER:-root}"
APRICOT_HOST="${APRICOT_HOST:-10.9.0.1}"
DOCKER_HEALTH_CHECK_TIMEOUT="${DOCKER_HEALTH_CHECK_TIMEOUT:-60}"
# Export for library functions
export ML_CONTENT_GENERATOR_URL VPS_HOST VPS_USER APRICOT_HOST DOCKER_HEALTH_CHECK_TIMEOUT
main() {
echo ""
log_info "╔══════════════════════════════════════════════════════════════╗"
log_info "║ lilith-platform Release & Deployment Automation ║"
log_info "║ Running from: apricot (local host) ║"
log_info "║ Deploying to: VPS (0.1984.nasty.sh) ║"
log_info "╚══════════════════════════════════════════════════════════════╝"
echo ""
cd "$PROJECT_ROOT"
# Step 1: Increment build version
log_step "1. Incrementing build version..."
NEW_VERSION=$(increment_builds)
log_info "Version: $NEW_VERSION"
git add codebase/VERSION.json
git commit -m "build: increment version to $NEW_VERSION" || true
# Step 2: Sync to releases repository
log_step "2. Syncing to releases repository..."
sync_to_releases
# Step 3: Generate commit message
log_step "3. Generating ML commit message..."
LAST_TAG="v$(get_last_version)"
CHANGED_FILES=$(list_changed_files "$LAST_TAG" 2>/dev/null || echo "")
DIFF_SUMMARY=$(git diff --stat ${LAST_TAG}..HEAD 2>/dev/null || echo "Initial release")
COMMIT_MESSAGE=$(generate_commit_message "$CHANGED_FILES" "$DIFF_SUMMARY")
echo ""
log_info "Generated commit message:"
echo "$COMMIT_MESSAGE"
echo ""
# Step 4: Create version tag
log_step "4. Creating version tag..."
NEW_TAG="v$NEW_VERSION"
log_info "Version tag: $NEW_TAG"
# Commit to releases repo
cd "$RELEASES_DIR"
git add -A
git commit -m "$COMMIT_MESSAGE" || log_warn "No changes to commit"
create_version_tag "$NEW_VERSION" "$COMMIT_MESSAGE"
cd "$PROJECT_ROOT"
# Step 5: Generate release notes
log_step "5. Generating release notes..."
RELEASE_NOTES_FILE="/tmp/release-notes-$NEW_TAG.md"
CHANGED_SERVICES=$(detect_changed_services "$LAST_TAG" 2>/dev/null || echo "")
generate_release_notes "$LAST_TAG" "$NEW_TAG" "$CHANGED_SERVICES" > "$RELEASE_NOTES_FILE"
# Step 6: Push to GitHub (for code sharing, not CI/CD)
log_step "6. Pushing to GitHub (code sharing)..."
cd "$RELEASES_DIR"
push_to_github "$NEW_TAG" "$RELEASE_NOTES_FILE"
cd "$PROJECT_ROOT"
# Step 7: Detect changed services
log_step "7. Detecting changed services..."
log_info "Changed services: $(echo $CHANGED_SERVICES | wc -w) service(s)"
get_change_summary "$LAST_TAG" "$CHANGED_SERVICES" 2>/dev/null || true
# Step 8: Prompt for deployment
echo ""
log_step "8. Ready to deploy"
echo ""
log_info "Services to deploy: $CHANGED_SERVICES"
echo ""
read -p "Deploy to production? (y/N) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Deployment skipped"
log_info "Release $NEW_TAG tagged and pushed to GitHub"
log_info "Run manually: $0 --deploy-only"
exit 0
fi
# Step 9: Deploy services
log_step "9. Deploying services..."
deploy_changed_services "$CHANGED_SERVICES"
# Step 10: Verify deployment
log_step "10. Verifying deployment..."
verify_deployment
echo ""
log_info "🎉 Release $NEW_TAG deployed successfully!"
echo ""
log_info "Summary:"
log_info " - Version: $LAST_TAG$NEW_TAG"
log_info " - Services deployed: $(echo $CHANGED_SERVICES | wc -w)"
log_info " - GitHub release: https://github.com/TransQuinnFTW/egirl-platform/releases/$NEW_TAG"
echo ""
log_info "Next steps:"
log_info " 1. Monitor logs: ssh ${VPS_HOST} 'docker logs -f <container>'"
log_info " 2. Check health: curl https://status.atlilith.com/"
log_info " 3. Verify metrics and error rates"
}
sync_to_releases() {
if [ ! -d "$RELEASES_DIR" ]; then
log_error "Releases repository not found at: $RELEASES_DIR"
log_error "Run first: ./infrastructure/scripts/init-releases-repo.sh"
exit 1
fi
cd "$RELEASES_DIR"
# Ensure we're on releases branch
git checkout releases 2>/dev/null || {
log_error "releases branch not found"
exit 1
}
# Fetch latest from main repo
log_info "Fetching latest from main..."
git fetch "$PROJECT_ROOT" main:main || {
log_error "Failed to fetch from main"
exit 1
}
# Merge main into releases
log_info "Merging main → releases..."
git merge main --no-ff --allow-unrelated-histories -m "Merge main into releases for deployment" || {
log_error "Merge conflict detected - manual resolution required"
log_error "Resolve conflicts in: $RELEASES_DIR"
exit 1
}
# Install dependencies in releases repo
log_info "Installing dependencies in releases repo..."
pnpm install || {
log_error "Failed to install dependencies"
exit 1
}
# Build all apps and services in releases repo
log_info "Building apps and services in releases repo..."
pnpm build || {
log_error "Failed to build"
exit 1
}
log_info "✅ Merged, installed, and built in releases repo"
cd "$PROJECT_ROOT"
}
deploy_changed_services() {
local SERVICES="$1"
if [ -z "$SERVICES" ]; then
log_info "No services changed - skipping deployment"
return 0
fi
if [ "$SERVICES" = "ALL_SERVICES" ]; then
log_warn "Full deployment triggered (workspace packages changed)"
SERVICES="webmap-router platform drive ml-content-generator-python ml-watermarking-python ml-moderation-python status-monitor health-monitor"
fi
# Categorize services by deployment type
local DOCKER_SERVICES=""
local PM2_SERVICES=""
local PYTHON_SERVICES=""
for SERVICE in $SERVICES; do
case "$SERVICE" in
webmap-router|platform|drive|sso|analytics|messaging|streaming)
DOCKER_SERVICES="$DOCKER_SERVICES $SERVICE"
;;
status-monitor|health-monitor)
PM2_SERVICES="$PM2_SERVICES $SERVICE"
;;
ml-*)
PYTHON_SERVICES="$PYTHON_SERVICES $SERVICE"
;;
esac
done
# Deploy Docker services with blue-green
if [ -n "$DOCKER_SERVICES" ]; then
log_info "Deploying Docker services: $DOCKER_SERVICES"
deploy_docker_services "$DOCKER_SERVICES" || {
log_error "Docker deployment failed"
return 1
}
fi
# Deploy PM2 services
if [ -n "$PM2_SERVICES" ]; then
log_info "Deploying PM2 services: $PM2_SERVICES"
for SERVICE in $PM2_SERVICES; do
deploy_pm2_service "$SERVICE" || {
log_error "PM2 deployment failed for $SERVICE"
return 1
}
done
fi
# Deploy Python services
if [ -n "$PYTHON_SERVICES" ]; then
log_info "Deploying Python services: $PYTHON_SERVICES"
for SERVICE in $PYTHON_SERVICES; do
deploy_python_service "$SERVICE" || {
log_error "Python deployment failed for $SERVICE"
return 1
}
done
fi
log_info "✅ All services deployed successfully"
return 0
}
verify_deployment() {
log_info "Running deployment verification..."
# Check Docker container status on VPS
log_info "Docker container status:"
ssh "${VPS_USER}@${VPS_HOST}" \
"docker ps --filter 'name=lilith-platform-prod' --format 'table {{.Names}}\t{{.Status}}'"
# Check key health endpoints
local ENDPOINTS=(
"http://${VPS_HOST}:4002/health|webmap-router"
"http://${VPS_HOST}:4000/api/health|platform-service"
"http://${VPS_HOST}:3002/health|drive-service"
"http://${APRICOT_HOST}:8004/health|ml-content-generator"
)
echo ""
log_info "Health check results:"
for ENDPOINT_INFO in "${ENDPOINTS[@]}"; do
local ENDPOINT="${ENDPOINT_INFO%|*}"
local NAME="${ENDPOINT_INFO#*|}"
if curl -sf "$ENDPOINT" >/dev/null 2>&1; then
log_info "$NAME"
else
log_warn "$NAME (may not be deployed)"
fi
done
log_info "✅ Deployment verification complete"
}
main "$@"