claude-configs/skills/deploy/deploy.sh
Cal Corum 8a1d15911f Initial commit: Claude Code configuration backup
Version control Claude Code configuration including:
- Global instructions (CLAUDE.md)
- User settings (settings.json)
- Custom agents (architect, designer, engineer, etc.)
- Custom skills (create-skill templates and workflows)

Excludes session data, secrets, cache, and temporary files per .gitignore.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 16:34:21 -06:00

324 lines
9.7 KiB
Bash
Executable File

#!/bin/bash
# deploy.sh - Deploy services to production
# Usage: deploy.sh <service> <bump-type> [--dry-run]
# service: md-discord | md-database | pd-discord | pd-database
# bump-type: major | minor | patch
# --dry-run: Show what would happen without making changes
set -e
# Color codes 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
# Detect SSH session and disable BuildKit to avoid credential helper GUI prompts
if [[ -n "$SSH_CLIENT" ]] || [[ -n "$SSH_TTY" ]] || [[ -n "$SSH_CONNECTION" ]]; then
export DOCKER_BUILDKIT=0
echo -e "${YELLOW}SSH session detected - BuildKit disabled to avoid credential prompts${NC}"
fi
# =============================================================================
# SERVICE CONFIGURATIONS
# =============================================================================
# Local source paths
declare -A SERVICE_PATHS=(
["md-discord"]="/mnt/NV2/Development/major-domo/discord-app-v2"
["md-database"]="/mnt/NV2/Development/major-domo/database"
["pd-discord"]="/mnt/NV2/Development/paper-dynasty/discord-app"
["pd-database"]="/mnt/NV2/Development/paper-dynasty/database"
)
# Docker Hub image names
declare -A DOCKER_IMAGES=(
["md-discord"]="manticorum67/major-domo-discordapp"
["md-database"]="manticorum67/major-domo-database"
["pd-discord"]="manticorum67/paper-dynasty-discordapp"
["pd-database"]="manticorum67/paper-dynasty-database"
)
# Production SSH hosts
declare -A PROD_HOSTS=(
["md-discord"]="akamai"
["md-database"]="akamai"
["pd-discord"]="sba-bots"
["pd-database"]="akamai"
)
# Production paths (on remote host)
declare -A PROD_PATHS=(
["md-discord"]="/root/container-data/major-domo"
["md-database"]="/root/container-data/sba-database"
["pd-discord"]="/home/cal/container-data/paper-dynasty"
["pd-database"]="/root/container-data/paper-dynasty"
)
# Docker Compose service names
declare -A COMPOSE_SERVICES=(
["md-discord"]="discord-app"
["md-database"]="api"
["pd-discord"]="discord-app"
["pd-database"]="api"
)
# Container names (for verification)
declare -A CONTAINER_NAMES=(
["md-discord"]="major-domo-discord-app-1"
["md-database"]="sba_db_api"
["pd-discord"]="paper-dynasty_discord-app_1"
["pd-database"]="pd_api"
)
# Friendly names for display
declare -A FRIENDLY_NAMES=(
["md-discord"]="Major Domo Discord Bot"
["md-database"]="Major Domo Database API"
["pd-discord"]="Paper Dynasty Discord Bot"
["pd-database"]="Paper Dynasty Database API"
)
# =============================================================================
# FUNCTIONS
# =============================================================================
# Parse version and increment
increment_version() {
local version=$1
local bump_type=$2
IFS='.' read -r major minor patch <<< "$version"
# Handle versions without patch (e.g., "1.5" -> "1.5.0")
patch=${patch:-0}
case $bump_type in
major)
echo "$((major + 1)).0.0"
;;
minor)
echo "$major.$((minor + 1)).0"
;;
patch)
echo "$major.$minor.$((patch + 1))"
;;
*)
echo "Invalid bump type: $bump_type" >&2
exit 1
;;
esac
}
# Display usage
usage() {
echo "Usage: $0 <service> <bump-type> [--dry-run]"
echo ""
echo "Services:"
echo " md-discord - Major Domo Discord Bot"
echo " md-database - Major Domo Database API"
echo " pd-discord - Paper Dynasty Discord Bot"
echo " pd-database - Paper Dynasty Database API"
echo ""
echo "Bump types:"
echo " major - Increment major version (x.0.0)"
echo " minor - Increment minor version (0.x.0)"
echo " patch - Increment patch version (0.0.x)"
echo ""
echo "Options:"
echo " --dry-run Show what would happen without making changes"
echo ""
echo "Examples:"
echo " $0 md-discord patch"
echo " $0 pd-database minor"
echo " $0 md-discord patch --dry-run"
exit 1
}
# =============================================================================
# ARGUMENT PARSING
# =============================================================================
DRY_RUN=false
SERVICE=""
BUMP_TYPE=""
for arg in "$@"; do
case $arg in
--dry-run)
DRY_RUN=true
;;
md-discord|md-database|pd-discord|pd-database)
SERVICE=$arg
;;
major|minor|patch)
BUMP_TYPE=$arg
;;
*)
echo -e "${RED}Unknown argument: $arg${NC}"
usage
;;
esac
done
# Validate required arguments
if [[ -z "$SERVICE" ]] || [[ -z "$BUMP_TYPE" ]]; then
usage
fi
# Validate service exists in config
if [[ ! ${SERVICE_PATHS[$SERVICE]+_} ]]; then
echo -e "${RED}Error: Invalid service '$SERVICE'${NC}"
usage
fi
# =============================================================================
# GET CONFIGURATION
# =============================================================================
LOCAL_PATH="${SERVICE_PATHS[$SERVICE]}"
DOCKER_IMAGE="${DOCKER_IMAGES[$SERVICE]}"
PROD_HOST="${PROD_HOSTS[$SERVICE]}"
PROD_PATH="${PROD_PATHS[$SERVICE]}"
COMPOSE_SERVICE="${COMPOSE_SERVICES[$SERVICE]}"
CONTAINER_NAME="${CONTAINER_NAMES[$SERVICE]}"
FRIENDLY_NAME="${FRIENDLY_NAMES[$SERVICE]}"
# =============================================================================
# DEPLOYMENT
# =============================================================================
echo -e "${BLUE}========================================${NC}"
if [[ "$DRY_RUN" == true ]]; then
echo -e "${CYAN} Deploy: $FRIENDLY_NAME (DRY RUN)${NC}"
else
echo -e "${BLUE} Deploy: $FRIENDLY_NAME${NC}"
fi
echo -e "${BLUE}========================================${NC}"
echo ""
# Change to service directory
cd "$LOCAL_PATH"
# Check git status
echo -e "${YELLOW}Checking git status...${NC}"
if [[ -n $(git status --porcelain) ]]; then
echo -e "${RED}Warning: Working directory has uncommitted changes${NC}"
git status --short
if [[ "$DRY_RUN" == true ]]; then
echo -e "${CYAN}(Dry run - would prompt for confirmation)${NC}"
else
read -p "Continue anyway? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
fi
fi
# Read current version
CURRENT_VERSION=$(cat VERSION | tr -d '\n')
echo -e "${GREEN}Current version: $CURRENT_VERSION${NC}"
# Calculate new version
NEW_VERSION=$(increment_version "$CURRENT_VERSION" "$BUMP_TYPE")
echo -e "${GREEN}New version: $NEW_VERSION${NC}"
echo ""
# Deployment Plan Summary
echo -e "${YELLOW}Deployment Plan:${NC}"
echo " Service: $FRIENDLY_NAME"
echo " Version: $CURRENT_VERSION -> $NEW_VERSION"
echo " Docker: $DOCKER_IMAGE:$NEW_VERSION"
echo " Host: $PROD_HOST"
echo " Path: $PROD_PATH"
echo ""
# DRY RUN: Just show what would happen
if [[ "$DRY_RUN" == true ]]; then
echo -e "${CYAN}=== DRY RUN - No changes will be made ===${NC}"
echo ""
echo -e "${CYAN}Step 1/6: Would update VERSION file${NC}"
echo " echo \"$NEW_VERSION\" > VERSION"
echo ""
echo -e "${CYAN}Step 2/6: Would build Docker image${NC}"
echo " docker build -t $DOCKER_IMAGE:$NEW_VERSION -t $DOCKER_IMAGE:latest ."
echo ""
echo -e "${CYAN}Step 3/6: Would push to Docker Hub${NC}"
echo " docker push $DOCKER_IMAGE:$NEW_VERSION"
echo " docker push $DOCKER_IMAGE:latest"
echo ""
echo -e "${CYAN}Step 4/6: Would deploy to production${NC}"
echo " ssh $PROD_HOST \"cd $PROD_PATH && docker compose pull $COMPOSE_SERVICE && docker compose up -d $COMPOSE_SERVICE\""
echo ""
echo -e "${CYAN}Step 5/6: Would commit version bump${NC}"
echo " git add VERSION"
echo " git commit -m \"Bump version to $NEW_VERSION\""
echo " git tag v$NEW_VERSION"
echo ""
echo -e "${CYAN}Step 6/6: Would push to git${NC}"
echo " git push"
echo " git push --tags"
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} DRY RUN Complete${NC}"
echo -e "${GREEN} Run without --dry-run to execute${NC}"
echo -e "${GREEN}========================================${NC}"
exit 0
fi
# REAL DEPLOYMENT: Confirm and execute
read -p "Proceed with deployment? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
echo ""
echo -e "${BLUE}Step 1/6: Updating VERSION file${NC}"
echo "$NEW_VERSION" > VERSION
echo -e "${GREEN}VERSION updated to $NEW_VERSION${NC}"
echo ""
echo -e "${BLUE}Step 2/6: Building Docker image${NC}"
docker build -t "$DOCKER_IMAGE:$NEW_VERSION" -t "$DOCKER_IMAGE:latest" .
echo ""
echo -e "${BLUE}Step 3/6: Pushing to Docker Hub${NC}"
docker push "$DOCKER_IMAGE:$NEW_VERSION"
docker push "$DOCKER_IMAGE:latest"
echo ""
echo -e "${BLUE}Step 4/6: Deploying to production ($PROD_HOST)${NC}"
ssh "$PROD_HOST" "cd $PROD_PATH && docker compose pull $COMPOSE_SERVICE && docker compose up -d $COMPOSE_SERVICE"
echo ""
echo -e "${BLUE}Step 5/6: Committing version bump${NC}"
git add VERSION
git commit -m "Bump version to $NEW_VERSION"
git tag "v$NEW_VERSION"
echo ""
echo -e "${BLUE}Step 6/6: Pushing to git${NC}"
git push
git push --tags
echo ""
echo -e "${BLUE}Verifying deployment...${NC}"
sleep 3
ssh "$PROD_HOST" "docker ps --filter name=$CONTAINER_NAME --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'"
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Deployment Complete!${NC}"
echo -e "${GREEN} $FRIENDLY_NAME v$NEW_VERSION is now live${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
echo "To view logs:"
echo " ssh $PROD_HOST \"docker logs $CONTAINER_NAME --tail 100 -f\""