Skip to content

Commit b2effaa

Browse files
owineclaude
andcommitted
feat(deploy): add deployment script library foundation
Created library infrastructure for script extraction refactor: Added: - scripts/deployment/lib/ssh-helpers.sh: SSH retry and connection utilities - scripts/deployment/lib/common.sh: Logging, validation, and helper functions This is Phase 1 of refactoring the deploy workflow to extract large inline scripts (health check heredoc is 24,812 chars, exceeds 21,000 limit). Scripts will run on GitHub Actions runner and make SSH calls to remote server as needed. This foundation provides reusable utilities for all deployment scripts. Next phases: - Phase 2: Extract stack removal detection - Phase 3: Extract health check logic - Phase 4: Extract deployment orchestration - Phase 5: Extract rollback logic - Phase 6: Update workflow to use scripts Related issue: Expression length limit exceeded on line 1214 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 761015b commit b2effaa

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

scripts/deployment/lib/common.sh

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env bash
2+
# Common Utilities for Deployment Scripts
3+
# Provides logging, validation, and helper functions
4+
5+
set -euo pipefail
6+
7+
# Logging functions with colors
8+
log_info() {
9+
echo "ℹ️ $*"
10+
}
11+
12+
log_success() {
13+
echo "$*"
14+
}
15+
16+
log_error() {
17+
echo "$*" >&2
18+
}
19+
20+
log_warning() {
21+
echo "⚠️ $*" >&2
22+
}
23+
24+
# Set GitHub Actions output
25+
set_github_output() {
26+
local key=$1
27+
local value=$2
28+
29+
if [ -n "${GITHUB_OUTPUT:-}" ]; then
30+
echo "${key}=${value}" >> "$GITHUB_OUTPUT"
31+
fi
32+
}
33+
34+
# Validate stack names (alphanumeric, dash, underscore only)
35+
validate_stack_name() {
36+
local stack=$1
37+
38+
if [[ ! "$stack" =~ ^[a-zA-Z0-9_-]+$ ]]; then
39+
log_error "Invalid stack name: $stack (must be alphanumeric with dash/underscore)"
40+
return 1
41+
fi
42+
43+
return 0
44+
}
45+
46+
# Validate SHA format (40 hex characters)
47+
validate_sha() {
48+
local sha=$1
49+
50+
if [[ ! "$sha" =~ ^[a-fA-F0-9]{40}$ ]]; then
51+
log_error "Invalid SHA format: $sha (must be 40 hex characters)"
52+
return 1
53+
fi
54+
55+
return 0
56+
}
57+
58+
# Validate 1Password reference format
59+
validate_op_reference() {
60+
local ref=$1
61+
62+
if [[ ! "$ref" =~ ^op:// ]]; then
63+
log_error "Invalid 1Password reference: $ref (must start with op://)"
64+
return 1
65+
fi
66+
67+
return 0
68+
}
69+
70+
# Format list for output (space-separated to comma-separated)
71+
format_list() {
72+
echo "$1" | tr ' ' ',' | sed 's/^,//;s/,/, /g'
73+
}
74+
75+
# Check if variable is set and non-empty
76+
require_var() {
77+
local var_name=$1
78+
local var_value="${!var_name:-}"
79+
80+
if [ -z "$var_value" ]; then
81+
log_error "Required variable $var_name is not set"
82+
return 1
83+
fi
84+
85+
return 0
86+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/usr/bin/env bash
2+
# SSH Helper Functions for Deployment Scripts
3+
# Provides retry logic and SSH connection utilities
4+
5+
set -euo pipefail
6+
7+
# General retry function with exponential backoff
8+
retry() {
9+
local max_attempts=$1
10+
local delay=$2
11+
local command="${@:3}"
12+
local attempt=1
13+
14+
while [ $attempt -le $max_attempts ]; do
15+
echo "Attempt $attempt of $max_attempts: $command"
16+
if eval "$command"; then
17+
echo "✅ Command succeeded on attempt $attempt"
18+
return 0
19+
else
20+
echo "❌ Command failed on attempt $attempt"
21+
if [ $attempt -lt $max_attempts ]; then
22+
echo "⏳ Waiting ${delay}s before retry..."
23+
sleep $delay
24+
delay=$((delay * 2)) # Exponential backoff
25+
fi
26+
attempt=$((attempt + 1))
27+
fi
28+
done
29+
30+
echo "💥 Command failed after $max_attempts attempts"
31+
return 1
32+
}
33+
34+
# SSH retry function with specific error handling
35+
ssh_retry() {
36+
local max_attempts=$1
37+
local delay=$2
38+
local ssh_cmd="${@:3}"
39+
local attempt=1
40+
local last_exit_code=1
41+
42+
while [ $attempt -le $max_attempts ]; do
43+
echo "SSH Attempt $attempt of $max_attempts" >&2
44+
if eval "$ssh_cmd"; then
45+
echo "✅ SSH command succeeded on attempt $attempt" >&2
46+
return 0
47+
else
48+
last_exit_code=$?
49+
echo "❌ SSH command failed on attempt $attempt (exit code: $last_exit_code)" >&2
50+
51+
# Check for specific SSH errors
52+
case $last_exit_code in
53+
255) echo "SSH connection error - network/auth issue" >&2 ;;
54+
1) echo "General SSH error" >&2 ;;
55+
*) echo "Unknown error code: $last_exit_code" >&2 ;;
56+
esac
57+
58+
if [ $attempt -lt $max_attempts ]; then
59+
echo "⏳ Waiting ${delay}s before SSH retry..." >&2
60+
sleep $delay
61+
fi
62+
attempt=$((attempt + 1))
63+
fi
64+
done
65+
66+
echo "💥 SSH command failed after $max_attempts attempts (final exit code: $last_exit_code)" >&2
67+
return $last_exit_code
68+
}
69+
70+
# Simple SSH execution wrapper
71+
ssh_exec() {
72+
local ssh_user=$1
73+
local ssh_host=$2
74+
local command=$3
75+
76+
ssh -o "StrictHostKeyChecking no" "${ssh_user}@${ssh_host}" "$command"
77+
}

0 commit comments

Comments
 (0)