Skip to content

Conversation

@yoshiori
Copy link
Contributor

@yoshiori yoshiori commented Dec 17, 2025

What

Fix fish shell variable scoping bug in wtp cd hook that caused the command to fail silently.

Why

The wtp cd <worktree> command was not working in fish shell. The target_dir variable was always empty when checked outside the if/else block, causing the hook to fall through to the error handling path instead of changing directories.

This bug was introduced in commit 3afdc10 (#64) when adding support for no-argument wtp cd. The fish implementation incorrectly declared target_dir with set -l inside the if/else blocks, but fish's block scoping means local variables declared inside a block are not accessible outside it.

How

Declare the local variable before the if/else block, then assign to it (without -l) inside the blocks:

# Before (broken)
if test -z "$argv[2]"
    set -l target_dir (command wtp cd 2>/dev/null)
else
    set -l target_dir (command wtp cd $argv[2] 2>/dev/null)
end
# $target_dir is empty here!

# After (fixed)
set -l target_dir
if test -z "$argv[2]"
    set target_dir (command wtp cd 2>/dev/null)
else
    set target_dir (command wtp cd $argv[2] 2>/dev/null)
end
# $target_dir contains the path

Testing

  • Added TestFishHook_VariableScoping to verify correct variable declaration pattern
  • Updated existing fish hook tests to expect the fixed syntax
  • All unit tests pass
  • Manual verification:
    source (wtp shell-init fish | psub)
    wtp cd # now works correctly

Breaking Changes

None. This is a bug fix that makes the existing wtp cd command work as documented in fish shell.

Summary by CodeRabbit

  • Bug Fixes

    • Improved Fish shell variable scoping for the cd command to ensure correct behavior.
  • Tests

    • Added test coverage for variable scoping validation in shell hooks.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Walkthrough

The changes refactor how the Fish shell script handles variable scoping for target_dir in the "cd" command processing. The variable is now declared once outside conditional blocks with set -l and reassigned without the -l flag inside branches. Tests are added and updated to validate this new scoping pattern.

Changes

Cohort / File(s) Summary
Fish hook variable scoping
cmd/wtp/hook.go
Modified printFishHook to declare target_dir outside if/else blocks with set -l, then assign without -l inside conditional branches
Variable scoping tests
cmd/wtp/hook_test.go
Added new test TestFishHook_VariableScoping to validate scoping behavior; updated existing fish hook no-arg cd tests to expect assignments without -l flag inside conditional blocks

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify Fish shell syntax correctness for the set -l declaration pattern used
  • Confirm test assertions accurately validate the new scoping behavior and edge cases
  • Check that all conditional branches consistently apply the assignment-without--l pattern

Possibly related PRs

Poem

A rabbit hops through scopes so neat,
Where set -l makes the dance complete!
Outside the blocks, declare with care,
Assign within—no flag to spare. 🐰✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing fish shell variable scoping by declaring target_dir outside if/else blocks.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3afdc10 and e856f76.

📒 Files selected for processing (2)
  • cmd/wtp/hook.go (1 hunks)
  • cmd/wtp/hook_test.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Follow standard Go style with tabs and gofmt; package names must be short and lowercase
Keep import groups tidy; use goimports for organization with local prefix following module path github.com/satococoa/wtp/v2
Adhere to linting rules in .golangci.yml (vet, staticcheck, gosec, mnd, lll=120)
Wrap errors with context; avoid ignoring errors in Go code
Use snake_case for Go filenames (e.g., remove.go, shell_integration.go)
Document exported items in Go when non-trivial; follow godoc conventions

Files:

  • cmd/wtp/hook_test.go
  • cmd/wtp/hook.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Unit tests must be placed alongside packages as *_test.go files in the same directory
Target 70% code coverage with unit tests focusing on fast feedback and mocked git interactions using table-driven test cases

Files:

  • cmd/wtp/hook_test.go
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: Shell integration must separate completion and hooks for clarity; `wtp cd` outputs absolute worktree path with no side effects
📚 Learning: 2025-12-02T13:33:48.693Z
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: Applies to **/*_test.go : Target 70% code coverage with unit tests focusing on fast feedback and mocked git interactions using table-driven test cases

Applied to files:

  • cmd/wtp/hook_test.go
📚 Learning: 2025-12-02T13:33:48.693Z
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: Applies to test/e2e/**/*.go : End-to-end tests must be placed in `test/e2e` and exercise real git workflows using the built binary

Applied to files:

  • cmd/wtp/hook_test.go
📚 Learning: 2025-12-02T13:33:48.693Z
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: Shell integration must separate completion and hooks for clarity; `wtp cd` outputs absolute worktree path with no side effects

Applied to files:

  • cmd/wtp/hook_test.go
  • cmd/wtp/hook.go
📚 Learning: 2025-12-02T13:33:48.693Z
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: Run commands from inside a worktree to mimic real usage (e.g., `go run ../cmd/wtp add feature/new-feature`)

Applied to files:

  • cmd/wtp/hook_test.go
📚 Learning: 2025-12-02T13:33:48.693Z
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: CLI entrypoint is located at `cmd/wtp`; new command implementations must integrate with the main CLI structure

Applied to files:

  • cmd/wtp/hook_test.go
📚 Learning: 2025-12-02T13:33:48.693Z
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: Toggle shell integration paths with `WTP_SHELL_INTEGRATION=1` when testing cd behavior

Applied to files:

  • cmd/wtp/hook_test.go
  • cmd/wtp/hook.go
📚 Learning: 2025-12-02T13:33:48.693Z
Learnt from: CR
Repo: satococoa/wtp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-02T13:33:48.693Z
Learning: Applies to .wtp.yml : Project hooks must be defined in `.wtp.yml`; keep commands deterministic and safe, avoiding destructive steps by default

Applied to files:

  • cmd/wtp/hook_test.go
🔇 Additional comments (3)
cmd/wtp/hook.go (1)

146-150: LGTM! Fish shell variable scoping fix correctly implemented.

The fix properly addresses the fish shell block scoping issue by declaring target_dir once outside the conditional block with set -l, then assigning to it inside branches without the -l flag. This ensures the variable remains accessible after the if/else block completes. The pattern now aligns with the bash (line 80) and zsh (line 113) implementations, which already declare local target_dir outside their conditional blocks.

cmd/wtp/hook_test.go (2)

104-120: Excellent test coverage for the variable scoping fix.

The new test comprehensively validates the fish shell scoping fix by checking all three critical aspects:

  1. target_dir is declared outside the if/else block with set -l (line 112)
  2. The no-arg branch assigns without -l flag (line 116)
  3. The with-arg branch assigns without -l flag (line 118)

The newline check in line 112 appropriately verifies that the declaration is on its own line, ensuring correct scoping structure.


159-162: Updated edge case expectations align with the scoping fix.

The updated test expectations correctly reflect the fix: assignments inside the if/else blocks now use set target_dir (without -l) instead of set -l target_dir. The edge cases remain comprehensively covered: no-arg branch detection, assignment behavior, explicit worktree handling, and safe quoting.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@satococoa satococoa self-requested a review December 18, 2025 13:20
Copy link
Owner

@satococoa satococoa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!! Merging 🚀

@satococoa satococoa merged commit e9095d3 into satococoa:main Dec 18, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants