Skip to content

Commit a6a0be6

Browse files
authored
Merge pull request #18 from mojwang/fix/ci-bash-version-check
fix: allow bash 3.2 in CI environments
2 parents 0163d7b + d6b9811 commit a6a0be6

2 files changed

Lines changed: 291 additions & 5 deletions

File tree

lib/common.sh

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,74 @@
77
# Note: Strict mode is not set here to allow sourcing from various scripts
88
# Individual scripts should set their own error handling as needed
99

10-
# Check bash version requirement (bash 4+ required for associative arrays)
10+
# =============================================================================
11+
# Bash Version Compatibility Check
12+
# =============================================================================
13+
# This library requires bash 4+ for full functionality due to:
14+
# - Associative arrays (declare -A) for MCP server configurations
15+
# - Indirect variable expansion (${!var}) for dynamic references
16+
# - Advanced string manipulation features
17+
#
18+
# CI Fallback Mode:
19+
# GitHub Actions and other CI environments typically only have bash 3.2.
20+
# When detected, we provide minimal functions to allow basic operations
21+
# while skipping advanced features. This enables CI/CD pipelines to run
22+
# preview/test commands without full functionality.
23+
# =============================================================================
24+
1125
if [[ "${BASH_VERSION%%.*}" -lt 4 ]]; then
12-
echo "Error: This script requires bash 4.0 or higher (found $BASH_VERSION)" >&2
13-
echo "Please run with Homebrew bash: brew install bash" >&2
14-
echo "Ensure /opt/homebrew/bin is in your PATH" >&2
15-
exit 1
26+
if [[ "${CI:-false}" == "true" ]] || [[ "${GITHUB_ACTIONS:-false}" == "true" ]]; then
27+
# CI Fallback Mode - provide minimal functionality for bash 3.2
28+
echo "Warning: Running with bash $BASH_VERSION in CI environment" >&2
29+
echo "Disabled features: MCP server management, associative arrays, indirect expansion" >&2
30+
echo "Available features: Basic setup preview, simple commands, file operations" >&2
31+
32+
# Mark library as loaded to prevent duplicate sourcing
33+
COMMON_LIB_LOADED=true
34+
35+
# Define minimal print functions with optional logging support
36+
# These use 'ci_' prefix to avoid confusion with full implementations
37+
ci_print_info() {
38+
echo "$*"
39+
[[ -n "${LOG_FILE:-}" ]] && echo "$(date '+%Y-%m-%d %H:%M:%S') [${SCRIPT_NAME:-common}] INFO: $*" >> "$LOG_FILE" 2>/dev/null || true
40+
}
41+
ci_print_success() {
42+
echo "$*"
43+
[[ -n "${LOG_FILE:-}" ]] && echo "$(date '+%Y-%m-%d %H:%M:%S') [${SCRIPT_NAME:-common}] SUCCESS: $*" >> "$LOG_FILE" 2>/dev/null || true
44+
}
45+
ci_print_error() {
46+
echo "$*" >&2
47+
[[ -n "${LOG_FILE:-}" ]] && echo "$(date '+%Y-%m-%d %H:%M:%S') [${SCRIPT_NAME:-common}] ERROR: $*" >> "$LOG_FILE" 2>/dev/null || true
48+
}
49+
ci_print_warning() {
50+
echo "$*"
51+
[[ -n "${LOG_FILE:-}" ]] && echo "$(date '+%Y-%m-%d %H:%M:%S') [${SCRIPT_NAME:-common}] WARNING: $*" >> "$LOG_FILE" 2>/dev/null || true
52+
}
53+
ci_print_step() {
54+
echo "$*"
55+
[[ -n "${LOG_FILE:-}" ]] && echo "$(date '+%Y-%m-%d %H:%M:%S') [${SCRIPT_NAME:-common}] STEP: $*" >> "$LOG_FILE" 2>/dev/null || true
56+
}
57+
58+
# Alias the CI functions to standard names for compatibility
59+
alias print_info='ci_print_info'
60+
alias print_success='ci_print_success'
61+
alias print_error='ci_print_error'
62+
alias print_warning='ci_print_warning'
63+
alias print_step='ci_print_step'
64+
65+
# Export the CI functions
66+
export -f ci_print_info ci_print_success ci_print_error ci_print_warning ci_print_step
67+
68+
# Log the bash version for debugging
69+
[[ -n "${LOG_FILE:-}" ]] && echo "$(date '+%Y-%m-%d %H:%M:%S') [${SCRIPT_NAME:-common}] CI Mode: bash $BASH_VERSION detected" >> "$LOG_FILE" 2>/dev/null || true
70+
71+
return 0
72+
else
73+
echo "Error: This script requires bash 4.0 or higher (found $BASH_VERSION)" >&2
74+
echo "Please run with Homebrew bash: brew install bash" >&2
75+
echo "Ensure /opt/homebrew/bin is in your PATH" >&2
76+
exit 1
77+
fi
1678
fi
1779

