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>
324 lines
9.7 KiB
Bash
Executable File
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\""
|