Skip to content

Commit 6341f20

Browse files
authored
vcspull add path-first workflow and snapshot stability (#481)
why: Prevent duplicate-root regressions, align docs, and keep CLI snapshots noise-free after lint refactors. what: - require repo-path positional, support `--url`/`--name`, auto-detect workspace - log `~/.vcspull.yaml` for dry runs to mirror other CLI outputs - refresh docs/README guidance and changelog for the new workflow - extend add/discover Syrupy snapshots with stable placeholders for line nums - broaden CLI tests for relative paths, workspace overrides, and parser errors
2 parents ebaf90a + e2d16bf commit 6341f20

File tree

14 files changed

+439
-240
lines changed

14 files changed

+439
-240
lines changed

CHANGES

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,25 @@ $ uvx --from 'vcspull' --prerelease allow vcspull
2929

3030
## vcspull v1.44.x (unreleased)
3131

32-
<!-- Maintainers, insert changes / features for the next release here -->
32+
### Improvements
33+
34+
#### `vcspull add` streamlines path-first imports (#481)
35+
36+
- The CLI now requires a repository path as its positional argument, inferring
37+
the name and `origin` remote automatically. Supply `--url` to record an
38+
alternative remote and `--name` when you need a different label.
39+
- Workspace roots default to the checkout's parent directory; use
40+
`--workspace/--workspace-root` to override the destination while keeping the
41+
path-first flow intact.
42+
- CLI output contracts configuration paths to `~/.vcspull.yaml`, keeping
43+
dry-run previews concise when configs live under the home directory.
44+
45+
### Development
46+
47+
#### Snapshot stability for CLI logs (#481)
3348

34-
_Upcoming changes will be written here._
49+
- Discover command snapshots replace volatile line numbers with placeholders so
50+
future refactors and lint rewrites do not break the test suite.
3551

3652
## vcspull v1.43.0 (2025-11-02)
3753

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,18 @@ machines. Subsequent syncs of initialized repos will fetch the latest commits.
9393

9494
### Add repositories from the CLI
9595

96-
Register a single repository without touching YAML manually:
96+
Register a single repository by pointing at the checkout:
9797

9898
```console
99-
$ vcspull add my-lib https://github.com/example/my-lib.git --path ~/code/my-lib
99+
$ vcspull add ~/projects/libs/my-lib
100100
```
101101

102-
- Omit `--path` to default the entry under `./`.
103-
- Use `-w/--workspace` when you want to force a specific workspace root, e.g.
104-
`-w ~/projects/libs`.
105-
- Pass `-f/--file` to add to an alternate YAML file.
106-
- Use `--dry-run` to preview changes before writing.
107-
- Point at an existing checkout (`vcspull add ~/projects/example`) to infer the
108-
name and remote; add `--yes` to skip the confirmation prompt.
102+
- vcspull infers the name from the directory and detects the `origin` remote.
103+
Pass `--url` when you need to record a different remote.
104+
- Override the derived name with `--name` and the workspace root with
105+
`-w/--workspace`.
106+
- `--dry-run` previews the update, while `--yes` skips the confirmation prompt.
107+
- `-f/--file` selects an alternate configuration file.
109108
- Append `--no-merge` if you prefer to review duplicate workspace roots
110109
yourself instead of having vcspull merge them automatically.
111110
- Follow with `vcspull sync my-lib` to clone or update the working tree after registration.

docs/cli/add.md

Lines changed: 63 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
# vcspull add
44

5-
The `vcspull add` command adds a single repository to your vcspull configuration.
6-
Provide a repository name and URL, and vcspull will append it to your config file
7-
with the appropriate workspace root.
5+
The `vcspull add` command registers a repository in your configuration by
6+
pointing vcspull at a checkout on disk. The command inspects the directory,
7+
merges duplicate workspace roots by default, and prompts before writing unless
8+
you pass `--yes`.
89

910
```{note}
1011
This command replaces the manual import functionality from `vcspull import`.
@@ -24,154 +25,112 @@ For bulk scanning of existing repositories, see {ref}`cli-discover`.
2425

2526
## Basic usage
2627

27-
Add a repository by name and URL:
28+
Point to an existing checkout to add it under its parent workspace:
2829

2930
```console
30-
$ vcspull add flask https://github.com/pallets/flask.git
31-
Successfully added 'flask' to ./.vcspull.yaml under './'
31+
$ vcspull add ~/study/python/pytest-docker
32+
Found new repository to import:
33+
+ pytest-docker (https://github.com/avast/pytest-docker)
34+
• workspace: ~/study/python/
35+
↳ path: ~/study/python/pytest-docker
36+
? Import this repository? [y/N]: y
37+
Successfully added 'pytest-docker' (git+https://github.com/avast/pytest-docker) to ~/.vcspull.yaml under '~/study/python/'.
3238
```
3339

34-
By default, the repository is added to the current directory's workspace root (`./`).
40+
The parent directory (`~/study/python/` in this example) becomes the workspace
41+
root. vcspull shortens paths under `$HOME` to `~/...` in its log output so the
42+
preview stays readable.
3543

36-
## Specifying workspace root
44+
## Overriding detected information
3745

38-
Use `-w/--workspace` or `--workspace-root` to control where the repository will be checked out:
46+
### Choose a different name
3947

40-
```console
41-
$ vcspull add flask https://github.com/pallets/flask.git -w ~/code/
42-
Successfully added 'flask' to ~/.vcspull.yaml under '~/code/'
43-
```
44-
45-
All three flag names work identically:
48+
Override the derived repository name with `--name` when the directory name
49+
isn't the label you want stored in the configuration:
4650

4751
```console
48-
$ vcspull add django https://github.com/django/django.git --workspace ~/code/
49-
$ vcspull add requests https://github.com/psf/requests.git --workspace-root ~/code/
52+
$ vcspull add ~/study/python/pytest-docker --name docker-pytest
5053
```
5154

52-
## Custom repository path
55+
### Override the remote URL
5356

54-
Override the inferred path with `--path` when the repository already exists on disk:
57+
vcspull reads the Git `origin` remote automatically. Supply `--url` when you
58+
need to register a different remote or when the checkout does not have one yet:
5559

5660
```console
57-
$ vcspull add my-lib https://github.com/example/my-lib.git \
58-
--path ~/code/libraries/my-lib
61+
$ vcspull add ~/study/python/example --url https://github.com/org/example
5962
```
6063

61-
The `--path` flag is useful when:
62-
- Migrating existing local repositories
63-
- Using non-standard directory layouts
64-
- The repository name doesn't match the desired directory name
65-
66-
You can also point `vcspull add` at an existing checkout. Supplying a path such
67-
as `vcspull add ~/projects/example` infers the repository name, inspects its
68-
`origin` remote, and prompts before writing. Add `--yes` when you need to skip
69-
the confirmation in scripts.
70-
71-
## Choosing configuration files
72-
73-
By default, vcspull looks for the first YAML configuration file in:
74-
1. Current directory (`.vcspull.yaml`)
75-
2. Home directory (`~/.vcspull.yaml`)
76-
3. XDG config directory (`~/.config/vcspull/`)
64+
URLs follow [pip's VCS format][pip vcs url]; vcspull inserts the `git+` prefix
65+
for HTTPS URLs so the resulting configuration matches `vcspull fmt` output.
7766

78-
If no config exists, a new `.vcspull.yaml` is created in the current directory.
67+
### Select a workspace explicitly
7968

80-
Specify a custom config file with `-f/--file`:
69+
The workspace defaults to the checkout's parent directory. Pass
70+
`--workspace`/`--workspace-root` to store the repository under a different
71+
section:
8172

8273
```console
83-
$ vcspull add vcspull https://github.com/vcs-python/vcspull.git \
84-
-f ~/projects/.vcspull.yaml
74+
$ vcspull add ~/scratch/tmp-project --workspace ~/projects/python/
8575
```
8676

87-
## Dry run mode
88-
89-
Preview changes without modifying your configuration with `--dry-run` or `-n`:
90-
91-
```console
92-
$ vcspull add flask https://github.com/pallets/flask.git -w ~/code/ --dry-run
93-
Would add 'flask' (https://github.com/pallets/flask.git) to ~/.vcspull.yaml under '~/code/'
94-
```
95-
96-
This is useful for:
97-
- Verifying the workspace root is correct
98-
- Checking which config file will be modified
99-
- Testing path inference
100-
101-
## URL formats
102-
103-
Repositories use [pip VCS URL][pip vcs url] format with a scheme prefix:
77+
## Confirmation and dry runs
10478

105-
- Git: `git+https://github.com/user/repo.git`
106-
- Mercurial: `hg+https://bitbucket.org/user/repo`
107-
- Subversion: `svn+http://svn.example.org/repo/trunk`
108-
109-
The URL scheme determines the VCS type. For Git, the `git+` prefix is required.
110-
111-
## Examples
112-
113-
Add to default location:
114-
115-
```console
116-
$ vcspull add myproject https://github.com/myuser/myproject.git
117-
```
118-
119-
Add to specific workspace:
79+
`vcspull add` asks for confirmation before writing. Use `--yes` to skip the
80+
prompt in automation, or `--dry-run`/`-n` to preview the changes without
81+
modifying any files:
12082

12183
```console
122-
$ vcspull add django-blog https://github.com/example/django-blog.git \
123-
-w ~/code/django/
84+
$ vcspull add ~/study/python/pytest-docker --dry-run
12485
```
12586

126-
Add with custom path:
87+
Dry runs still show duplicate merge diagnostics so you can see what would
88+
change.
12789

128-
```console
129-
$ vcspull add dotfiles https://github.com/myuser/dotfiles.git \
130-
--path ~/.dotfiles
131-
```
90+
## Choosing configuration files
13291

133-
Preview before adding:
92+
vcspull searches for configuration files in this order:
13493

135-
```console
136-
$ vcspull add flask https://github.com/pallets/flask.git \
137-
-w ~/code/ --dry-run
138-
```
94+
1. `./.vcspull.yaml`
95+
2. `~/.vcspull.yaml`
96+
3. `~/.config/vcspull/*.yaml`
13997

140-
Add to specific config file:
98+
Specify a file explicitly with `-f/--file`:
14199

142100
```console
143-
$ vcspull add tooling https://github.com/company/tooling.git \
144-
-f ~/company/.vcspull.yaml \
145-
-w ~/work/
101+
$ vcspull add ~/study/python/pytest-docker -f ~/configs/python.yaml
146102
```
147103

148104
## Handling duplicates
149105

150-
vcspull merges duplicate workspace sections by default so existing repositories
151-
stay intact. When conflicts appear, the command logs what it kept. Prefer to
152-
resolve duplicates yourself? Pass `--no-merge` to leave every section untouched
153-
while still surfacing warnings.
106+
vcspull merges duplicate workspace sections before writing so existing
107+
repositories stay intact. When it collapses multiple sections, the command logs
108+
a summary of the merge. Prefer to inspect duplicates yourself? Add
109+
`--no-merge` to keep every section untouched.
154110

155111
## After adding repositories
156112

157-
After adding repositories, consider:
158-
159-
1. Running `vcspull fmt --write` to normalize and sort your configuration (see {ref}`cli-fmt`)
160-
2. Running `vcspull list` to verify the repository was added correctly (see {ref}`cli-list`)
161-
3. Running `vcspull sync` to clone the repository (see {ref}`cli-sync`)
113+
1. Run `vcspull fmt --write` to normalize your configuration (see
114+
{ref}`cli-fmt`).
115+
2. Run `vcspull list` to verify the new entry (see {ref}`cli-list`).
116+
3. Run `vcspull sync` to clone or update the working tree (see {ref}`cli-sync`).
162117

163118
## Migration from vcspull import
164119

165-
If you previously used `vcspull import <name> <url>`:
120+
If you previously used `vcspull import <name> <url>`, switch to the path-first
121+
workflow:
166122

167123
```diff
168124
- $ vcspull import flask https://github.com/pallets/flask.git -c ~/.vcspull.yaml
169-
+ $ vcspull add flask https://github.com/pallets/flask.git -f ~/.vcspull.yaml
125+
+ $ vcspull add ~/code/flask --url https://github.com/pallets/flask.git -f ~/.vcspull.yaml
170126
```
171127

172-
Changes:
173-
- Command name: `import``add`
174-
- Config flag: `-c``-f`
175-
- Same functionality otherwise
128+
Key differences:
129+
130+
- `vcspull add` now derives the name from the filesystem unless you pass
131+
`--name`.
132+
- The parent directory becomes the workspace automatically; use `--workspace`
133+
to override.
134+
- Use `--url` to record a remote when the checkout does not have one.
176135

177136
[pip vcs url]: https://pip.pypa.io/en/stable/topics/vcs-support/

src/vcspull/_internal/config_reader.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def _duplicate_tracking_construct_mapping(
241241

242242
for key_node, value_node in node.value:
243243
construct = t.cast(
244-
t.Callable[[yaml.nodes.Node], t.Any],
244+
"t.Callable[[yaml.nodes.Node], t.Any]",
245245
loader.construct_object,
246246
)
247247
key = construct(key_node)
@@ -289,7 +289,7 @@ def _load_yaml_with_duplicates(
289289
try:
290290
data = loader.get_single_data()
291291
finally:
292-
dispose = t.cast(t.Callable[[], None], loader.dispose)
292+
dispose = t.cast("t.Callable[[], None]", loader.dispose)
293293
dispose()
294294

295295
if data is None:
@@ -301,7 +301,7 @@ def _load_yaml_with_duplicates(
301301
loaded = t.cast("dict[str, t.Any]", data)
302302

303303
duplicate_sections = {
304-
t.cast(str, key): values
304+
t.cast("str", key): values
305305
for key, values in loader.top_level_key_values.items()
306306
if len(values) > 1
307307
}

0 commit comments

Comments
 (0)