1880
# Prevent multiple sourcing of this file to avoid readonly variable errors
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
#!/usr/bin/env bash
2+
3+
# Test CI environment bash fallback behavior
4+
5+
# Minimal test framework for standalone running
6+
TESTS_PASSED=0
7+
TESTS_FAILED=0
8+
9+
run_test() {
10+
local test_name="$1"
11+
echo ""
12+
echo "Running: $test_name"
13+
if $test_name; then
14+
((TESTS_PASSED++))
15+
echo "$test_name passed"
16+
else
17+
((TESTS_FAILED++))
18+
echo "$test_name failed"
19+
fi
20+
}
21+
22+
test_ci_environment_detection() {
23+
echo "Testing CI environment detection..."
24+
25+
# Test 1: CI=true should trigger fallback mode
26+
local output=$(CI=true /bin/bash -c 'source ./lib/common.sh 2>&1' || true)
27+
if echo "$output" | grep -q "Running with bash .* in CI environment"; then
28+
echo "✓ CI=true detected correctly"
29+
else
30+
echo "✗ CI=true not detected"
31+
return 1
32+
fi
33+
34+
# Test 2: GITHUB_ACTIONS=true should trigger fallback mode
35+
output=$(GITHUB_ACTIONS=true /bin/bash -c 'source ./lib/common.sh 2>&1' || true)
36+
if echo "$output" | grep -q "Running with bash .* in CI environment"; then
37+
echo "✓ GITHUB_ACTIONS=true detected correctly"
38+
else
39+
echo "✗ GITHUB_ACTIONS=true not detected"
40+
return 1
41+
fi
42+
43+
# Test 3: Both CI and GITHUB_ACTIONS should work
44+
output=$(CI=true GITHUB_ACTIONS=true /bin/bash -c 'source ./lib/common.sh 2>&1' || true)
45+
if echo "$output" | grep -q "Running with bash .* in CI environment"; then
46+
echo "✓ Both CI and GITHUB_ACTIONS detected correctly"
47+
else
48+
echo "✗ Both flags not detected"
49+
return 1
50+
fi
51+
52+
# Test 4: Check specific disabled features message
53+
if echo "$output" | grep -q "Disabled features: MCP server management, associative arrays, indirect expansion"; then
54+
echo "✓ Disabled features message is correct"
55+
else
56+
echo "✗ Disabled features message is missing or incorrect"
57+
return 1
58+
fi
59+
60+
# Test 5: Check available features message
61+
if echo "$output" | grep -q "Available features: Basic setup preview, simple commands, file operations"; then
62+
echo "✓ Available features message is correct"
63+
else
64+
echo "✗ Available features message is missing or incorrect"
65+
return 1
66+
fi
67+
}
68+
69+
test_ci_minimal_functions() {
70+
echo "Testing CI minimal functions..."
71+
72+
# Create a test script that uses CI functions
73+
local test_script=$(mktemp)
74+
cat > "$test_script" << 'EOF'
75+
#!/bin/bash
76+
export CI=true
77+
source ./lib/common.sh
78+
79+
# Test the minimal functions exist and work
80+
ci_print_info "Test info message"
81+
ci_print_success "Test success message"
82+
ci_print_warning "Test warning message"
83+
ci_print_step "Test step message"
84+
ci_print_error "Test error message"
85+
EOF
86+
87+
# Run with system bash and check output
88+
local output=$(/bin/bash "$test_script" 2>&1)
89+
rm -f "$test_script"
90+
91+
# Check each function output
92+
if echo "$output" | grep -q "ℹ Test info message"; then
93+
echo "✓ ci_print_info works"
94+
else
95+
echo "✗ ci_print_info failed"
96+
return 1
97+
fi
98+
99+
if echo "$output" | grep -q "✓ Test success message"; then
100+
echo "✓ ci_print_success works"
101+
else
102+
echo "✗ ci_print_success failed"
103+
return 1
104+
fi
105+
106+
if echo "$output" | grep -q "⚠ Test warning message"; then
107+
echo "✓ ci_print_warning works"
108+
else
109+
echo "✗ ci_print_warning failed"
110+
return 1
111+
fi
112+
113+
if echo "$output" | grep -q "→ Test step message"; then
114+
echo "✓ ci_print_step works"
115+
else
116+
echo "✗ ci_print_step failed"
117+
return 1
118+
fi
119+
120+
if echo "$output" | grep -q "✗ Test error message"; then
121+
echo "✓ ci_print_error works"
122+
else
123+
echo "✗ ci_print_error failed"
124+
return 1
125+
fi
126+
}
127+
128+
test_ci_logging_support() {
129+
echo "Testing CI logging support..."
130+
131+
local log_file=$(mktemp)
132+
local test_script=$(mktemp)
133+
134+
cat > "$test_script" << EOF
135+
#!/bin/bash
136+
export CI=true
137+
export LOG_FILE="$log_file"
138+
export SCRIPT_NAME="test_ci"
139+
source ./lib/common.sh
140+
141+
ci_print_info "Test log message"
142+
EOF
143+
144+
# Run the script
145+
/bin/bash "$test_script" >/dev/null 2>&1
146+
147+
# Check if log file contains the message
148+
if [[ -f "$log_file" ]] && grep -q "INFO: Test log message" "$log_file"; then
149+
echo "✓ Logging works in CI mode"
150+
else
151+
echo "✗ Logging failed in CI mode"
152+
cat "$log_file" 2>/dev/null || echo "Log file not created"
153+
rm -f "$test_script" "$log_file"
154+
return 1
155+
fi
156+
157+
# Check log format
158+
if grep -q "\[test_ci\] INFO: Test log message" "$log_file"; then
159+
echo "✓ Log format is correct"
160+
else
161+
echo "✗ Log format is incorrect"
162+
rm -f "$test_script" "$log_file"
163+
return 1
164+
fi
165+
166+
rm -f "$test_script" "$log_file"
167+
}
168+
169+
test_non_ci_behavior() {
170+
echo "Testing non-CI behavior..."
171+
172+
# Without CI flags, system bash should fail
173+
local output=$(/bin/bash -c 'source ./lib/common.sh 2>&1' || true)
174+
175+
if echo "$output" | grep -q "Error: This script requires bash 4.0 or higher"; then
176+
echo "✓ Non-CI mode correctly requires bash 4+"
177+
else
178+
echo "✗ Non-CI mode didn't enforce bash version"
179+
return 1
180+
fi
181+
}
182+
183+
test_bash_version_logging() {
184+
echo "Testing bash version logging..."
185+
186+
local log_file=$(mktemp)
187+
local test_script=$(mktemp)
188+
189+
cat > "$test_script" << EOF
190+
#!/bin/bash
191+
export CI=true
192+
export LOG_FILE="$log_file"
193+
source ./lib/common.sh
194+
EOF
195+
196+
# Run the script
197+
/bin/bash "$test_script" >/dev/null 2>&1
198+
199+
# Check if bash version was logged
200+
if [[ -f "$log_file" ]] && grep -q "CI Mode: bash .* detected" "$log_file"; then
201+
echo "✓ Bash version logged for debugging"
202+
else
203+
echo "✗ Bash version not logged"
204+
rm -f "$test_script" "$log_file"
205+
return 1
206+
fi
207+
208+
rm -f "$test_script" "$log_file"
209+
}
210+
211+
# Run all tests
212+
run_test test_ci_environment_detection
213+
run_test test_ci_minimal_functions
214+
run_test test_ci_logging_support
215+
run_test test_non_ci_behavior
216+
run_test test_bash_version_logging
217+
218+
# Summary
219+
echo ""
220+
echo "CI Bash Fallback Test Summary:"
221+
echo "Passed: $TESTS_PASSED"
222+
echo "Failed: $TESTS_FAILED"
223+
224+
[[ $TESTS_FAILED -eq 0 ]]

0 commit comments

Comments
 (0)