Skip to content

Commit c96216e

Browse files
Kasper Jungeclaude
authored andcommitted
refactor: extract clone error classification helpers from _raise_clone_error
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bd6ee2b commit c96216e

1 file changed

Lines changed: 41 additions & 17 deletions

File tree

agr/git.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,42 @@ def _reset_repo_dir(repo_dir: Path) -> None:
255255
shutil.rmtree(repo_dir, ignore_errors=True)
256256

257257

258+
def _is_explicit_auth_failure(lowered: str) -> bool:
259+
"""Detect explicit authentication failures from git credential helpers."""
260+
return "authentication failed" in lowered or "permission denied" in lowered
261+
262+
263+
def _is_repo_not_found(lowered: str) -> bool:
264+
"""Detect explicit 'repository not found' responses from the server."""
265+
return (
266+
"repository not found" in lowered
267+
or ("not found" in lowered and "repository" in lowered)
268+
or "does not exist" in lowered
269+
)
270+
271+
272+
def _is_network_error(lowered: str) -> bool:
273+
"""Detect DNS / network failures."""
274+
return "could not resolve host" in lowered
275+
276+
277+
def _is_ambiguous_auth_hint(lowered: str) -> bool:
278+
"""Detect ambiguous errors that likely indicate missing authentication.
279+
280+
When no GitHub token is set, these errors suggest the repo is private
281+
or doesn't exist. Includes the empty-message case — git sometimes
282+
exits non-zero with no output when auth is needed.
283+
"""
284+
return (
285+
not lowered
286+
or "could not read username" in lowered # no credential helper
287+
or "terminal prompts disabled" in lowered # GIT_TERMINAL_PROMPT=0
288+
or "authentication required" in lowered
289+
or "authorization failed" in lowered
290+
or "access denied" in lowered
291+
)
292+
293+
258294
def _raise_clone_error(
259295
stderr: str | None,
260296
owner: str,
@@ -279,7 +315,7 @@ def _raise_clone_error(
279315
token_missing = _is_github_source(source) and not get_github_token()
280316

281317
# 1. Explicit authentication failures (git credential helper responded)
282-
if "authentication failed" in lowered or "permission denied" in lowered:
318+
if _is_explicit_auth_failure(lowered):
283319
if token_missing:
284320
raise AuthenticationError(
285321
f"Authentication failed for source '{source.name}'. "
@@ -290,33 +326,21 @@ def _raise_clone_error(
290326
) from None
291327

292328
# 2. Explicit "not found" responses from the server
293-
if (
294-
"repository not found" in lowered
295-
or ("not found" in lowered and "repository" in lowered)
296-
or "does not exist" in lowered
297-
):
329+
if _is_repo_not_found(lowered):
298330
raise RepoNotFoundError(
299331
f"Repository '{owner}/{repo_name}' not found in source '{source.name}'."
300332
) from None
301333

302334
# 3. DNS / network failures
303-
if "could not resolve host" in lowered:
335+
if _is_network_error(lowered):
304336
raise AgrError(
305337
f"Network error: could not resolve host for source '{source.name}'."
306338
) from None
307339

308340
# 4. Heuristic: when no token is set, ambiguous errors likely mean the
309341
# repo is private or doesn't exist. We report "not found" to guide the
310-
# user toward setting GITHUB_TOKEN. This includes empty stderr (git
311-
# sometimes exits non-zero with no output when auth is needed).
312-
if token_missing and (
313-
not lowered
314-
or "could not read username" in lowered # no credential helper
315-
or "terminal prompts disabled" in lowered # GIT_TERMINAL_PROMPT=0
316-
or "authentication required" in lowered
317-
or "authorization failed" in lowered
318-
or "access denied" in lowered
319-
):
342+
# user toward setting GITHUB_TOKEN.
343+
if token_missing and _is_ambiguous_auth_hint(lowered):
320344
raise RepoNotFoundError(
321345
f"Repository '{owner}/{repo_name}' not found in source '{source.name}'."
322346
) from None

0 commit comments

Comments
 (0)