Skip to content

Commit 726d2e9

Browse files
authored
Merge branch 'main' into disable-windows-tests
2 parents 9679679 + 49de436 commit 726d2e9

File tree

2 files changed

+152
-29
lines changed

2 files changed

+152
-29
lines changed

README.md

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# GitIngest
22

3+
[![Image](./docs/frontpage.png "GitIngest main page")](https://gitingest.com)
4+
35
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/cyclotruc/gitingest/blob/main/LICENSE)
46
[![PyPI version](https://badge.fury.io/py/gitingest.svg)](https://badge.fury.io/py/gitingest)
57
[![Downloads](https://pepy.tech/badge/gitingest)](https://pepy.tech/project/gitingest)
68
[![GitHub issues](https://img.shields.io/github/issues/cyclotruc/gitingest)](https://github.com/cyclotruc/gitingest/issues)
79
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
810
[![Discord](https://dcbadge.limes.pink/api/server/https://discord.com/invite/zerRaGK9EC)](https://discord.com/invite/zerRaGK9EC)
911

10-
[![Image](./docs/frontpage.png "GitIngest main page")](https://gitingest.com)
11-
1212
Turn any Git repository into a prompt-friendly text ingest for LLMs.
1313

1414
You can also replace `hub` with `ingest` in any github url to access the coresponding digest
@@ -62,13 +62,6 @@ summary, tree, content = ingest("https://github.com/cyclotruc/gitingest")
6262

6363
By default, this won't write a file but can be enabled with the `output` argument
6464

65-
## 🛠️ Using
66-
67-
- Tailwind CSS - Frontend
68-
- [FastAPI](https://github.com/fastapi/fastapi) - Backend framework
69-
- [tiktoken](https://github.com/openai/tiktoken) - Token estimation
70-
- [apianalytics.dev](https://www.apianalytics.dev/) - Simple Analytics
71-
7265
## 🌐 Self-host
7366

7467
1. Build the image:
@@ -84,35 +77,45 @@ By default, this won't write a file but can be enabled with the `output` argumen
8477
```
8578

8679
The application will be available at `http://localhost:8000`
87-
Ensure environment variables are set before running the application or deploying it via Docker.
8880

89-
## ✔️ Contributing
81+
If you are hosting it on a domain, you can specify the allowed hostnames via env variable `ALLOWED_HOSTS`.
9082

91-
Contributions are welcome!
83+
```bash
84+
#Default: "gitingest.com,*.gitingest.com,localhost, 127.0.0.1".
85+
ALLOWED_HOSTS="example.com, localhost, 127.0.0.1"
86+
```
9287

93-
Gitingest aims to be friendly for first time contributors, with a simple python and html codebase. If you need any help while working with the code, reach out to us on [discord](https://discord.com/invite/zerRaGK9EC)
88+
## 🛠️ Stack
9489

95-
### Ways to contribute
90+
- [Tailwind CSS](https://tailwindcss.com/) - Frontend
91+
- [FastAPI](https://github.com/fastapi/fastapi) - Backend framework
92+
- [Jinja2](https://jinja.palletsprojects.com/) - HTML templating
93+
- [tiktoken](https://github.com/openai/tiktoken) - Token estimation
94+
- [apianalytics.dev](https://www.apianalytics.dev/) - Simple Analytics
9695

97-
1. Provide your feedback and ideas on discord
98-
2. Open an Issue on github to report a bug
99-
3. Create a Pull request
100-
- Fork the repository
101-
- Make your changes and test them locally
102-
- Open a pull request for review and feedback
96+
## ✔️ Contributing to Gitingest
10397

104-
### 🔧 Local dev
98+
Gitingest aims to be friendly for first time contributors, with a simple python and html codebase.
99+
If you need any help while working with the code, reach out to us on [discord](https://discord.com/invite/zerRaGK9EC)
105100

106-
#### Environment Configuration
101+
### Ways to help (non-technical)
107102

108-
- **`ALLOWED_HOSTS`**: Specify allowed hostnames for the application. Default: `"gitingest.com,*.gitingest.com,gitdigest.dev,localhost"`.
109-
You can configure the application using the following environment variables:
103+
- Provide your feedback and ideas on discord
104+
- Open an Issue on github to report a bug / submit an feature request
105+
- Talk about Gitingest on social media
110106

111-
```bash
112-
ALLOWED_HOSTS="gitingest.local,localhost"
113-
```
107+
### How to submit a PR
114108

115-
#### Run locally
109+
1. Fork the repository & clone it locally
110+
2. Setup the dev environment (see Development section bellow)
111+
3. Run unit tests with `pytest`
112+
4. Commit your changes and run `pre-commit`
113+
5. Open a pull request on Github for review and feedback
114+
6. (Optionnal) Invite project maintainer to your branch for easier collaboration
115+
116+
## 🔧 Development
117+
118+
### Run web UI locally
116119

117120
1. Clone the repository
118121

@@ -124,7 +127,10 @@ ALLOWED_HOSTS="gitingest.local,localhost"
124127
2. Install dependencies
125128

126129
```bash
127-
pip install -r requirements.txt
130+
pip install -r requirements-dev.txt
131+
python -m venv .venv
132+
source .venv/bin/activate
133+
pre-commit install
128134
```
129135

130136
3. Run the application:
@@ -133,3 +139,25 @@ ALLOWED_HOSTS="gitingest.local,localhost"
133139
cd src
134140
uvicorn main:app --reload
135141
```
142+
143+
4. Run unit tests
144+
145+
```bash
146+
pytest
147+
```
148+
149+
The application should be available at `http://localhost:8000`
150+
151+
### Working on the CLI
152+
153+
1. Install the package in dev mode
154+
155+
```bash
156+
pip install -e .
157+
```
158+
159+
2. Run the CLI
160+
161+
```bash
162+
gitingest --help
163+
```

src/gitingest/tests/test_clone.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,98 @@ async def test_check_repo_exists() -> None:
7474
# Test failed request
7575
mock_process.returncode = 1
7676
assert await _check_repo_exists(url) is False
77+
78+
79+
@pytest.mark.asyncio
80+
async def test_clone_repo_invalid_url() -> None:
81+
clone_config = CloneConfig(
82+
url="",
83+
local_path="/tmp/repo",
84+
)
85+
with pytest.raises(ValueError, match="The 'url' parameter is required."):
86+
await clone_repo(clone_config)
87+
88+
89+
@pytest.mark.asyncio
90+
async def test_clone_repo_invalid_local_path() -> None:
91+
clone_config = CloneConfig(
92+
url="https://github.com/user/repo",
93+
local_path="",
94+
)
95+
with pytest.raises(ValueError, match="The 'local_path' parameter is required."):
96+
await clone_repo(clone_config)
97+
98+
99+
@pytest.mark.asyncio
100+
async def test_clone_repo_with_custom_branch() -> None:
101+
clone_config = CloneConfig(
102+
url="https://github.com/user/repo",
103+
local_path="/tmp/repo",
104+
branch="feature-branch",
105+
)
106+
with patch("gitingest.clone._check_repo_exists", return_value=True):
107+
with patch("gitingest.clone._run_git_command", new_callable=AsyncMock) as mock_exec:
108+
await clone_repo(clone_config)
109+
mock_exec.assert_called_once_with(
110+
"git",
111+
"clone",
112+
"--depth=1",
113+
"--single-branch",
114+
"--branch",
115+
"feature-branch",
116+
clone_config.url,
117+
clone_config.local_path,
118+
)
119+
120+
121+
@pytest.mark.asyncio
122+
async def test_git_command_failure() -> None:
123+
clone_config = CloneConfig(
124+
url="https://github.com/user/repo",
125+
local_path="/tmp/repo",
126+
)
127+
with patch("gitingest.clone._check_repo_exists", return_value=True):
128+
with patch("gitingest.clone._run_git_command", side_effect=RuntimeError("Git command failed")):
129+
with pytest.raises(RuntimeError, match="Git command failed"):
130+
await clone_repo(clone_config)
131+
132+
133+
@pytest.mark.asyncio
134+
async def test_clone_repo_default_shallow_clone() -> None:
135+
clone_config = CloneConfig(
136+
url="https://github.com/user/repo",
137+
local_path="/tmp/repo",
138+
)
139+
with patch("gitingest.clone._check_repo_exists", return_value=True):
140+
with patch("gitingest.clone._run_git_command", new_callable=AsyncMock) as mock_exec:
141+
await clone_repo(clone_config)
142+
mock_exec.assert_called_once_with(
143+
"git", "clone", "--depth=1", "--single-branch", clone_config.url, clone_config.local_path
144+
)
145+
146+
147+
@pytest.mark.asyncio
148+
async def test_clone_repo_commit_without_branch() -> None:
149+
clone_config = CloneConfig(
150+
url="https://github.com/user/repo",
151+
local_path="/tmp/repo",
152+
commit="a" * 40, # Simulating a valid commit hash
153+
)
154+
with patch("gitingest.clone._check_repo_exists", return_value=True):
155+
with patch("gitingest.clone._run_git_command", new_callable=AsyncMock) as mock_exec:
156+
await clone_repo(clone_config)
157+
assert mock_exec.call_count == 2 # Clone and checkout calls
158+
mock_exec.assert_any_call("git", "clone", "--single-branch", clone_config.url, clone_config.local_path)
159+
mock_exec.assert_any_call("git", "-C", clone_config.local_path, "checkout", clone_config.commit)
160+
161+
162+
@pytest.mark.asyncio
163+
async def test_check_repo_exists_with_redirect() -> None:
164+
url = "https://github.com/user/repo"
165+
with patch("asyncio.create_subprocess_exec", new_callable=AsyncMock) as mock_exec:
166+
mock_process = AsyncMock()
167+
mock_process.communicate.return_value = (b"HTTP/1.1 302 Found\n", b"")
168+
mock_process.returncode = 0 # Simulate successful request
169+
mock_exec.return_value = mock_process
170+
171+
assert await _check_repo_exists(url)

0 commit comments

Comments
 (0)