Commit Graph

31 Commits

Author SHA1 Message Date
Maximilian Roos 9032308400 refactor(tests): give the PTY test environment one home (#3618)
Follow-up to #3616, which fixed a PTY snapshot flake by adding one env
knob — and to add it I had to touch three separate env builders, none of
which knew about the others. This consolidates that surface.

## What was there

The environment a test subprocess runs in was assembled at nine sites:
five copies of the PTY prologue (`env_clear`, HOME, PATH, the Windows
block, coverage passthrough) and four partial restatements of the
determinism knobs. There was no rule for which belonged where, so adding
a knob meant finding every copy, and a missed copy surfaced later as a
flake somewhere unrelated.

## What's there now

Three named layers, each with one home in `src/testing/mod.rs`:

| Layer | Home | Contents |
|---|---|---|
| Baseline | `STATIC_TEST_ENV_VARS` | knobs every child needs, whatever
it's attached to |
| Terminal | `PTY_TEST_ENV_VARS` (new) | knobs only a TTY triggers —
`WORKTRUNK_TEST_SPINNERS=0` |
| Fixture | `pty_env_vars(TestEnvPaths { … })` (new) | the paths that
vary per fixture |

`configure_cli_command` and `configure_pty_command` apply them by
transport. That turns the standing `// NOTE: TERM is intentionally NOT
in STATIC_TEST_ENV_VARS` comment into a consequence rather than an
exception: `TERM` is transport-level, so it can't sit in a baseline both
transports share.

`WORKTRUNK_TEST_SPINNERS` stays out of the shared baseline deliberately.
It's inert on a pipe, and insta-cmd records the whole environment into
every snapshot it writes (`Info::from_std_command` builds it
unconditionally from `cmd.get_envs()` — there's no hook to suppress it),
so putting it there would add a no-op line to 1043 snapshot files.

`configure_pty_command` is now the only place a PTY child's isolation is
set up. `shell_command`, `execute_shell_script`,
`configure_pty_environment`, `exec_in_pty_shell`,
`exec_bash_truly_interactive` and two `wt switch` spawns all delegate to
it. `shell_wrapper`'s `STANDARD_TEST_ENV` and `bare_repository`'s
hand-rolled `test_env_vars` are gone, as are `configure_shell`'s
hand-copied knobs and four redundant `CLICOLOR_FORCE` lines in
`switch_picker`. Net −149 lines.

One spawn stays outside: the Windows ConPTY smoke test, which runs
PowerShell against a deliberately bare environment and isn't a wt child
at all.

## Reviewing

Start at `src/testing/mod.rs` — the three layers and their doc comments
are the whole design. Everything under `tests/` is deletion plus a
delegation call.

Two snapshots change: `install_preview_with_gutter` and
`install_preview_declined` now carry ANSI, because those two tests
previously ran without `CLICOLOR_FORCE`. Text is identical. Arguably a
fix — the test named "with_gutter" couldn't see the gutter (a
background-color block), while its own prompt line was already colored,
so the file was internally inconsistent.

## Testing

Full `wt hook pre-merge --yes` green: 4601 tests, `--features
shell-integration-tests`, `RUSTFLAGS='-D warnings'`, `insta --check`.

The knob's delivery path was verified by probe rather than by
inspection. With `sleep 6` in the mock `llm`,
`test_readme_example_hooks_pre_merge` passes; flipping
`PTY_TEST_ENV_VARS` to `"1"` reproduces the original failure byte for
byte:

```
+␛[1G␛[J␛[2m↳␛[22m ␛[2mWaiting for the commit generation command (4s)␛[22m␛[1G␛[J␛[2m↳␛[22m ␛[2mWaiting for the commit generation command (5s)␛[22m
```

So the knob reaches the shell-wrapper PTY child through the shared
setup, not through a surviving copy. Both probe edits are reverted.

> _This was written by Claude Code on behalf of max_

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 14:59:48 -07:00
Worktrunk Bot 1d46c0083b fix(test): treat Linux PTY EIO-on-close as EOF in read helpers (#3398)
## Problem

The `code-coverage` job failed on [run
29053905721](https://github.com/max-sixty/worktrunk/actions/runs/29053905721)
(default branch, commit f593438) with a panic in a PTY test:

```
thread '...test_branch_name_with_dashes_underscores::case_3' panicked at tests/common/pty.rs:44:41:
```

Line 44 was `reader.read_to_string(&mut buf).unwrap()` in the Unix
branch of `read_pty_output`. Only `case_3` (fish) panicked;
`case_1`/`case_2` (bash/zsh) passed in the same run — the flaky
signature.

**Root cause:** On Linux, a `read` on a PTY master returns `EIO` once
the child exits and closes the slave side, instead of the clean 0-byte
EOF macOS returns. `read_to_string` propagates that `EIO` as an
`io::Error`, and `.unwrap()` panics. Whether the read observes the `EIO`
or a clean EOF depends on whether it raced ahead of or behind the
child's exit — hence the intermittent, per-case failure.

This is the Linux face of the same fragile read that #3144 diagnosed as
a macOS read-to-EOF timeout; that issue explicitly flagged a more robust
read in this path as the escalation if the flake recurred.

## Solution

Extract a shared `read_pty_master_to_string` helper that reads to
end-of-stream and treats `EIO` as EOF on Unix (a plain `read_to_string`
on Windows/ConPTY, behavior unchanged). Route both PTY-master reads that
shared the fragile `read_to_string().unwrap()` pattern through it:

- `read_pty_output` (`tests/common/pty.rs`) — the shell-wrapper and
README-example PTY path.
- `execute_shell_script` (`tests/common/shell.rs:108`) — the e2e-shell
path, which had the identical pattern and the same latent flake.

`libc` (already present transitively via `portable-pty`) is added to
`[dev-dependencies]` for the canonical `EIO` constant.

## Testing

- `cargo test --test integration --features shell-integration-tests` for
`test_branch_name_with_dashes_underscores` and
`test_source_flag_forwards_errors` (bash/zsh/fish cases) — all pass.
`case_4` (nu) is only skippable locally because nushell isn't installed
in the CI-fix sandbox; it fails at *spawn*, not the read path, and
passed in the original CI run.
- `e2e_shell::*` (7 tests exercising `execute_shell_script`) — all pass.
- `cargo clippy --tests --features shell-integration-tests` and `cargo
fmt --check` — clean.

---
Automated fix for [failed
run](https://github.com/max-sixty/worktrunk/actions/runs/29053905721)

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-09 19:42:48 -07:00
worktrunk-bot 1afa9c230b refactor: rename get_* functions to bare nouns (#1586) 2026-03-17 08:00:16 -07:00
worktrunk-bot 4bfe85403c fix(ci): use compile-time binary path for nextest compatibility (#884)
* fix(ci): build wt binary before running nextest

## Problem

The test `test_switch_with_execute_through_wrapper` was failing on macOS CI with:
```
bash: /Users/runner/work/worktrunk/worktrunk/target/debug/wt: No such file or directory
```

Root cause: `cargo nextest` only builds test binaries, not the main binary. The
shell_wrapper tests use `insta_cmd::get_cargo_bin("wt")` which expects the main
binary to exist at `target/debug/wt`. When running via nextest without building
the binary first, this path doesn't exist, causing the test to fail.

The issue surfaced after commit 0679e6d8 but wasn't caused by that change - it
exposed a pre-existing race condition where tests sometimes ran before the binary
was built.

## Solution

Add `cargo build --bin wt` before the nextest command in the pre-merge hook.
This ensures the main binary is built before tests that depend on it run.

The fix is at the right level because:
- Tests legitimately need the binary to exist (they're testing CLI behavior)
- Building the binary once before all tests is more efficient than per-test builds
- The pre-merge hook is the natural place to ensure test prerequisites are met

## Testing

Verified locally:
```
cargo build --bin wt && NEXTEST_NO_INPUT_HANDLER=1 cargo nextest run \
  --test integration --features shell-integration-tests \
  test_switch_with_execute_through_wrapper
```

Test passes with the binary built first.

---
🤖 Automated fix for [failed run](https://github.com/max-sixty/worktrunk/actions/runs/21382473224)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(ci): use compile-time binary path instead of runtime workaround

Replace `get_cargo_bin("wt")` with `env!("CARGO_BIN_EXE_wt")` via a new
`wt_bin()` helper. The compile-time macro tells Cargo to build the binary
when compiling tests, fixing nextest compatibility without needing an
explicit `cargo build` step.

This supersedes the previous commit's workaround (adding `cargo build --bin wt`
to the pre-merge hook).

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: move wt_bin imports into cfg(unix) blocks

Fix unused import warnings on Windows where some tests are Unix-only.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Maximilian Roos <m@maxroos.com>
2026-01-26 21:24:48 -08:00
Maximilian Roos ffe2d41b42 refactor: simplify test normalization by using insta filters (#672)
* refactor: simplify test normalization by using insta filters

- Remove redundant `normalize_newlines()` from shell_wrapper.rs
  (already handled by `add_pty_filters()`)
- Remove dead `add_pty_tmpdir_filters()` from common/mod.rs
  (no snapshots used [TMPDIR] placeholder)
- Convert config_state.rs `normalize_log_path()` to insta filter
- Convert configure_shell.rs `normalize_output()` to insta filter
  via `install_pty_settings()` function

Analyzed but kept as-is (appropriate for their use cases):
- shell_integration_prompt.rs: Uses `contains()` assertions, not snapshots
- select.rs: Requires line-specific manipulation for TUI timing
- diagnostic.rs: Complex domain-specific normalization with ordering

Net reduction: 46 lines of test code.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: restore CRLF normalization in PTY exec functions

The insta filter for \r\n wasn't fully equivalent to the
String::replace() call. Restore eager normalization to avoid
subtle edge cases with ANSI code matching.

Also removes redundant set_snapshot_path() since it's inherited
from TestRepo's bound settings.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: consolidate CRLF normalization to PTY source

Move CRLF normalization from insta filter to PTY exec functions.
This follows the principle: normalize once, at the source.

Changes:
- Add CRLF normalization to all PTY exec functions
- Remove CRLF filter from add_pty_filters()
- Update snapshots (removes redundant trailing [0m codes)

This eliminates subtle ordering issues between filters and ensures
consistent data for all downstream processing.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 17:06:58 -08:00
Maximilian Roos f584cf7833 test: add cross-platform PTY infrastructure for Windows shell tests (#670)
* test: add cross-platform PTY infrastructure for Windows shell tests

Make shell integration tests cross-platform using portable_pty's ConPTY
support on Windows.

Changes:
- tests/common/mod.rs: Remove Unix-only gate from shell module
- tests/common/shell.rs: Add Windows env vars, PowerShell -Command flag,
  fix PATH separator for PowerShell
- tests/integration_tests/shell_wrapper.rs: Add PowerShell support to
  build_shell_script and exec_in_pty_interactive, add Windows-only
  PowerShell test cases

The Windows tests are gated with #[cfg(windows)] and will run when CI
has Windows runners with PowerShell available.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: gate remaining Unix-only shell tests with #[cfg(unix)]

Three more tests use `shell_command` which is Unix-only:
- test_zsh_completion_produces_correct_output
- test_wrapper_help_redirect_captures_all_output
- test_wrapper_help_interactive_uses_pager

These tests require zsh/bash/fish which aren't available on Windows.
The Windows PowerShell tests at the end of the file remain ungated.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: gate all Unix shell tests with #[cfg(unix)]

Comprehensive update to gate all tests that use bash/zsh/fish shells
with #[cfg(unix)] to prevent them from running on Windows CI.

Tests gated:
- All parameterized shell tests (bash/zsh/fish cases)
- Bash-specific tests (completions, job control, shell integration)
- Zsh-specific tests (wrapper function, job control)
- Fish-specific tests (completions, multiline commands)
- README example tests that use Unix shells

Windows PowerShell tests at the end of the file remain active on
Windows via their existing #[cfg(windows)] attributes.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(tests): gate Unix-only imports and statics for Windows CI

When all Unix shell tests are gated with #[cfg(unix)], the imports and
static variables they use become unused on Windows, causing clippy errors.

Add #[cfg(unix)] to:
- Imports: canonicalize, wait_for_file_content, assert_snapshot, fs,
  PathBuf, LazyLock, shell
- Statics: TMPDIR_REGEX, TMPDIR_PLACEHOLDER_COLLAPSE_REGEX, WORKSPACE_REGEX,
  COMMIT_HASH_REGEX, JOB_CONTROL_REGEX
- Methods: assert_no_job_control_messages, normalized
- Function: generate_completions

Co-Authored-By: Claude <noreply@anthropic.com>

* test(windows): temporarily ignore PowerShell PTY tests

PowerShell PTY tests timeout in CI (60+ seconds). The issue is likely
that Get-Command finds Windows Terminal's wt.exe instead of the test
binary, causing the completion setup to hang.

Mark tests as ignored pending investigation. The test infrastructure
and cross-platform PTY support remain in place.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(tests): gate assert_success method for Windows CI

The assert_success() method (added in #668) is only used by Unix shell
tests. Gate it with #[cfg(unix)] to fix Windows clippy dead_code error.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(tests): organize shell tests by platform

- Group Unix-only imports in single #[cfg(unix)] block
- Move Windows tests into `mod windows_tests` with single #[cfg(windows)]
- Add documentation explaining test organization by platform
- Remove individual #[cfg(windows)] from each Windows test

This makes it clearer which tests run on which platform and reduces
the number of scattered cfg attributes.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(tests): organize shell_wrapper tests by platform with module-level gating

- Replace 46 individual #[cfg(unix)] annotations with single module-level gate
- Restructure from nested `mod tests { mod windows_tests }` to sibling modules:
  - `#[cfg(unix)] mod unix_tests` - 47 bash/zsh/fish tests
  - `#[cfg(windows)] mod windows_tests` - 4 PowerShell tests
- Rename 30 snapshot files to match new module path (__tests__ → __unix_tests__)

This makes platform organization explicit at the module level rather than
scattered across individual test functions.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 16:43:19 -08:00
Maximilian Roos 18b8831534 test: remove runtime shell availability skipping (#443)
Remove skip_if_shell_unavailable! macro from shell integration tests.
Tests are already gated by the shell-integration-tests feature flag,
making runtime skipping redundant. If CI fails to install shells, tests
now fail loudly instead of silently passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-05 19:59:28 -08:00
Maximilian Roos bceedcade7 Fix test isolation for wt commands and improve test API (#314)
Tests that spawn `wt` must be isolated from the host environment to
prevent directive leakage (test commands writing to user's shell
directive file), config pollution, and git interference.

Changes:
- Add `TestRepo::wt_command()` returning pre-configured Command
- Rename `clean_cli_env` → `configure_wt_cmd` (parallel to git)
- Make `git_command()` consistent (no args, chain `.args()`)
- Fix approval_ui.rs and readme_sync.rs missing isolation
- Add `#[must_use]` to command builders
- Document pattern in tests/CLAUDE.md

The public API is now 3 symmetric methods:
- `repo.wt_command()` - for wt commands with TestRepo
- `repo.git_command()` - for git commands
- `wt_command()` - for wt without TestRepo (help tests)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-30 20:29:27 -08:00
Maximilian Roos 5656ed4e1b Remove unnecessary piped stdout bypass from shell wrappers (#278)
The shell wrappers had a check to bypass shell integration when stdout
was piped (e.g., `wt list | jq`). This was needed for an older output
system that didn't cleanly separate stdout from stderr.

With the current output system:
- `table()` → stdout (data)
- `print()` → stderr (status messages)
- Directives → file (cd commands)

This separation means piping works correctly with shell integration
active. Removing the bypass actually improves behavior for cases like
`wt switch feature | tee log.txt` where you want both piped output AND
shell effects (cd).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-21 01:36:44 -08:00
Maximilian Roos b4e2f2e4ed Fix shell wrapper piping and simplify process detachment (#258)
Detached processes now use process_group(0) instead of nohup, allowing
them to survive PTY closure while remaining responsive. Shell wrappers
now detect piping via `[[ ! -t 1 ]]` and bypass the wrapper when stdout
isn't a terminal, enabling commands like `wt list --format=json | jq`.

Updated shell templates (bash, zsh, fish, PowerShell) to check for
redirected output and run the binary directly in those cases. Removed
dev-detach dependency in favor of portable PTY for shell integration
tests. Simplified output routing by removing data_raw() function and
consolidating data output handling. Added FAQ entry explaining JSON
output routing and piping behavior.
2025-12-20 16:59:03 -08:00
Maximilian Roos a458da8726 Clarify shell integration purpose in docs
Shell integration allows commands to change directories. Updated documentation
to separate this explanation from the installation command. Refactored CI
status detection to use non-interactive mode for CLI tools (gh, glab) by
disabling TTY features and stdin. Renamed disable_color_output to
configure_non_interactive and set stdin to /dev/null across all tool
invocations. Simplified shell availability checks in tests with dedicated
helper function.
2025-12-15 20:51:41 -08:00
Maximilian Roos 363edb24fc Improve dev-detach binary detection with custom error handling
Replace get_cargo_bin() with manual binary detection using environment
variables and target directory inspection. This provides a clearer error
message explaining when and how to build the binary, since it's only
built during full workspace tests without package filters.

Also add env and PathBuf to imports for the custom detection logic.
2025-12-10 12:47:33 -08:00
Maximilian Roos 13f3f0bccb Reformat DEV_DETACH_BIN declaration to single line 2025-12-10 04:13:25 -08:00
Maximilian Roos 1377e2c733 Move dev-detach to separate workspace package for dist compatibility
cargo-dist includes all [[bin]] targets from the main package. Moving
dev-detach to its own workspace package (with publish = false) excludes
it from releases while keeping it available for tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 04:01:27 -08:00
Maximilian Roos 6922780d5e Add Windows support via Git Bash with PowerShell fallback (#122)
* Add Windows support via Git Bash with PowerShell fallback

Implements cross-platform shell execution for Windows:

- New `shell_exec` module providing unified shell abstraction
  - Unix: uses `sh -c`
  - Windows: prefers Git Bash (checks $MSYSTEM, standard paths,
    derives from git.exe), falls back to PowerShell
  - Cached detection via OnceLock for performance

- Updated shell execution points to use ShellConfig:
  - execute_streaming() in output/handlers.rs
  - spawn_detached_windows() in commands/process.rs
  - InteractiveOutput::execute() in output/interactive.rs
  - help_pager.rs (skips less default without POSIX shell)

- Added PowerShell shell integration:
  - New Shell::PowerShell variant with config paths
  - templates/powershell.ps1 with documented limitations
  - Basic wt wrapper and tab completion support

Design: Git Bash enables same bash hook syntax on all platforms.
PowerShell fallback works for basic commands but has limitations
(no directory change, hooks using bash syntax won't work).

Closes #121

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add which crate and Windows-specific tests

- Use `which` crate for cleaner executable path detection
- Add Windows-specific unit tests for CI:
  - Shell detection (Git Bash vs PowerShell)
  - Command execution validation
  - POSIX syntax support verification
- Add documentation about Windows limitations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix clippy collapsible_if and improve error message

- Collapse nested if statement in find_git_bash() to satisfy clippy
- Update home directory error message to mention Windows environment variable

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix Windows clippy errors and add PowerShell integration detection

- Gate Command import with #[cfg(unix)] in process.rs
- Gate Stdio and ShellConfig imports with #[cfg(unix)] in interactive.rs
- Add PowerShell profile detection to is_integration_configured()
- Fix collapsible_if warnings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix PowerShell tab completion to use clap's generated script

Previously we had a custom Register-ArgumentCompleter that didn't
properly interface with clap's completion system. Now we let clap
generate its completion script and eval it, which handles:
- Proper cursor position tracking
- Tab-separated output format with help text
- Correct argument passing with -- separator

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add warnings for Windows users without Git Bash

When installing PowerShell shell integration on Windows without Git Bash:
- Show warning about limited functionality
- List specific limitations (no directory change, bash hooks won't work)
- Suggest installing Git for Windows

Also:
- Include PowerShell in auto-detected shells on Windows
- Add is_windows_without_git_bash() helper to ShellConfig

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Improve Windows test assertions

- Check stdout contains expected output instead of just "not empty"
- Remove fallback assertions that would pass even if wrong stream used
- Simplify POSIX redirection test command

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Document PowerShell stdout redirection limitation

PowerShell doesn't support redirecting stdout to stderr (*>&2 fails).
Document this known limitation with link to PowerShell issue #7620.

The practical impact is limited since:
- Users are warned at shell install time about PowerShell limitations
- Hooks using bash syntax need Git Bash anyway
- Most hook output is informational

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add PowerShell directory change support via --internal=powershell

PowerShell can now change directories after `wt switch` using the same
pattern as zoxide/fnm/starship:

1. `--internal` now takes an optional shell type: `--internal=posix` (default)
   or `--internal=powershell`
2. PowerShell wrapper passes `--internal=powershell` and captures stdout
3. Binary outputs `Set-Location 'path'` for PowerShell, `cd 'path'` for POSIX
4. Wrapper executes the directive via Invoke-Expression

Changes:
- Add DirectiveShell enum (Posix, Powershell) to cli.rs
- Update OutputMode::Directive to carry shell type
- Add shell-specific path escaping in directive.rs
- Rewrite PowerShell template to use directive mode
- Update install warning (only hooks limitation now, not cd)
- Add tests for PowerShell path formatting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix Windows implementation weaknesses

- Fix PowerShell backtick escaping (backticks are literal in single quotes)
- Sanitize Windows-illegal characters in log filenames (< > : " \ | ? *)
- Use dirs crate for non-English Windows Documents folder
- Support both PowerShell Core and Windows PowerShell 5.1 profiles
- Add require_equals to --internal flag to fix CLI parsing
- Fix PowerShell wrapper stderr handling (don't merge with stdout)
- Redirect hook stdout to stderr on non-POSIX shells via Stdio::from(io::stderr())

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Address Codex review findings

- Handle Windows reserved device names (CON, PRN, AUX, NUL, COM1-9, LPT1-9)
  in filename sanitization by prefixing with underscore
- Propagate exit code in PowerShell wrapper so $? and $LASTEXITCODE are
  consistent for scripts and CI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Enable shell integration tests on Windows with runtime shell detection

- Remove Unix-only restriction from test common module
- Add shell_available() function to detect available shells at runtime
- Add skip_if_shell_unavailable! macro to skip tests for unavailable shells
- Enable shell-integration-tests feature on Windows CI
- Tests automatically skip unavailable shells (zsh, fish on Windows)

This allows bash tests to run on Windows via Git Bash while gracefully
skipping zsh/fish tests that require those shells.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix Windows reserved device name detection

Code review found that COM0 and LPT0 were incorrectly being treated as
reserved device names. Only COM1-9 and LPT1-9 are reserved on Windows,
not COM0/LPT0.

Changes:
- Change `is_ascii_digit()` to `matches!(c, '1'..='9')` in sanitize_for_filename
- Add comprehensive test coverage for reserved device names
- Add explanatory comment for Windows process detachment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Gate Unix-only test modules to fix Windows CI

The shell integration tests and progressive output tests use Unix-specific
features (PTY, dev-detach binary with setsid). Gate these modules with
#[cfg(unix)] so they don't compile on Windows, fixing dead code warnings.

Changes:
- Gate shell module with #[cfg(all(unix, feature = "shell-integration-tests"))]
- Gate progressive_output module with #[cfg(unix)]
- Gate e2e_shell.rs, e2e_shell_post_start.rs, shell_wrapper.rs with #[cfg(all(unix, ...))]
- Gate list_progressive.rs with #[cfg(unix)]

Windows shell integration support is planned for a future PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Gate test utilities module to Unix-only to fix Windows CI

The tests/common/mod.rs module is only used by integration tests which
are gated to Unix-only. On Windows, the common module was being compiled
but had no consumers, causing dead code warnings that failed CI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-10 11:35:45 +00:00
Maximilian Roos 689af2e1f7 Make dev-detach a compile-time dependency (#123)
Move dev-detach from a separate workspace member to a binary in the main
crate gated behind `shell-integration-tests` feature. This eliminates the
need for explicit `cargo build -p dev-detach` before running tests.

- Move `tests/helpers/dev-detach/` → `tests/bin/dev-detach.rs`
- Add `[[bin]]` with `required-features = ["shell-integration-tests"]`
- Make nix an optional dependency gated by the feature
- Use `env!("CARGO_BIN_EXE_dev-detach")` in tests for compile-time path
- Remove explicit build steps from CI and pre-merge hooks

Benefits:
- Cargo builds dev-detach automatically when running tests with the feature
- No lock contention during parallel test execution
- `cargo install` correctly excludes dev-detach (via required-features)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-10 03:30:25 -08:00
Maximilian Roos 5a793ab727 feat(dev-detach): Extract dev-detach helper into its own package
This refactoring modularizes the `dev-detach` helper by moving it into a dedicated package, improving code organization and reusability.
2025-11-28 15:25:21 -08:00
Maximilian Roos 5f46aa548b Refactor dev-detach helper binary for tests
Moves the `dev-detach` helper binary from `tests/helpers/dev-detach` to `src/bin/dev-detach.rs`.

This simplifies the Cargo workspace configuration, removes a separate `Cargo.toml` and `Cargo.lock` entry, and allows the binary to be built as part of the main `worktrunk` crate under a `shell-integration-tests` feature.

The `fs2` dependency for file locking is removed as `CARGO_BIN_EXE_dev-detach` ensures the binary is already built by `cargo test`.
2025-11-25 16:24:40 -08:00
Maximilian Roos 7a05a54aaa Refactor: Replace expect with unwrap in tests
Replaces most uses of `.expect(...)` with `.unwrap()` in test code. This is a common pattern in Rust tests for operations that are expected to succeed, simplifying the code.
2025-11-23 21:00:31 -08:00
Maximilian Roos 7ca9f3596c refactor: Rename config init to config create 2025-11-21 03:36:47 -08:00
Maximilian Roos 829e5f6b5a Improve dev-detach build error messages
Updates error messages for lock file operations to be more informative,
including the path to the lock file and potential causes of failure.
This makes debugging concurrent test failures easier.
2025-11-18 16:32:50 -08:00
Maximilian Roos 9b91401d85 feat: Handle concurrent dev-detach builds
Addresses intermittent SIGKILL failures during concurrent integration tests
on macOS when `cargo run -p dev-detach` blocked on cargo's package cache
lock.

This change avoids `cargo run` during tests by:
1. Adding `fs2` dependency for file locking.
2. Implementing a `get_dev_detach_bin` function that:
   - Acquires an exclusive file lock to prevent concurrent builds.
   - Builds `dev-detach` only once if the binary does not exist.
   - Returns the path to the pre-built `dev-detach` binary.
3. Updating test logic to invoke the pre-built `dev-detach` directly.
4. Adding `test-concurrent.sh` to `.gitignore`.

This ensures that `dev-detach` is built only once across all concurrent
test processes, eliminating the lock contention that led to SIGKILL.

The new `ISSUE.md` documents the problem, observations, attempts, and open
questions.
2025-11-18 16:06:14 -08:00
Maximilian Roos f4c778c3f1 Remove global workspace manifest from tests
Moves the `workspace_manifest` to be computed per test. This removes
the use of `OnceLock` and `static` which can make debugging more
difficult due to the global state.
2025-11-18 13:13:44 -08:00
Maximilian Roos 9ef288ad0a Remove shell script retry logic in tests
The retry logic was masking actual issues with test flakiness.
Removing it will allow us to address the root causes directly.
The `cargo run` command in the panic message is also updated
to include `--manifest-path <workspace>/Cargo.toml` for clarity.
2025-11-18 13:02:39 -08:00
Maximilian Roos 82a74ae0ca feat: Handle concurrent dev-detach builds in tests 2025-11-18 12:56:30 -08:00
Maximilian Roos bfa76b5eac fix: Add retry logic for shell test failures under parallel load 2025-11-17 23:06:37 -08:00
Maximilian Roos b5b6aeec19 feat: Add PTY support, interactive execution, and refine CLI flags
This commit introduces PTY support and interactive execution, enhancing the CLI experience. It also refines existing CLI flags for better usability.

Additionally, this commit excludes plugin README files from lychee link checking.
2025-11-17 22:33:01 -08:00
Maximilian Roos 2532b88476 feat: improve shell test failure messages and refactor helper functions 2025-11-17 22:10:33 -08:00
Maximilian Roos cfca6567bb Refactor helper binaries into a workspace
This moves `dev-detach` and `setup-select-test` into their own packages within a workspace.
This allows them to be built explicitly as separate packages, ensuring `cargo test` automatically builds `dev-detach` if needed, and simplifying overall project structure.
2025-11-17 15:47:21 -08:00
Maximilian Roos 85ffbee9f2 feat: Enhance shell completion and diff parsing, fix rustdoc warning, and add link exclusions 2025-11-10 18:58:38 -08:00
Maximilian Roos 1185adacb5 Refactor: Extract common shell and list snapshot utilities
This extracts common shell execution and snapshot setup logic into new `tests/common/shell.rs` and `tests/common/list_snapshots.rs` modules. This reduces duplication in integration tests and centralizes utility functions.

- Moves `get_shell_binary`, `execute_shell_script`, `generate_init_code`, `path_export_syntax` from `e2e_shell.rs` and `e2e_shell_post_start.rs` into `tests/common/shell.rs`.
- Moves snapshot settings and command builders from `list.rs` and `spacing_edge_cases.rs` into `tests/common/list_snapshots.rs`.
- Updates `e2e_shell.rs`, `e2e_shell_post_start.rs`, `list.rs`, and `spacing_edge_cases.rs` to import and use these new common utilities.
- Removes redundant snapshot setup code from individual test files.
- Removes `terminal_width_XX.snap` snapshots, as the `COLUMNS` environment variable is now handled by the shared `list_snapshots::command_with_width`.
2025-11-07 09:44:21 -08:00