Skip to content

Commit a343914

Browse files
BareninVitalyafilipchristiansen
authored andcommitted
Merge main into fix/windows-support
1 parent cf80424 commit a343914

File tree

5 files changed

+20
-63
lines changed

5 files changed

+20
-63
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ tmp/
3737

3838
# Project-specific files
3939
history.txt
40-
digest.txt
40+
digest.txt

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,4 @@ repos:
151151
- repo: meta
152152
hooks:
153153
- id: check-hooks-apply
154-
- id: check-useless-excludes
154+
- id: check-useless-excludes

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,4 @@ If you ever get stuck, reach out on [Discord](https://discord.com/invite/zerRaGK
8989

9090
13. **Iterate** on any review feedback—update your branch and repeat **6 – 11** as needed.
9191

92-
*(Optional) Invite a maintainer to your branch for easier collaboration.*
92+
*(Optional) Invite a maintainer to your branch for easier collaboration.*

src/gitingest/utils/git_utils.py

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,15 @@
44

55
import asyncio
66
import base64
7-
import os
87
import re
98
import sys
109
from pathlib import Path
1110
from typing import TYPE_CHECKING, Final, Iterable
1211
import sys
1312
from urllib.parse import urlparse
1413

15-
from starlette.status import (
16-
HTTP_200_OK,
17-
HTTP_301_MOVED_PERMANENTLY,
18-
HTTP_302_FOUND,
19-
HTTP_401_UNAUTHORIZED,
20-
HTTP_403_FORBIDDEN,
21-
HTTP_404_NOT_FOUND,
22-
)
14+
import httpx
15+
from starlette.status import HTTP_200_OK, HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND
2316

2417
from gitingest.utils.exceptions import InvalidGitHubTokenError
2518
from server.server_utils import Colors
@@ -137,46 +130,28 @@ async def check_repo_exists(url: str, token: str | None = None) -> bool:
137130
If the host returns an unrecognised status code.
138131
139132
"""
140-
# TODO: use `requests` instead of `curl`
141-
cmd: list[str] = [
142-
"curl",
143-
"--silent",
144-
"--location",
145-
"--head",
146-
"--write-out",
147-
"%{http_code}",
148-
"-o",
149-
os.devnull,
150-
]
133+
headers = {}
151134

152135
if token and is_github_host(url):
153136
host, owner, repo = _parse_github_url(url)
154137
# Public GitHub vs. GitHub Enterprise
155138
base_api = "https://api.github.com" if host == "github.com" else f"https://{host}/api/v3"
156139
url = f"{base_api}/repos/{owner}/{repo}"
157-
cmd += [f"Authorization: Bearer {token}"]
158-
159-
cmd.append(url)
140+
headers["Authorization"] = f"Bearer {token}"
160141

161-
proc = await asyncio.create_subprocess_exec(
162-
*cmd,
163-
stdout=asyncio.subprocess.PIPE,
164-
stderr=asyncio.subprocess.PIPE,
165-
)
166-
stdout, _ = await proc.communicate()
142+
async with httpx.AsyncClient(follow_redirects=True) as client:
143+
try:
144+
response = await client.head(url, headers=headers)
145+
except httpx.RequestError:
146+
return False
167147

168-
if proc.returncode != 0:
169-
return False
148+
status_code = response.status_code
170149

171-
status = int(stdout.decode().strip())
172-
if status in {HTTP_200_OK, HTTP_301_MOVED_PERMANENTLY}:
150+
if status_code == HTTP_200_OK:
173151
return True
174-
# TODO: handle 302 redirects
175-
if status in {HTTP_404_NOT_FOUND, HTTP_302_FOUND}:
176-
return False
177-
if status in {HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN}:
152+
if status_code in {HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND}:
178153
return False
179-
msg = f"Unexpected HTTP status {status} for {url}"
154+
msg = f"Unexpected HTTP status {status_code} for {url}"
180155
raise RuntimeError(msg)
181156

182157

tests/test_clone.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ async def test_clone_nonexistent_repository(repo_exists_true: AsyncMock) -> None
9191
@pytest.mark.parametrize(
9292
("status_code", "expected"),
9393
[
94-
(b"200\n", 0, True), # Existing repo
95-
(b"404\n", 0, False), # Non-existing repo
96-
(b"200\n", 1, False), # Failed request
94+
(HTTP_200_OK, True),
95+
(HTTP_401_UNAUTHORIZED, False),
96+
(HTTP_403_FORBIDDEN, False),
97+
(HTTP_404_NOT_FOUND, False),
9798
],
9899
)
99100
async def test_check_repo_exists(status_code: int, *, expected: bool, mocker: MockerFixture) -> None:
@@ -208,25 +209,6 @@ async def test_check_repo_exists_with_redirect(mocker: MockerFixture) -> None:
208209
assert repo_exists is False
209210

210211

211-
@pytest.mark.asyncio
212-
async def test_check_repo_exists_with_permanent_redirect(mocker: MockerFixture) -> None:
213-
"""Test ``check_repo_exists`` when a permanent redirect (301) is returned.
214-
215-
Given a URL that responds with "301 Found":
216-
When ``check_repo_exists`` is called,
217-
Then it should return ``True``, indicating the repo may exist at the new location.
218-
"""
219-
mock_exec = mocker.patch("asyncio.create_subprocess_exec", new_callable=AsyncMock)
220-
mock_process = AsyncMock()
221-
mock_process.communicate.return_value = (b"301\n", b"")
222-
mock_process.returncode = 0 # Simulate successful request
223-
mock_exec.return_value = mock_process
224-
225-
repo_exists = await check_repo_exists(DEMO_URL)
226-
227-
assert repo_exists
228-
229-
230212
@pytest.mark.asyncio
231213
async def test_clone_with_timeout(run_command_mock: AsyncMock) -> None:
232214
"""Test cloning a repository when a timeout occurs.

0 commit comments

Comments
 (0)