Skip to content

fix(config): let wt config update --print read project config from a linked worktree - #4015

Closed
worktrunk-bot wants to merge 2 commits into
mainfrom
nightly/clean-34016843422
Closed

fix(config): let wt config update --print read project config from a linked worktree#4015
worktrunk-bot wants to merge 2 commits into
mainfrom
nightly/clean-34016843422

Conversation

@worktrunk-bot

Copy link
Copy Markdown
Collaborator

wt config update --print renders the migrated config to stdout and writes nothing, but check_project_config gated it behind the same main-worktree requirement that guards the rewrite. From a linked worktree — where a worktree tool's users mostly stand — the command emitted an empty stdout, silently dropping the project config from the pipe, plus a stderr hint naming wt -C <main> config update, a writing command, in answer to a request that only reads. The rewrite still requires the main worktree; --print no longer does.

Found by the nightly survey while reading src/commands/config/update.rs, then reproduced against a scratch repo before the fix.

Reproduction and verification

Against a repo whose committed .config/wt.toml uses the deprecated {{ repo_root }}:

$ cd main-worktree && wt config update --print
[pre-merge]
check = "echo {{ repo_path }}"

$ cd ../linked-worktree && wt config update --print
                                    # stdout: empty
↳ To update project config:         # stderr, contradicting the
  wt -C /tmp/cfgtest/repo config update   # `--print` contract below

The stderr half also contradicts the stated contract a few lines up in the same function's caller — "--print is for piping, so stderr stays empty" — which test_config_update_print_emits_migrated_without_writing already pins, but only for user config from the main worktree.

Regression test: test_config_update_print_emits_project_config_from_linked_worktree asserts the migrated project config reaches stdout, stderr stays empty, and the file is untouched. Confirmed it fails on main (got: — empty stdout) and passes with the fix.

Verification: cargo clippy --all-targets and cargo fmt --check clean; 137 config_show / config_update integration tests pass, including test_config_update_project_config_from_linked_worktree_shows_hint, which pins that the writing path still declines from a linked worktree.

…linked worktree

The main-worktree requirement in check_project_config exists to keep the
rewrite off a linked checkout, but it also gated --print, which writes
nothing. From a linked worktree -- where a worktree tool's users mostly
stand -- wt config update --print emitted an empty stdout, silently
dropping the project config from the pipe, plus a stderr hint naming
'wt -C <main> config update' (a writing command) in answer to a read.

Gate the rewrite on !is_linked as before; gate --print on nothing.
@worktrunk-bot worktrunk-bot added the nightly-cleanup Issues found by nightly code quality sweep label Sep 6, 2026

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The production change is right: --print writes nothing, handle_config_update returns before the write loop, and check_and_migrate has no filesystem side effects, so widening actionable can't reach the rewrite. One test gap and two observations.

The regression test's write-freedom assertion checks the wrong file. From a linked worktree, project_config_path() resolves against the current worktree root, so the command reads and would write <feature-print>/.config/wt.toml — not the main worktree's copy the test snapshots into before. Verified against a scratch repo with the two copies deliberately diverged: --print from the linked worktree printed the linked copy. The final assert_eq! therefore passes no matter what the command does to the file at risk, which is the half of the --print contract this test exists to pin. Inline suggestion below adds an assertion on the file it actually reads; I applied it locally and the test passes (cargo fmt --check clean).

Two things I'm not asking for in this PR:

  • The same read-vs-write conflation is still live in wt config show. format_deprecation_details in src/config/deprecation.rs returns early on if let Some(main_path) = &info.main_worktree_path, so from a linked worktree it prints the warnings and the To apply: hint but skips the migration diff — a read-only render withheld for a reason that only applies to the rewrite, the same shape this PR fixes for --print.
  • Related, and pre-existing: the retained !actionable branch hints wt -C <main> config update, which acts on the main worktree's .config/wt.toml. Since .config/wt.toml is tracked, that can be a different file with different (or no) deprecations than the linked worktree's copy the warning was derived from. Worth a separate look at whether the write path should refuse a linked worktree at all, rather than redirect to a file the user wasn't asking about.

Heads-up on overlap: #3999 edits the --print block's "stderr stays empty" contract, adding a dropped-approved-commands warning on stderr in print mode. No textual conflict with this diff, and the new test's fixture has no approved-commands so its stderr.is_empty() assertion still holds — but whichever lands second should re-read the other's contract wording.

Comment thread tests/integration_tests/config_show.rs
…grated

The write-freedom assertion checked the main worktree's .config/wt.toml,
which the command never touches when run from a linked worktree:
project_config_path() resolves against the current worktree root, so the
file read — and the one a regression would rewrite — is
<feature-print>/.config/wt.toml. Assert on that copy too.
@worktrunk-bot

Copy link
Copy Markdown
Collaborator Author

Superseded by #4021, which landed on main as 474f93a.

That PR replaced --print with --output <path> / --output=-, and in doing so applied the same gate widening this PR proposes: check_project_config now computes let actionable = read_only || !is_linked;, so output mode reads project config from a linked worktree and only the in-place rewrite still requires the main worktree. The regression test is covered too, by test_config_update_output_stdout_from_linked_worktree, which asserts the same four properties as this PR's test — migrated stdout, empty stderr, and both checkouts' wt.toml unchanged.

What is left of this branch after merging main is a doc comment plus a test that calls the removed --print flag, so it no longer compiles as written. Closing rather than rewriting it; the branch stays in place.

Conflict detail

Test-merged refs/pull/4015/head (d60ee5b) against main at 474f93a: one content conflict in src/commands/config/update.rs, both hunks being this PR's print: bool parameter against main's read_only: bool — the same change under the new flag name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

nightly-cleanup Issues found by nightly code quality sweep

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant