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.
Files changed (27) hide show
  1. {devlaunch-0.0.15 → devlaunch-0.0.16}/PKG-INFO +6 -1
  2. {devlaunch-0.0.15 → devlaunch-0.0.16}/README.md +5 -0
  3. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/gh_auth.py +33 -6
  4. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/config.py +3 -2
  5. devlaunch-0.0.16/devlaunch/xdg.py +21 -0
  6. {devlaunch-0.0.15 → devlaunch-0.0.16}/pyproject.toml +1 -1
  7. {devlaunch-0.0.15 → devlaunch-0.0.16}/.gitignore +0 -0
  8. {devlaunch-0.0.15 → devlaunch-0.0.16}/LICENSE +0 -0
  9. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/__init__.py +0 -0
  10. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/aid.py +0 -0
  11. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completion.py +0 -0
  12. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completion_loader.py +0 -0
  13. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completions/__init__.py +0 -0
  14. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/completions/dl.bash +0 -0
  15. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/devpod_provider.py +0 -0
  16. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/devpod_ssh.py +0 -0
  17. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/dl.py +0 -0
  18. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/tools.py +0 -0
  19. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/tty_session.py +0 -0
  20. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/workspace_id.py +0 -0
  21. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/__init__.py +0 -0
  22. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/branch_manager.py +0 -0
  23. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/migration.py +0 -0
  24. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/models.py +0 -0
  25. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/repo_manager.py +0 -0
  26. {devlaunch-0.0.15 → devlaunch-0.0.16}/devlaunch/worktree/storage.py +0 -0
  27. {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.15
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.debug("Could not read a GitHub token from gh: %s", e)
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
- logging.debug("gh auth token exited %s; no GitHub auth to forward", result.returncode)
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.debug("gh auth token printed something that is not a token; ignoring it")
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.debug("Could not create a file to pass the GitHub token to devpod: %s", e)
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.debug("Could not write the GitHub token for devpod: %s", e)
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
- config_dir = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"))
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")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devlaunch"
3
- version = "0.0.15"
3
+ version = "0.0.16"
4
4
  authors = [{ name = "Austin Gregg-Smith", email = "blooop@gmail.com" }]
5
5
  description = "DevLaunch - A streamlined CLI for devpod workspaces"
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes