Skip to content

Commit 3531c26

Browse files
duyetclaudeduyetbot
committed
ci: add bash script testing workflow
- Add GitHub Actions workflow for bash script testing - ShellCheck for static analysis - Syntax check for all .sh files - Bash version compatibility tests (4.4, 5.0, 5.1, 5.2) - bats-core unit tests for ralph-wiggum lib functions - Dry run tests for scripts Tests cover: - response_analyzer: completion signals, test-only detection, stuck state - circuit_breaker: initialization, state management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>
1 parent 5505064 commit 3531c26

2 files changed

Lines changed: 226 additions & 0 deletions

File tree

.github/workflows/bash-tests.yml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
name: Bash Tests
2+
3+
on:
4+
push:
5+
branches: [main, master, "claude/**"]
6+
paths:
7+
- "**/*.sh"
8+
- ".github/workflows/bash-tests.yml"
9+
pull_request:
10+
branches: [main, master]
11+
paths:
12+
- "**/*.sh"
13+
- ".github/workflows/bash-tests.yml"
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
shellcheck:
20+
name: ShellCheck
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v5
24+
25+
- name: Run ShellCheck
26+
uses: ludeeus/action-shellcheck@2.0.0
27+
with:
28+
scandir: "."
29+
severity: warning
30+
31+
syntax-check:
32+
name: Syntax Check
33+
runs-on: ubuntu-latest
34+
steps:
35+
- uses: actions/checkout@v5
36+
37+
- name: Check bash syntax
38+
run: |
39+
echo "Checking bash script syntax..."
40+
failed=0
41+
while IFS= read -r -d '' script; do
42+
echo "Checking: $script"
43+
if ! bash -n "$script"; then
44+
echo "❌ Syntax error in: $script"
45+
failed=1
46+
fi
47+
done < <(find . -name "*.sh" -type f -print0)
48+
49+
if [[ $failed -eq 1 ]]; then
50+
echo "❌ Some scripts have syntax errors"
51+
exit 1
52+
fi
53+
echo "✅ All scripts passed syntax check"
54+
55+
compatibility:
56+
name: Bash Compatibility
57+
runs-on: ubuntu-latest
58+
strategy:
59+
matrix:
60+
bash-version: ["4.4", "5.0", "5.1", "5.2"]
61+
steps:
62+
- uses: actions/checkout@v5
63+
64+
- name: Test with bash version
65+
env:
66+
BASH_VERSION_TAG: ${{ matrix.bash-version }}
67+
run: |
68+
docker run --rm -v "$PWD:/workspace" -w /workspace "bash:${BASH_VERSION_TAG}" bash -c '
69+
echo "Testing with bash version:"
70+
bash --version | head -1
71+
72+
failed=0
73+
for script in $(find . -name "*.sh" -type f); do
74+
echo "Checking: $script"
75+
if ! bash -n "$script" 2>&1; then
76+
echo "❌ Failed: $script"
77+
failed=1
78+
fi
79+
done
80+
81+
if [[ $failed -eq 1 ]]; then
82+
exit 1
83+
fi
84+
echo "✅ All scripts compatible"
85+
'
86+
87+
unit-tests:
88+
name: Unit Tests (bats)
89+
runs-on: ubuntu-latest
90+
steps:
91+
- uses: actions/checkout@v5
92+
93+
- name: Setup bats
94+
uses: bats-core/bats-action@2.0.0
95+
96+
- name: Run bats tests
97+
run: |
98+
if [[ -d "tests" ]] && ls tests/*.bats 1>/dev/null 2>&1; then
99+
bats tests/*.bats
100+
else
101+
echo "No bats tests found in tests/ directory"
102+
echo "Skipping unit tests"
103+
fi
104+
105+
dry-run:
106+
name: Dry Run Scripts
107+
runs-on: ubuntu-latest
108+
steps:
109+
- uses: actions/checkout@v5
110+
111+
- name: Install dependencies
112+
run: |
113+
sudo apt-get update
114+
sudo apt-get install -y jq
115+
116+
- name: Dry run ralph-wiggum scripts
117+
run: |
118+
echo "Testing ralph-wiggum scripts can be sourced..."
119+
120+
for lib in ralph-wiggum/lib/*.sh; do
121+
echo "Sourcing: $lib"
122+
(
123+
export RALPH_STATE_DIR="/tmp/ralph-test"
124+
mkdir -p "$RALPH_STATE_DIR"
125+
source "$lib"
126+
echo "✅ $lib sourced successfully"
127+
) || {
128+
echo "❌ Failed to source: $lib"
129+
exit 1
130+
}
131+
done
132+
133+
echo "✅ All lib scripts can be sourced"
134+
135+
- name: Test status script
136+
run: |
137+
echo "Testing status.sh..."
138+
bash ralph-wiggum/scripts/status.sh || true
139+
echo "✅ status.sh runs without crash"
140+
141+
- name: Test cancel script
142+
run: |
143+
echo "Testing cancel-ralph.sh..."
144+
bash ralph-wiggum/scripts/cancel-ralph.sh || true
145+
echo "✅ cancel-ralph.sh runs without crash"

tests/ralph-wiggum.bats

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env bats
2+
3+
# Unit tests for ralph-wiggum bash scripts
4+
5+
setup() {
6+
export RALPH_STATE_DIR="$BATS_TMPDIR/ralph-test-$$"
7+
mkdir -p "$RALPH_STATE_DIR"
8+
9+
# Source the lib scripts
10+
source "$BATS_TEST_DIRNAME/../ralph-wiggum/lib/response_analyzer.sh"
11+
source "$BATS_TEST_DIRNAME/../ralph-wiggum/lib/circuit_breaker.sh"
12+
}
13+
14+
teardown() {
15+
rm -rf "$RALPH_STATE_DIR"
16+
}
17+
18+
# Response Analyzer Tests
19+
20+
@test "response_analyzer: init creates state file" {
21+
init_response_analyzer
22+
[[ -f "$RALPH_STATE_DIR/ralph-analysis.json" ]]
23+
}
24+
25+
@test "response_analyzer: detect completion signals returns confidence" {
26+
result=$(detect_completion_signals "Task complete, all tests pass")
27+
confidence=$(echo "$result" | jq -r '.confidence')
28+
[[ $confidence -gt 0 ]]
29+
}
30+
31+
@test "response_analyzer: detect completion signals with no keywords returns 0" {
32+
result=$(detect_completion_signals "Hello world")
33+
confidence=$(echo "$result" | jq -r '.confidence')
34+
[[ $confidence -eq 0 ]]
35+
}
36+
37+
@test "response_analyzer: detect test only loop identifies test commands" {
38+
result=$(detect_test_only_loop "Running npm test...")
39+
[[ "$result" == "true" ]]
40+
}
41+
42+
@test "response_analyzer: detect test only loop with implementation returns false" {
43+
result=$(detect_test_only_loop "Creating new function and running npm test")
44+
[[ "$result" == "false" ]]
45+
}
46+
47+
@test "response_analyzer: detect stuck state identifies stuck keywords" {
48+
result=$(detect_stuck_state "I am stuck and blocked on this issue")
49+
[[ "$result" == "true" ]]
50+
}
51+
52+
@test "response_analyzer: detect stuck state with normal output returns false" {
53+
result=$(detect_stuck_state "Making progress on the implementation")
54+
[[ "$result" == "false" ]]
55+
}
56+
57+
# Circuit Breaker Tests
58+
59+
@test "circuit_breaker: init creates state file" {
60+
init_circuit_breaker
61+
[[ -f "$RALPH_STATE_DIR/ralph-circuit.json" ]]
62+
}
63+
64+
@test "circuit_breaker: initial state is CLOSED" {
65+
init_circuit_breaker
66+
state=$(get_circuit_state)
67+
[[ "$state" == "CLOSED" ]]
68+
}
69+
70+
@test "circuit_breaker: can_execute returns true when CLOSED" {
71+
init_circuit_breaker
72+
run can_execute
73+
[[ "$status" -eq 0 ]]
74+
}
75+
76+
@test "circuit_breaker: reset_circuit_breaker resets state" {
77+
init_circuit_breaker
78+
reset_circuit_breaker
79+
state=$(get_circuit_state)
80+
[[ "$state" == "CLOSED" ]]
81+
}

0 commit comments

Comments
 (0)