From 0f61684397fe1476d8e89db538c8234461b04bac Mon Sep 17 00:00:00 2001 From: root Date: Sat, 9 May 2026 22:16:41 +0000 Subject: [PATCH] feat(deploy): add deployment scripts for clock and notes repos - Add deploy-clock.sh for ChronoMind deployment (backend:4011, web:3030) - Add deploy-notes.sh for NoteLett deployment (backend:4016, web:3000) - Both scripts follow same pattern as deploy-invttrdg.sh - Include dirty checks, pull/rebase, smoke tests, Docker deployment, health checks Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- deploy-clock.sh | 223 ++++++++++++++++++++++++++++++++++++++++++++++++ deploy-notes.sh | 223 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 446 insertions(+) create mode 100755 deploy-clock.sh create mode 100755 deploy-notes.sh diff --git a/deploy-clock.sh b/deploy-clock.sh new file mode 100755 index 0000000..1cfb595 --- /dev/null +++ b/deploy-clock.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ═══════════════════════════════════════════════════════════════════════ +# ByteLyst ChronoMind - Production Deployment Script +# ═══════════════════════════════════════════════════════════════════════ +# Usage: ./deploy-clock.sh [--force] [--skip-health-check] +# +# What it does: +# 1. Dirty check: uncommitted changes, unpushed commits +# 2. Pull and rebase origin/main +# 3. Build and deploy Docker containers +# 4. Verify endpoints: https://api.bytelyst.com/chronomind, http://localhost:3030 +# +# Options: +# --force Skip dirty checks and force deployment +# --skip-health-check Skip endpoint health verification +# ═══════════════════════════════════════════════════════════════════════ + +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' + +log() { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $*"; } +ok() { echo -e "${GREEN}[$(date +%H:%M:%S)] ✓${NC} $*"; } +warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] ⚠${NC} $*"; } +fail() { echo -e "${RED}[$(date +%H:%M:%S)] ✗${NC} $*"; exit 1; } + +# ── Configuration ──────────────────────────────────────────────────── +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_DIR="${SCRIPT_DIR}/../learning_ai_clock" +cd "$SCRIPT_DIR" + +FORCE=false +SKIP_HEALTH_CHECK=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --force) FORCE=true; shift ;; + --skip-health-check) SKIP_HEALTH_CHECK=true; shift ;; + *) fail "Unknown option: $1" ;; + esac +done + +# ── Prerequisites ──────────────────────────────────────────────────── +if [ ! -d "$REPO_DIR" ]; then + fail "Repo directory not found: $REPO_DIR" +fi + +cd "$REPO_DIR" + +# ── Dirty Check ─────────────────────────────────────────────────────── +if [ "$FORCE" = false ]; then + log "Running dirty checks..." + + # Check for uncommitted changes + if ! git diff-index --quiet HEAD --; then + fail "Uncommitted changes detected. Commit or stash first, or use --force" + fi + + # Check for untracked files + if [ -n "$(git ls-files --others --exclude-standard)" ]; then + fail "Untracked files detected. Commit or remove them, or use --force" + fi + + # Check for unpushed commits + LOCAL_COMMIT=$(git rev-parse @) + REMOTE_COMMIT=$(git rev-parse '@{u}' 2>/dev/null || echo "") + + if [ -n "$REMOTE_COMMIT" ] && [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then + fail "Unpushed commits detected. Push first or use --force" + fi + + ok "Dirty checks passed" +else + warn "Skipping dirty checks (--force enabled)" +fi + +# ── Pull and Rebase ─────────────────────────────────────────────────── +log "Pulling latest changes from origin/main..." +git fetch origin + +LOCAL_MAIN=$(git rev-parse main) +REMOTE_MAIN=$(git rev-parse origin/main) + +if [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then + log "Local main is behind origin/main, rebasing..." + git rebase origin/main || { + fail "Rebase failed. Resolve conflicts and run: git rebase --continue" + } + ok "Rebase completed successfully" +else + ok "Already up to date with origin/main" +fi + +# ── Run Smoke Tests ───────────────────────────────────────────────────── +if [ "$SKIP_HEALTH_CHECK" = false ]; then + log "Running smoke tests before deployment..." + if [ -f "scripts/smoke-release.sh" ]; then + chmod +x scripts/smoke-release.sh + ./scripts/smoke-release.sh || { + fail "Smoke tests failed. Fix issues before deploying or use --skip-health-check" + } + ok "Smoke tests passed" + else + warn "Smoke test script not found, skipping pre-deployment tests" + fi +fi + +# ── Build and Deploy ────────────────────────────────────────────────── +log "Building and deploying Docker containers..." + +# Check if docker-compose files exist +if [ ! -f "docker-compose.yml" ]; then + fail "docker-compose.yml not found in $REPO_DIR" +fi + +# Build and start services +log "Building Docker images..." +docker compose build || fail "Docker build failed" + +log "Starting services..." +docker compose up -d || fail "Docker compose up failed" + +ok "Deployment completed" + +# ── Health Check ────────────────────────────────────────────────────── +if [ "$SKIP_HEALTH_CHECK" = true ]; then + warn "Skipping health checks (--skip-health-check enabled)" + exit 0 +fi + +log "Waiting for services to be healthy..." +sleep 10 + +# Check backend health +BACKEND_HEALTH=false +for _ in {1..30}; do + if curl -sf http://localhost:4011/health > /dev/null 2>&1; then + BACKEND_HEALTH=true + break + fi + echo -n "." + sleep 2 +done +echo "" + +if [ "$BACKEND_HEALTH" = true ]; then + ok "Backend health check passed (http://localhost:4011)" +else + fail "Backend health check failed" +fi + +# Check web health +WEB_HEALTH=false +for _ in {1..30}; do + if curl -sf http://localhost:3030 > /dev/null 2>&1; then + WEB_HEALTH=true + break + fi + echo -n "." + sleep 2 +done +echo "" + +if [ "$WEB_HEALTH" = true ]; then + ok "Web health check passed (http://localhost:3030)" +else + warn "Web health check failed (may be starting up)" +fi + +# ── Endpoint Verification ───────────────────────────────────────────── +log "Verifying production endpoints..." + +API_ENDPOINT="https://api.bytelyst.com/chronomind" +WEB_ENDPOINT="http://localhost:3030" + +# Check API endpoint +if curl -sf "$API_ENDPOINT/health" > /dev/null 2>&1; then + ok "API endpoint accessible: $API_ENDPOINT" +else + warn "API endpoint not accessible: $API_ENDPOINT (may need DNS propagation or routing)" +fi + +# Check web endpoint +if curl -sf "$WEB_ENDPOINT" > /dev/null 2>&1; then + ok "Web endpoint accessible: $WEB_ENDPOINT" +else + warn "Web endpoint not accessible: $WEB_ENDPOINT (may be starting up)" +fi + +# ── API Smoke Tests (Post-Deployment) ─────────────────────────────────── +log "Running post-deployment API smoke tests..." + +# Test backend health endpoint +BACKEND_URL="http://localhost:4011" +if curl -sf "$BACKEND_URL/health" > /dev/null 2>&1; then + ok "Backend health endpoint responding" + # Try to get health details + HEALTH_RESPONSE=$(curl -s "$BACKEND_URL/health" 2>/dev/null || echo "{}") + log "Health response: $HEALTH_RESPONSE" +else + fail "Backend health endpoint not responding" +fi + +# Test web is serving content +WEB_URL="http://localhost:3030" +if curl -sf "$WEB_URL" > /dev/null 2>&1; then + ok "Web frontend is serving content" + # Check if it's actually HTML + CONTENT_TYPE=$(curl -sI "$WEB_URL" | grep -i content-type || echo "") + if echo "$CONTENT_TYPE" | grep -qi "text/html"; then + ok "Web frontend is serving HTML content" + else + warn "Web frontend content type unexpected: $CONTENT_TYPE" + fi +else + fail "Web frontend not responding" +fi + +log "══════════════════════════════════════════════════════════════════════" +ok "Deployment completed successfully!" +log "Backend: http://localhost:4011 → $API_ENDPOINT" +log "Web: http://localhost:3030" +log "══════════════════════════════════════════════════════════════════════" diff --git a/deploy-notes.sh b/deploy-notes.sh new file mode 100755 index 0000000..a50032a --- /dev/null +++ b/deploy-notes.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ═══════════════════════════════════════════════════════════════════════ +# ByteLyst NoteLett - Production Deployment Script +# ═══════════════════════════════════════════════════════════════════════ +# Usage: ./deploy-notes.sh [--force] [--skip-health-check] +# +# What it does: +# 1. Dirty check: uncommitted changes, unpushed commits +# 2. Pull and rebase origin/main +# 3. Build and deploy Docker containers +# 4. Verify endpoints: https://api.bytelyst.com/notelett, http://localhost:3000 +# +# Options: +# --force Skip dirty checks and force deployment +# --skip-health-check Skip endpoint health verification +# ═══════════════════════════════════════════════════════════════════════ + +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' + +log() { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $*"; } +ok() { echo -e "${GREEN}[$(date +%H:%M:%S)] ✓${NC} $*"; } +warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] ⚠${NC} $*"; } +fail() { echo -e "${RED}[$(date +%H:%M:%S)] ✗${NC} $*"; exit 1; } + +# ── Configuration ──────────────────────────────────────────────────── +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_DIR="${SCRIPT_DIR}/../learning_ai_notes" +cd "$SCRIPT_DIR" + +FORCE=false +SKIP_HEALTH_CHECK=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --force) FORCE=true; shift ;; + --skip-health-check) SKIP_HEALTH_CHECK=true; shift ;; + *) fail "Unknown option: $1" ;; + esac +done + +# ── Prerequisites ──────────────────────────────────────────────────── +if [ ! -d "$REPO_DIR" ]; then + fail "Repo directory not found: $REPO_DIR" +fi + +cd "$REPO_DIR" + +# ── Dirty Check ─────────────────────────────────────────────────────── +if [ "$FORCE" = false ]; then + log "Running dirty checks..." + + # Check for uncommitted changes + if ! git diff-index --quiet HEAD --; then + fail "Uncommitted changes detected. Commit or stash first, or use --force" + fi + + # Check for untracked files + if [ -n "$(git ls-files --others --exclude-standard)" ]; then + fail "Untracked files detected. Commit or remove them, or use --force" + fi + + # Check for unpushed commits + LOCAL_COMMIT=$(git rev-parse @) + REMOTE_COMMIT=$(git rev-parse '@{u}' 2>/dev/null || echo "") + + if [ -n "$REMOTE_COMMIT" ] && [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then + fail "Unpushed commits detected. Push first or use --force" + fi + + ok "Dirty checks passed" +else + warn "Skipping dirty checks (--force enabled)" +fi + +# ── Pull and Rebase ─────────────────────────────────────────────────── +log "Pulling latest changes from origin/main..." +git fetch origin + +LOCAL_MAIN=$(git rev-parse main) +REMOTE_MAIN=$(git rev-parse origin/main) + +if [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then + log "Local main is behind origin/main, rebasing..." + git rebase origin/main || { + fail "Rebase failed. Resolve conflicts and run: git rebase --continue" + } + ok "Rebase completed successfully" +else + ok "Already up to date with origin/main" +fi + +# ── Run Smoke Tests ───────────────────────────────────────────────────── +if [ "$SKIP_HEALTH_CHECK" = false ]; then + log "Running smoke tests before deployment..." + if [ -f "scripts/smoke-release.sh" ]; then + chmod +x scripts/smoke-release.sh + ./scripts/smoke-release.sh || { + fail "Smoke tests failed. Fix issues before deploying or use --skip-health-check" + } + ok "Smoke tests passed" + else + warn "Smoke test script not found, skipping pre-deployment tests" + fi +fi + +# ── Build and Deploy ────────────────────────────────────────────────── +log "Building and deploying Docker containers..." + +# Check if docker-compose files exist +if [ ! -f "docker-compose.yml" ]; then + fail "docker-compose.yml not found in $REPO_DIR" +fi + +# Build and start services +log "Building Docker images..." +docker compose build || fail "Docker build failed" + +log "Starting services..." +docker compose up -d || fail "Docker compose up failed" + +ok "Deployment completed" + +# ── Health Check ────────────────────────────────────────────────────── +if [ "$SKIP_HEALTH_CHECK" = true ]; then + warn "Skipping health checks (--skip-health-check enabled)" + exit 0 +fi + +log "Waiting for services to be healthy..." +sleep 10 + +# Check backend health +BACKEND_HEALTH=false +for _ in {1..30}; do + if curl -sf http://localhost:4016/health > /dev/null 2>&1; then + BACKEND_HEALTH=true + break + fi + echo -n "." + sleep 2 +done +echo "" + +if [ "$BACKEND_HEALTH" = true ]; then + ok "Backend health check passed (http://localhost:4016)" +else + fail "Backend health check failed" +fi + +# Check web health +WEB_HEALTH=false +for _ in {1..30}; do + if curl -sf http://localhost:3000 > /dev/null 2>&1; then + WEB_HEALTH=true + break + fi + echo -n "." + sleep 2 +done +echo "" + +if [ "$WEB_HEALTH" = true ]; then + ok "Web health check passed (http://localhost:3000)" +else + warn "Web health check failed (may be starting up)" +fi + +# ── Endpoint Verification ───────────────────────────────────────────── +log "Verifying production endpoints..." + +API_ENDPOINT="https://api.bytelyst.com/notelett" +WEB_ENDPOINT="http://localhost:3000" + +# Check API endpoint +if curl -sf "$API_ENDPOINT/health" > /dev/null 2>&1; then + ok "API endpoint accessible: $API_ENDPOINT" +else + warn "API endpoint not accessible: $API_ENDPOINT (may need DNS propagation or routing)" +fi + +# Check web endpoint +if curl -sf "$WEB_ENDPOINT" > /dev/null 2>&1; then + ok "Web endpoint accessible: $WEB_ENDPOINT" +else + warn "Web endpoint not accessible: $WEB_ENDPOINT (may be starting up)" +fi + +# ── API Smoke Tests (Post-Deployment) ─────────────────────────────────── +log "Running post-deployment API smoke tests..." + +# Test backend health endpoint +BACKEND_URL="http://localhost:4016" +if curl -sf "$BACKEND_URL/health" > /dev/null 2>&1; then + ok "Backend health endpoint responding" + # Try to get health details + HEALTH_RESPONSE=$(curl -s "$BACKEND_URL/health" 2>/dev/null || echo "{}") + log "Health response: $HEALTH_RESPONSE" +else + fail "Backend health endpoint not responding" +fi + +# Test web is serving content +WEB_URL="http://localhost:3000" +if curl -sf "$WEB_URL" > /dev/null 2>&1; then + ok "Web frontend is serving content" + # Check if it's actually HTML + CONTENT_TYPE=$(curl -sI "$WEB_URL" | grep -i content-type || echo "") + if echo "$CONTENT_TYPE" | grep -qi "text/html"; then + ok "Web frontend is serving HTML content" + else + warn "Web frontend content type unexpected: $CONTENT_TYPE" + fi +else + fail "Web frontend not responding" +fi + +log "══════════════════════════════════════════════════════════════════════" +ok "Deployment completed successfully!" +log "Backend: http://localhost:4016 → $API_ENDPOINT" +log "Web: http://localhost:3000" +log "══════════════════════════════════════════════════════════════════════"