diff --git a/CHANGES b/CHANGES index cd53ff93..a665f609 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,14 @@ $ uvx --from 'vcspull' --prerelease allow vcspull _Upcoming changes will be written here._ +### Bug Fixes + +#### `vcspull add` keeps tilde workspace labels in path-first mode (#482, #483) + +- Running `vcspull add ~/study/python/…` from inside the workspace now logs the + workspace as `~/study/python/` instead of `./`, preserving tilde-shortened + labels for path-first imports. + ## vcspull v1.45.0 (2025-11-02) ### Bug Fixes diff --git a/src/vcspull/cli/add.py b/src/vcspull/cli/add.py index c18b5bef..f79b5397 100644 --- a/src/vcspull/cli/add.py +++ b/src/vcspull/cli/add.py @@ -201,9 +201,10 @@ def handle_add_command(args: argparse.Namespace) -> None: repo_path, ) + workspace_root_arg = getattr(args, "workspace_root_path", None) workspace_root_input = ( - args.workspace_root_path - if getattr(args, "workspace_root_path", None) + workspace_root_arg + if workspace_root_arg is not None else repo_path.parent.as_posix() ) @@ -212,6 +213,7 @@ def handle_add_command(args: argparse.Namespace) -> None: workspace_path, cwd=cwd, home=pathlib.Path.home(), + preserve_cwd_label=workspace_root_arg in {".", "./"}, ) summary_url = display_url or config_url @@ -479,11 +481,18 @@ def _aggregate_items(items: list[tuple[str, t.Any]]) -> dict[str, t.Any]: cwd=cwd, ) workspace_label = workspace_map.get(workspace_path) + + if workspace_root_path is None: + preserve_workspace_label = path is None + else: + preserve_workspace_label = workspace_root_path in {".", "./"} + if workspace_label is None: workspace_label = workspace_root_label( workspace_path, cwd=cwd, home=home, + preserve_cwd_label=preserve_workspace_label, ) workspace_map[workspace_path] = workspace_label raw_config.setdefault(workspace_label, {}) diff --git a/src/vcspull/config.py b/src/vcspull/config.py index 6dc351e8..1c06e079 100644 --- a/src/vcspull/config.py +++ b/src/vcspull/config.py @@ -588,12 +588,13 @@ def workspace_root_label( *, cwd: pathlib.Path | None = None, home: pathlib.Path | None = None, + preserve_cwd_label: bool = True, ) -> str: """Create a normalized label for a workspace root path.""" cwd = cwd or pathlib.Path.cwd() home = home or pathlib.Path.home() - if workspace_path == cwd: + if preserve_cwd_label and workspace_path == cwd: return "./" try: diff --git a/tests/cli/test_add.py b/tests/cli/test_add.py index 065d8f49..eddafd0f 100644 --- a/tests/cli/test_add.py +++ b/tests/cli/test_add.py @@ -890,3 +890,45 @@ def test_add_repo_no_merge_preserves_duplicate_sections( expected_repos = set(expected_original_repos) | {new_repo_name} assert combined_repos == expected_repos, f"{test_id}: repositories mismatch" assert contains_new_repo, f"{test_id}: new repo missing from duplicate sections" + + +def test_handle_add_command_workspace_label_from_workspace_root( + tmp_path: pathlib.Path, + monkeypatch: MonkeyPatch, + caplog: t.Any, +) -> None: + """CLI add should label workspace roots with their tilde path even from root cwd.""" + caplog.set_level(logging.INFO) + + monkeypatch.setenv("HOME", str(tmp_path)) + + workspace_root = tmp_path / "study/python" + repo_path = workspace_root / "pytest-docker" + init_git_repo(repo_path, remote_url="https://github.com/avast/pytest-docker") + + monkeypatch.chdir(workspace_root) + + config_file = tmp_path / ".vcspull.yaml" + + args = argparse.Namespace( + repo_path=str(repo_path), + url=None, + override_name=None, + config=str(config_file), + workspace_root_path=None, + dry_run=False, + assume_yes=True, + merge_duplicates=True, + ) + + handle_add_command(args) + + expected_label = "~/study/python/" + assert expected_label in caplog.text + + import yaml + + with config_file.open(encoding="utf-8") as fh: + config_data = yaml.safe_load(fh) + + assert expected_label in config_data