devlaunch 0.0.21__tar.gz → 0.0.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {devlaunch-0.0.21 → devlaunch-0.0.22}/PKG-INFO +9 -3
- {devlaunch-0.0.21 → devlaunch-0.0.22}/README.md +8 -2
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/workspace_state.py +32 -3
- {devlaunch-0.0.21 → devlaunch-0.0.22}/pyproject.toml +1 -1
- {devlaunch-0.0.21 → devlaunch-0.0.22}/.gitignore +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/LICENSE +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/__init__.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/aid.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/completion.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/completion_loader.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/completions/__init__.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/completions/dl.bash +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/devpod_provider.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/devpod_ssh.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/dl.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/gh_auth.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/tools.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/tty_session.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/workspace_id.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/__init__.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/branch_manager.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/config.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/locks.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/migration.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/models.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/repo_manager.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/storage.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/worktree/workspace_clone.py +0 -0
- {devlaunch-0.0.21 → devlaunch-0.0.22}/devlaunch/xdg.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devlaunch
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.22
|
|
4
4
|
Summary: DevLaunch - A streamlined CLI for devpod workspaces
|
|
5
5
|
Project-URL: Source, https://github.com/blooop/devlaunch
|
|
6
6
|
Project-URL: Home, https://github.com/blooop/devlaunch
|
|
@@ -427,13 +427,19 @@ cleanup tool must not ignore — `unsaved`:
|
|
|
427
427
|
"repo": "blooop/devlaunch",
|
|
428
428
|
"branch": "wayfinder/devlaunch-80",
|
|
429
429
|
"state": "Stopped",
|
|
430
|
-
"unsaved": "2 uncommitted change(s) and 1 unpushed commit(s)"
|
|
430
|
+
"unsaved": "2 uncommitted change(s) (pixi.lock, notes.md) and 1 unpushed commit(s)"
|
|
431
431
|
}
|
|
432
432
|
```
|
|
433
433
|
|
|
434
434
|
`unsaved` is a description of what deleting would destroy, or `null` when the
|
|
435
435
|
clone holds nothing that does not also exist on a remote — uncommitted changes
|
|
436
|
-
(untracked files included) and commits no remote has.
|
|
436
|
+
(untracked files included) and commits no remote has. The changed paths are
|
|
437
|
+
named, not just counted, and that matters more than it looks: a devcontainer
|
|
438
|
+
that runs a package install in its `postCreateCommand` can leave a tracked
|
|
439
|
+
lockfile modified in *every* workspace it builds — this repo's own does — and as
|
|
440
|
+
a bare count that is indistinguishable from an hour of unsaved work. A cleanup
|
|
441
|
+
tool believing the count would then never clean anything. Named, it is
|
|
442
|
+
judgeable. A workspace `dl` did not
|
|
437
443
|
create reports `devlaunch: false` with no repo, branch or `unsaved`: there is no
|
|
438
444
|
clone of `dl`'s to protect, and it has no business inspecting your checkout.
|
|
439
445
|
|
|
@@ -405,13 +405,19 @@ cleanup tool must not ignore — `unsaved`:
|
|
|
405
405
|
"repo": "blooop/devlaunch",
|
|
406
406
|
"branch": "wayfinder/devlaunch-80",
|
|
407
407
|
"state": "Stopped",
|
|
408
|
-
"unsaved": "2 uncommitted change(s) and 1 unpushed commit(s)"
|
|
408
|
+
"unsaved": "2 uncommitted change(s) (pixi.lock, notes.md) and 1 unpushed commit(s)"
|
|
409
409
|
}
|
|
410
410
|
```
|
|
411
411
|
|
|
412
412
|
`unsaved` is a description of what deleting would destroy, or `null` when the
|
|
413
413
|
clone holds nothing that does not also exist on a remote — uncommitted changes
|
|
414
|
-
(untracked files included) and commits no remote has.
|
|
414
|
+
(untracked files included) and commits no remote has. The changed paths are
|
|
415
|
+
named, not just counted, and that matters more than it looks: a devcontainer
|
|
416
|
+
that runs a package install in its `postCreateCommand` can leave a tracked
|
|
417
|
+
lockfile modified in *every* workspace it builds — this repo's own does — and as
|
|
418
|
+
a bare count that is indistinguishable from an hour of unsaved work. A cleanup
|
|
419
|
+
tool believing the count would then never clean anything. Named, it is
|
|
420
|
+
judgeable. A workspace `dl` did not
|
|
415
421
|
create reports `devlaunch: false` with no repo, branch or `unsaved`: there is no
|
|
416
422
|
clone of `dl`'s to protect, and it has no business inspecting your checkout.
|
|
417
423
|
|
|
@@ -56,6 +56,13 @@ def _git(repo: Path, *args: str) -> Optional[str]:
|
|
|
56
56
|
never be reported as *safe to delete* on the strength of a failed command —
|
|
57
57
|
every caller here treats ``None`` as "no information", and the one place
|
|
58
58
|
that matters (:func:`holds_unsaved_work`) fails safe explicitly.
|
|
59
|
+
|
|
60
|
+
Only trailing newlines are trimmed, never leading whitespace. A full
|
|
61
|
+
``strip()`` here was wrong in a way that took real use to notice: the first
|
|
62
|
+
line of ``git status --porcelain`` for a *modified tracked* file begins with
|
|
63
|
+
a space (`` M pixi.lock``), so stripping ate the status column and
|
|
64
|
+
:func:`_name_a_few` then reported ``ixi.lock``. Untracked entries start
|
|
65
|
+
``??`` and were unharmed, which is exactly why the tests missed it.
|
|
59
66
|
"""
|
|
60
67
|
try:
|
|
61
68
|
result = subprocess.run(
|
|
@@ -67,7 +74,7 @@ def _git(repo: Path, *args: str) -> Optional[str]:
|
|
|
67
74
|
if result.returncode != 0:
|
|
68
75
|
logger.debug(f"git {' '.join(args)} in {repo}: {result.stderr.strip()}")
|
|
69
76
|
return None
|
|
70
|
-
return result.stdout.
|
|
77
|
+
return result.stdout.rstrip("\n")
|
|
71
78
|
|
|
72
79
|
|
|
73
80
|
def read_clone(clone: Path) -> CloneState:
|
|
@@ -84,6 +91,26 @@ def read_clone(clone: Path) -> CloneState:
|
|
|
84
91
|
return CloneState(branch=branch or None, unsaved=_unsaved(clone, branch))
|
|
85
92
|
|
|
86
93
|
|
|
94
|
+
def _name_a_few(changed: List[str], limit: int = 3) -> str:
|
|
95
|
+
"""Name the first few changed paths from `git status --porcelain` lines.
|
|
96
|
+
|
|
97
|
+
A count alone is not enough to decide anything with. A devcontainer that
|
|
98
|
+
runs `pixi install` in its `postCreateCommand` leaves the tracked lockfile
|
|
99
|
+
modified in *every* workspace it builds, so "1 uncommitted change(s)" is the
|
|
100
|
+
permanent state of an otherwise untouched clone — and a person told only the
|
|
101
|
+
count has no way to tell that from an hour of unsaved work. Told the name,
|
|
102
|
+
they can.
|
|
103
|
+
|
|
104
|
+
The porcelain format is two status characters, a space, then the path, so
|
|
105
|
+
the path starts at offset 3; a rename reads `old -> new`, and the whole
|
|
106
|
+
field is kept rather than split, because both halves are the news.
|
|
107
|
+
"""
|
|
108
|
+
names = [line[3:].strip() for line in changed[:limit] if len(line) > 3]
|
|
109
|
+
if len(changed) > limit:
|
|
110
|
+
names.append("…")
|
|
111
|
+
return ", ".join(names)
|
|
112
|
+
|
|
113
|
+
|
|
87
114
|
def _unsaved(clone: Path, branch: Optional[str]) -> Optional[str]:
|
|
88
115
|
"""What deleting *clone* would destroy, in words, or ``None`` if nothing.
|
|
89
116
|
|
|
@@ -91,7 +118,8 @@ def _unsaved(clone: Path, branch: Optional[str]) -> Optional[str]:
|
|
|
91
118
|
force a delete wants both:
|
|
92
119
|
|
|
93
120
|
- a dirty tree, **untracked files included** — an agent's scratch notes are
|
|
94
|
-
not less lost for never having been added
|
|
121
|
+
not less lost for never having been added — with the first few paths
|
|
122
|
+
named, because a count alone cannot be judged (see :func:`_name_a_few`);
|
|
95
123
|
- commits no remote-tracking ref contains. ``--not --remotes`` asks about
|
|
96
124
|
*any* remote ref rather than this branch's upstream, so work that was
|
|
97
125
|
pushed under another name, or merged and fetched back, is correctly not
|
|
@@ -100,7 +128,8 @@ def _unsaved(clone: Path, branch: Optional[str]) -> Optional[str]:
|
|
|
100
128
|
losses: List[str] = []
|
|
101
129
|
status = _git(clone, "status", "--porcelain")
|
|
102
130
|
if status:
|
|
103
|
-
|
|
131
|
+
changed = status.splitlines()
|
|
132
|
+
losses.append(f"{len(changed)} uncommitted change(s) ({_name_a_few(changed)})")
|
|
104
133
|
if branch:
|
|
105
134
|
# Argument order is load-bearing: `--not` flips the sense of every ref
|
|
106
135
|
# *after* it, so the branch has to be named before it. `log --not
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|