devlaunch 0.0.15__tar.gz → 0.0.16__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.15 → devlaunch-0.0.16}/PKG-INFO +6 -1
- {devlaunch-0.0.15 → devlaunch-0.0.16}/README.md +5 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/gh_auth.py +33 -6
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/config.py +3 -2
- devlaunch-0.0.16/devlaunch/xdg.py +21 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/pyproject.toml +1 -1
- {devlaunch-0.0.15 → devlaunch-0.0.16}/.gitignore +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/LICENSE +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/__init__.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/aid.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completion.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completion_loader.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completions/__init__.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completions/dl.bash +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/devpod_provider.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/devpod_ssh.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/dl.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/tools.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/tty_session.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/workspace_id.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/__init__.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/branch_manager.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/migration.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/models.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/repo_manager.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/storage.py +0 -0
- {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/workspace_clone.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.16
|
|
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
|
|
@@ -267,6 +267,11 @@ something to be spent on whatever the image ships. Check a workspace with:
|
|
|
267
267
|
dl <workspace> -- gh auth status
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
If no token can be found, `dl` warns on stderr and opens the workspace anyway rather
|
|
271
|
+
than failing — and the warning names the config directory `gh` consulted, because the
|
|
272
|
+
usual cause is a shell that scoped `XDG_CONFIG_HOME` somewhere `gh` has no login,
|
|
273
|
+
not a host that is actually logged out.
|
|
274
|
+
|
|
270
275
|
### Who gets the token
|
|
271
276
|
|
|
272
277
|
Everything running in the container does — including a `postCreateCommand` from a
|
|
@@ -245,6 +245,11 @@ something to be spent on whatever the image ships. Check a workspace with:
|
|
|
245
245
|
dl <workspace> -- gh auth status
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
+
If no token can be found, `dl` warns on stderr and opens the workspace anyway rather
|
|
249
|
+
than failing — and the warning names the config directory `gh` consulted, because the
|
|
250
|
+
usual cause is a shell that scoped `XDG_CONFIG_HOME` somewhere `gh` has no login,
|
|
251
|
+
not a host that is actually logged out.
|
|
252
|
+
|
|
248
253
|
### Who gets the token
|
|
249
254
|
|
|
250
255
|
Everything running in the container does — including a `postCreateCommand` from a
|
|
@@ -27,6 +27,8 @@ import subprocess
|
|
|
27
27
|
import tempfile
|
|
28
28
|
from typing import Dict, Iterator, List, Optional, Tuple
|
|
29
29
|
|
|
30
|
+
from devlaunch.xdg import config_home
|
|
31
|
+
|
|
30
32
|
# The variable set inside the container. gh consults it before its config file.
|
|
31
33
|
TOKEN_VAR = "GH_TOKEN"
|
|
32
34
|
|
|
@@ -74,14 +76,31 @@ def _token_from_gh_cli() -> Optional[str]:
|
|
|
74
76
|
timeout=_GH_TIMEOUT_SECONDS,
|
|
75
77
|
)
|
|
76
78
|
except (OSError, subprocess.SubprocessError) as e:
|
|
77
|
-
logging.
|
|
79
|
+
logging.warning(
|
|
80
|
+
"Could not read a GitHub token from gh (%s), so this workspace opens "
|
|
81
|
+
"without a GitHub login.",
|
|
82
|
+
e,
|
|
83
|
+
)
|
|
78
84
|
return None
|
|
79
85
|
if result.returncode != 0:
|
|
80
|
-
|
|
86
|
+
# Name the config dir: a run that scoped XDG_CONFIG_HOME to a scratch
|
|
87
|
+
# directory hides the host's gh login, so gh refuses even though the user
|
|
88
|
+
# is logged in, and `gh auth login` is exactly the wrong remedy for it.
|
|
89
|
+
logging.warning(
|
|
90
|
+
"gh auth token exited %s, so this workspace opens without a GitHub login. "
|
|
91
|
+
"gh read its config from %s -- if you are logged in on this host, that "
|
|
92
|
+
"directory is the thing to check before `gh auth login`.",
|
|
93
|
+
result.returncode,
|
|
94
|
+
config_home(),
|
|
95
|
+
)
|
|
81
96
|
return None
|
|
82
|
-
# Never log the value itself, only whether it was usable
|
|
97
|
+
# Never log the value itself, only whether it was usable: what gh printed may
|
|
98
|
+
# be a malformed credential, and a warning is not a place to put one.
|
|
83
99
|
if not _is_token(result.stdout.strip()):
|
|
84
|
-
logging.
|
|
100
|
+
logging.warning(
|
|
101
|
+
"gh auth token printed something that is not a token, so this workspace "
|
|
102
|
+
"opens without a GitHub login."
|
|
103
|
+
)
|
|
85
104
|
return None
|
|
86
105
|
return result.stdout.strip()
|
|
87
106
|
|
|
@@ -112,13 +131,21 @@ def _stage_token_file(token: str) -> Optional[str]:
|
|
|
112
131
|
try:
|
|
113
132
|
fd, path = tempfile.mkstemp(prefix="devlaunch-gh-", suffix=".env")
|
|
114
133
|
except OSError as e:
|
|
115
|
-
logging.
|
|
134
|
+
logging.warning(
|
|
135
|
+
"Could not create a file to pass the GitHub token to devpod (%s), so this "
|
|
136
|
+
"workspace opens without a GitHub login.",
|
|
137
|
+
e,
|
|
138
|
+
)
|
|
116
139
|
return None
|
|
117
140
|
try:
|
|
118
141
|
with os.fdopen(fd, "w") as handle:
|
|
119
142
|
handle.write(f"{TOKEN_VAR}={token}\n")
|
|
120
143
|
except OSError as e:
|
|
121
|
-
logging.
|
|
144
|
+
logging.warning(
|
|
145
|
+
"Could not write the GitHub token for devpod (%s), so this workspace "
|
|
146
|
+
"opens without a GitHub login.",
|
|
147
|
+
e,
|
|
148
|
+
)
|
|
122
149
|
with contextlib.suppress(OSError):
|
|
123
150
|
os.unlink(path)
|
|
124
151
|
return None
|
|
@@ -7,6 +7,8 @@ from typing import Dict, Optional, Union
|
|
|
7
7
|
|
|
8
8
|
import tomli
|
|
9
9
|
|
|
10
|
+
from devlaunch.xdg import config_home
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
def _get_cache_base() -> Path:
|
|
12
14
|
"""Get the base cache directory, honoring XDG_CACHE_HOME."""
|
|
@@ -86,8 +88,7 @@ class WorktreeConfig:
|
|
|
86
88
|
|
|
87
89
|
def get_config_path() -> Path:
|
|
88
90
|
"""Get the path to the config file."""
|
|
89
|
-
|
|
90
|
-
return config_dir / "devlaunch" / "config.toml"
|
|
91
|
+
return config_home() / "devlaunch" / "config.toml"
|
|
91
92
|
|
|
92
93
|
|
|
93
94
|
def load_config() -> Dict:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Where the XDG base directories point on this machine.
|
|
2
|
+
|
|
3
|
+
Two unrelated places ask for the config home: the worktree loader, which reads
|
|
4
|
+
`config.toml` under it, and the gh-token warning, which names it so a user whose
|
|
5
|
+
shell scoped the variable can see why `gh auth token` refused. Those two have to
|
|
6
|
+
agree -- a warning that names one directory while the loader reads another is
|
|
7
|
+
worse than no warning -- so they share the answer rather than each spelling it.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def config_home() -> Path:
|
|
15
|
+
"""`$XDG_CONFIG_HOME`, or the `~/.config` the spec falls back to.
|
|
16
|
+
|
|
17
|
+
An empty value counts as unset, which is what the XDG basedir spec says and
|
|
18
|
+
what a shell exporting the variable with no value means. Reading it any other
|
|
19
|
+
way resolves the config path relative to the working directory instead.
|
|
20
|
+
"""
|
|
21
|
+
return Path(os.environ.get("XDG_CONFIG_HOME") or Path.home() / ".config")
|
|
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
|