Skip to content

Commit 7e89cbe

Browse files
Merge pull request #27 from AndreJorgeLopes/wonderful-swirles-e95c58
fix: prevent fail() from shadowing bats-assert; unmask 9 latent test bugs
2 parents 78cb3d7 + a6e6900 commit 7e89cbe

7 files changed

Lines changed: 33 additions & 25 deletions

File tree

lib/init.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ devflow_init() {
4545
fi
4646
fi
4747
else
48-
fail "$cmd — not found"
48+
status_fail "$cmd — not found"
4949
missing=1
5050
fi
5151
done
@@ -54,7 +54,7 @@ devflow_init() {
5454
if has_cmd brew; then
5555
ok "brew"
5656
else
57-
fail "brew — not found (required on macOS)"
57+
status_fail "brew — not found (required on macOS)"
5858
missing=1
5959
fi
6060
fi

lib/release.sh

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@ _parse_conventional_commits() {
2525
log_target="HEAD"
2626
fi
2727

28-
# Stream commits with NUL separators using git's %x00 (portable, no bash NUL issues)
29-
local commits
30-
commits="$(git -C "$project_dir" log "$log_target" --format='%B%x00' 2>/dev/null || echo "")"
31-
if [[ -z "$commits" ]]; then
28+
# Bail early if the commit range is empty
29+
if ! git -C "$project_dir" log "$log_target" --format='%H' 2>/dev/null | grep -q .; then
3230
echo "none"
3331
return 0
3432
fi
@@ -46,7 +44,9 @@ _parse_conventional_commits() {
4644
local fix_msgs=""
4745
local other_msgs=""
4846

49-
# Parse each commit
47+
# Parse each commit. Stream NUL-delimited blocks directly from git log via
48+
# process substitution — bash command substitution strips NUL bytes, so we
49+
# cannot capture the output into a variable first.
5050
local IFS_SAVE="$IFS"
5151
while IFS= read -r -d '' commit_block; do
5252
[[ -z "$commit_block" ]] && continue
@@ -72,14 +72,15 @@ _parse_conventional_commits() {
7272
other_msgs+="other|${subject}\n"
7373
;;
7474
esac
75-
done < <(printf '%s' "$commits")
75+
done < <(git -C "$project_dir" log "$log_target" --format='%B%x00' 2>/dev/null)
7676
IFS="$IFS_SAVE"
7777

7878
# Output
7979
echo "$bump"
8080
[[ -n "$feat_msgs" ]] && printf "%b" "$feat_msgs"
8181
[[ -n "$fix_msgs" ]] && printf "%b" "$fix_msgs"
8282
[[ -n "$other_msgs" ]] && printf "%b" "$other_msgs"
83+
return 0
8384
}
8485

8586
# ── Semver Arithmetic ────────────────────────────────────────────────────────
@@ -211,6 +212,6 @@ devflow_release_preview() {
211212
if check_version_consistency "$proj" >/dev/null 2>&1; then
212213
ok "Version files are consistent"
213214
else
214-
fail "Version files are inconsistent — run 'devflow check-version' for details"
215+
status_fail "Version files are inconsistent — run 'devflow check-version' for details"
215216
fi
216217
}

lib/seed.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ JSON
146146
if hindsight_post "/v1/retain" "$body" >/dev/null; then
147147
ok "Mental model: ${id}"
148148
else
149-
fail "Failed to seed mental model: ${id}"
149+
status_fail "Failed to seed mental model: ${id}"
150150
fi
151151
}
152152

@@ -169,6 +169,6 @@ JSON
169169
if hindsight_post "/v1/retain" "$body" >/dev/null; then
170170
ok "Directive: ${id}"
171171
else
172-
fail "Failed to seed directive: ${id}"
172+
status_fail "Failed to seed directive: ${id}"
173173
fi
174174
}

lib/services.sh

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,25 +101,25 @@ devflow_status() {
101101
ok "Hindsight container running (Docker)"
102102
hindsight_runtime_found=true
103103
else
104-
fail "Hindsight container not running — run 'devflow up' to start"
104+
status_fail "Hindsight container not running — run 'devflow up' to start"
105105
fi
106106
else
107-
fail "Docker runtime not running — run 'devflow up' to start"
107+
status_fail "Docker runtime not running — run 'devflow up' to start"
108108
fi
109109
fi
110110

111111
if hindsight_available; then
112112
ok "Hindsight API reachable at ${HINDSIGHT_API}"
113113
else
114-
fail "Hindsight API not reachable at ${HINDSIGHT_API}"
114+
status_fail "Hindsight API not reachable at ${HINDSIGHT_API}"
115115
fi
116116

117117
# ── Layer 2: Worktrunk ─────────────────────────────────────────────────────
118118
printf "\n${BOLD}Layer 2: Worktrunk${RESET} (git worktrees)\n"
119119
if has_cmd wt; then
120120
ok "worktrunk (wt) installed"
121121
else
122-
fail "worktrunk (wt) not installed"
122+
status_fail "worktrunk (wt) not installed"
123123
fi
124124

125125
# ── Layer 3: Code Review ────────────────────────────────────────────────────
@@ -131,7 +131,7 @@ devflow_status() {
131131
elif has_cmd opencode; then
132132
ok "Code review CLI: opencode (fallback)"
133133
else
134-
fail "No code review CLI found — install Claude Code or OpenCode"
134+
status_fail "No code review CLI found — install Claude Code or OpenCode"
135135
fi
136136

137137
# ── Layer 4: CLAUDE.md + Skills ────────────────────────────────────────────
@@ -141,7 +141,7 @@ devflow_status() {
141141
if [[ -f "${HOME}/.claude/CLAUDE.md" ]]; then
142142
ok "~/.claude/CLAUDE.md found (user-scoped)"
143143
else
144-
fail "~/.claude/CLAUDE.md not found"
144+
status_fail "~/.claude/CLAUDE.md not found"
145145
fi
146146

147147
# Check project-scoped CLAUDE.md
@@ -169,7 +169,7 @@ devflow_status() {
169169
if claude plugin list 2>/dev/null | grep -q "worktrunk"; then
170170
ok "worktrunk plugin installed"
171171
else
172-
fail "worktrunk plugin not installed"
172+
status_fail "worktrunk plugin not installed"
173173
fi
174174
fi
175175

@@ -179,10 +179,10 @@ devflow_status() {
179179
if docker_compose -f "$compose_file" ps --status running 2>/dev/null | grep -q "langfuse"; then
180180
ok "Langfuse container running"
181181
else
182-
fail "Langfuse container not running — run 'devflow up' to start"
182+
status_fail "Langfuse container not running — run 'devflow up' to start"
183183
fi
184184
else
185-
fail "Docker runtime not running — run 'devflow up' to start"
185+
status_fail "Docker runtime not running — run 'devflow up' to start"
186186
fi
187187

188188
echo ""

lib/utils.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ section() { printf "\n${BOLD}${CYAN}── %s ──${RESET}\n" "$*"; }
2828
detail() { printf " ${DIM}%s${RESET}\n" "$*"; }
2929

3030
# Status indicators
31-
ok() { printf " ${GREEN}${RESET} %s\n" "$*"; }
32-
fail() { printf " ${RED}${RESET} %s\n" "$*"; }
33-
skip() { printf " ${YELLOW}${RESET} %s\n" "$*"; }
31+
ok() { printf " ${GREEN}${RESET} %s\n" "$*"; }
32+
status_fail() { printf " ${RED}${RESET} %s\n" "$*"; }
33+
skip() { printf " ${YELLOW}${RESET} %s\n" "$*"; }
3434

3535
# ── Checks ────────────────────────────────────────────────────────────────────
3636

tests/unit/utils.bats

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ teardown() {
3030
@test "project_root returns directory containing .git" {
3131
run project_root
3232
assert_success
33-
assert [ -d "${output}/.git" ]
33+
# In a regular checkout `.git` is a directory; in a worktree it's a file
34+
# pointing at the parent repo's gitdir. Accept either.
35+
assert [ -e "${output}/.git" ]
3436
}
3537

3638
# ── devflow_root ──────────────────────────────────────────────────

tests/unit/watch.bats

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,12 @@ EOF
204204
# ── _detect_install_mode ───────────────────────────────────────
205205

206206
@test "detect_install_mode returns link for symlinked devflow" {
207-
ln -sf /some/repo/bin/devflow "${MOCK_DIR}/devflow"
207+
# `command -v` skips dangling symlinks, so the target must actually exist
208+
# — otherwise the lookup falls through to a real devflow on PATH.
209+
local target="${BATS_TEST_TMPDIR}/real-devflow"
210+
printf '#!/bin/sh\n' > "$target"
211+
chmod +x "$target"
212+
ln -sf "$target" "${MOCK_DIR}/devflow"
208213
run _detect_install_mode
209214
assert_success
210215
assert_output "link"

0 commit comments

Comments
 (0)