@@ -70,22 +70,7 @@ async def test_clone_with_commit(repo_exists_true: AsyncMock, gitpython_mocks: d
70
70
mock_repo .git .checkout .assert_called_with (commit_hash )
71
71
72
72
73
- @pytest .mark .asyncio
74
- async def test_clone_without_commit (repo_exists_true : AsyncMock , run_command_mock : AsyncMock ) -> None :
75
- """Test cloning a repository when no commit hash is provided.
76
73
77
- Given a valid URL and no commit hash:
78
- When ``clone_repo`` is called,
79
- Then only the clone_repo operation should be performed (no checkout).
80
- """
81
- expected_call_count = GIT_INSTALLED_CALLS + 4 # ensure_git_installed + resolve_commit + clone + fetch + checkout
82
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , commit = None , branch = "main" )
83
-
84
- await clone_repo (clone_config )
85
-
86
- repo_exists_true .assert_any_call (clone_config .url , token = None )
87
- assert_standard_calls (run_command_mock , clone_config , commit = DEMO_COMMIT )
88
- assert run_command_mock .call_count == expected_call_count
89
74
90
75
91
76
@pytest .mark .asyncio
@@ -133,227 +118,123 @@ async def test_check_repo_exists(status_code: int, *, expected: bool, mocker: Mo
133
118
assert result is expected
134
119
135
120
136
- @pytest .mark .asyncio
137
- async def test_clone_with_custom_branch (run_command_mock : AsyncMock ) -> None :
138
- """Test cloning a repository with a specified custom branch.
139
121
140
- Given a valid URL and a branch:
141
- When ``clone_repo`` is called,
142
- Then the repository should be cloned shallowly to that branch.
143
- """
144
- expected_call_count = GIT_INSTALLED_CALLS + 4 # ensure_git_installed + resolve_commit + clone + fetch + checkout
145
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , branch = "feature-branch" )
146
122
147
- await clone_repo (clone_config )
148
123
149
- assert_standard_calls (run_command_mock , clone_config , commit = DEMO_COMMIT )
150
- assert run_command_mock .call_count == expected_call_count
151
124
152
125
153
- @pytest .mark .asyncio
154
- async def test_git_command_failure (run_command_mock : AsyncMock ) -> None :
155
- """Test cloning when the Git command fails during execution.
156
126
157
- Given a valid URL, but ``run_command`` raises a RuntimeError:
158
- When ``clone_repo`` is called,
159
- Then a RuntimeError should be raised with the correct message.
160
- """
161
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH )
162
-
163
- run_command_mock .side_effect = RuntimeError ("Git is not installed or not accessible. Please install Git first." )
164
-
165
- with pytest .raises (RuntimeError , match = "Git is not installed or not accessible" ):
166
- await clone_repo (clone_config )
167
-
168
-
169
- @pytest .mark .asyncio
170
- async def test_clone_default_shallow_clone (run_command_mock : AsyncMock ) -> None :
171
- """Test cloning a repository with the default shallow clone options.
172
127
173
- Given a valid URL and no branch or commit:
174
- When ``clone_repo`` is called,
175
- Then the repository should be cloned with ``--depth=1`` and ``--single-branch``.
176
- """
177
- expected_call_count = GIT_INSTALLED_CALLS + 4 # ensure_git_installed + resolve_commit + clone + fetch + checkout
178
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH )
179
-
180
- await clone_repo (clone_config )
181
-
182
- assert_standard_calls (run_command_mock , clone_config , commit = DEMO_COMMIT )
183
- assert run_command_mock .call_count == expected_call_count
184
128
185
129
186
130
@pytest .mark .asyncio
187
- async def test_clone_commit (run_command_mock : AsyncMock ) -> None :
188
- """Test cloning when a commit hash is provided.
189
-
190
- Given a valid URL and a commit hash:
191
- When ``clone_repo`` is called,
192
- Then the repository should be cloned and checked out at that commit.
193
- """
194
- expected_call_count = GIT_INSTALLED_CALLS + 3 # ensure_git_installed + clone + fetch + checkout
195
- commit_hash = "a" * 40 # Simulating a valid commit hash
196
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , commit = commit_hash )
197
-
198
- await clone_repo (clone_config )
199
-
200
- assert_standard_calls (run_command_mock , clone_config , commit = commit_hash )
201
- assert run_command_mock .call_count == expected_call_count
202
-
203
-
204
- @pytest .mark .asyncio
205
- async def test_check_repo_exists_with_redirect (mocker : MockerFixture ) -> None :
206
- """Test ``check_repo_exists`` when a redirect (302) is returned.
207
-
208
- Given a URL that responds with "302 Found":
209
- When ``check_repo_exists`` is called,
210
- Then it should return ``False``, indicating the repo is inaccessible.
211
- """
212
- mock_exec = mocker .patch ("asyncio.create_subprocess_exec" , new_callable = AsyncMock )
213
- mock_process = AsyncMock ()
214
- mock_process .communicate .return_value = (b"302\n " , b"" )
215
- mock_process .returncode = 0 # Simulate successful request
216
- mock_exec .return_value = mock_process
217
-
218
- repo_exists = await check_repo_exists (DEMO_URL )
219
-
220
- assert repo_exists is False
221
-
222
-
223
- @pytest .mark .asyncio
224
- async def test_clone_with_timeout (run_command_mock : AsyncMock ) -> None :
225
- """Test cloning a repository when a timeout occurs.
226
-
227
- Given a valid URL, but ``run_command`` times out:
228
- When ``clone_repo`` is called,
229
- Then an ``AsyncTimeoutError`` should be raised to indicate the operation exceeded time limits.
230
- """
231
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH )
232
-
233
- run_command_mock .side_effect = asyncio .TimeoutError
234
-
235
- with pytest .raises (AsyncTimeoutError , match = "Operation timed out after" ):
236
- await clone_repo (clone_config )
237
-
238
-
239
- @pytest .mark .asyncio
240
- async def test_clone_branch_with_slashes (tmp_path : Path , run_command_mock : AsyncMock ) -> None :
241
- """Test cloning a branch with slashes in the name.
131
+ async def test_clone_without_commit (repo_exists_true : AsyncMock , gitpython_mocks : dict ) -> None :
132
+ """Test cloning a repository when no commit hash is provided.
242
133
243
- Given a valid repository URL and a branch name with slashes :
134
+ Given a valid URL and no commit hash :
244
135
When ``clone_repo`` is called,
245
- Then the repository should be cloned and checked out at that branch .
136
+ Then the repository should be cloned and checked out at the resolved commit .
246
137
"""
247
- branch_name = "fix/in-operator"
248
- local_path = tmp_path / "gitingest"
249
- expected_call_count = GIT_INSTALLED_CALLS + 4 # ensure_git_installed + resolve_commit + clone + fetch + checkout
250
- clone_config = CloneConfig (url = DEMO_URL , local_path = str (local_path ), branch = branch_name )
138
+ clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , commit = None , branch = "main" )
251
139
252
140
await clone_repo (clone_config )
253
141
254
- assert_standard_calls (run_command_mock , clone_config , commit = DEMO_COMMIT )
255
- assert run_command_mock .call_count == expected_call_count
142
+ repo_exists_true .assert_any_call (clone_config .url , token = None )
143
+
144
+ # Verify GitPython calls were made
145
+ mock_git_cmd = gitpython_mocks ["git_cmd" ]
146
+ mock_repo = gitpython_mocks ["repo" ]
147
+ mock_clone_from = gitpython_mocks ["clone_from" ]
148
+
149
+ # Should have resolved the commit via ls_remote
150
+ mock_git_cmd .ls_remote .assert_called ()
151
+ # Should have cloned the repo
152
+ mock_clone_from .assert_called_once ()
153
+ # Should have fetched and checked out
154
+ mock_repo .git .fetch .assert_called ()
155
+ mock_repo .git .checkout .assert_called ()
256
156
257
157
258
158
@pytest .mark .asyncio
259
- async def test_clone_creates_parent_directory (tmp_path : Path , run_command_mock : AsyncMock ) -> None :
159
+ async def test_clone_creates_parent_directory (tmp_path : Path , gitpython_mocks : dict ) -> None :
260
160
"""Test that ``clone_repo`` creates parent directories if they don't exist.
261
161
262
162
Given a local path with non-existent parent directories:
263
163
When ``clone_repo`` is called,
264
164
Then it should create the parent directories before attempting to clone.
265
165
"""
266
- expected_call_count = GIT_INSTALLED_CALLS + 4 # ensure_git_installed + resolve_commit + clone + fetch + checkout
267
166
nested_path = tmp_path / "deep" / "nested" / "path" / "repo"
268
-
269
167
clone_config = CloneConfig (url = DEMO_URL , local_path = str (nested_path ))
270
168
271
169
await clone_repo (clone_config )
272
170
171
+ # Verify parent directories were created
273
172
assert nested_path .parent .exists ()
274
- assert_standard_calls (run_command_mock , clone_config , commit = DEMO_COMMIT )
275
- assert run_command_mock .call_count == expected_call_count
173
+
174
+ # Verify clone operation happened
175
+ mock_clone_from = gitpython_mocks ["clone_from" ]
176
+ mock_clone_from .assert_called_once ()
276
177
277
178
278
179
@pytest .mark .asyncio
279
- async def test_clone_with_specific_subpath (run_command_mock : AsyncMock ) -> None :
180
+ async def test_clone_with_specific_subpath (gitpython_mocks : dict ) -> None :
280
181
"""Test cloning a repository with a specific subpath.
281
182
282
183
Given a valid repository URL and a specific subpath:
283
184
When ``clone_repo`` is called,
284
- Then the repository should be cloned with sparse checkout enabled and the specified subpath .
185
+ Then the repository should be cloned with sparse checkout enabled.
285
186
"""
286
- # ensure_git_installed + resolve_commit + clone + sparse-checkout + fetch + checkout
287
187
subpath = "src/docs"
288
- expected_call_count = GIT_INSTALLED_CALLS + 5
289
188
clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , subpath = subpath )
290
189
291
190
await clone_repo (clone_config )
292
191
293
- # Verify the clone command includes sparse checkout flags
294
- assert_partial_clone_calls (run_command_mock , clone_config , commit = DEMO_COMMIT )
295
- assert run_command_mock .call_count == expected_call_count
192
+ # Verify partial clone (using git.clone instead of Repo.clone_from)
193
+ mock_git_cmd = gitpython_mocks ["git_cmd" ]
194
+ mock_git_cmd .clone .assert_called ()
195
+
196
+ # Verify sparse checkout was configured
197
+ mock_repo = gitpython_mocks ["repo" ]
198
+ mock_repo .git .sparse_checkout .assert_called ()
296
199
297
200
298
201
@pytest .mark .asyncio
299
- async def test_clone_with_commit_and_subpath ( run_command_mock : AsyncMock ) -> None :
300
- """Test cloning a repository with both a specific commit and subpath .
202
+ async def test_clone_with_include_submodules ( gitpython_mocks : dict ) -> None :
203
+ """Test cloning a repository with submodules included .
301
204
302
- Given a valid repository URL, commit hash, and subpath :
205
+ Given a valid URLand ``include_submodules=True`` :
303
206
When ``clone_repo`` is called,
304
- Then the repository should be cloned with sparse checkout enabled,
305
- checked out at the specific commit, and only include the specified subpath.
207
+ Then the repository should update submodules after cloning.
306
208
"""
307
- subpath = "src/docs"
308
- expected_call_count = GIT_INSTALLED_CALLS + 4 # ensure_git_installed + clone + sparse-checkout + fetch + checkout
309
- commit_hash = "a" * 40 # Simulating a valid commit hash
310
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , commit = commit_hash , subpath = subpath )
209
+ clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , branch = "main" , include_submodules = True )
311
210
312
211
await clone_repo (clone_config )
313
212
314
- assert_partial_clone_calls (run_command_mock , clone_config , commit = commit_hash )
315
- assert run_command_mock .call_count == expected_call_count
213
+ # Verify submodule update was called
214
+ mock_repo = gitpython_mocks ["repo" ]
215
+ mock_repo .git .submodule .assert_called_with ("update" , "--init" , "--recursive" , "--depth=1" )
316
216
317
217
318
218
@pytest .mark .asyncio
319
- async def test_clone_with_include_submodules ( run_command_mock : AsyncMock ) -> None :
320
- """Test cloning a repository with submodules included .
219
+ async def test_check_repo_exists_with_redirect ( mocker : MockerFixture ) -> None :
220
+ """Test ``check_repo_exists`` when a redirect (302) is returned .
321
221
322
- Given a valid URL and ``include_submodules=True`` :
323
- When ``clone_repo `` is called,
324
- Then the repository should be cloned with ``--recurse-submodules`` in the git command .
222
+ Given a URL that responds with "302 Found" :
223
+ When ``check_repo_exists `` is called,
224
+ Then it should return ``False``, indicating the repo is inaccessible .
325
225
"""
326
- # ensure_git_installed + resolve_commit + clone + fetch + checkout + checkout submodules
327
- expected_call_count = GIT_INSTALLED_CALLS + 5
328
- clone_config = CloneConfig (url = DEMO_URL , local_path = LOCAL_REPO_PATH , branch = "main" , include_submodules = True )
226
+ mock_exec = mocker .patch ("asyncio.create_subprocess_exec" , new_callable = AsyncMock )
227
+ mock_process = AsyncMock ()
228
+ mock_process .communicate .return_value = (b"302\n " , b"" )
229
+ mock_process .returncode = 0 # Simulate successful request
230
+ mock_exec .return_value = mock_process
329
231
330
- await clone_repo ( clone_config )
232
+ repo_exists = await check_repo_exists ( DEMO_URL )
331
233
332
- assert_standard_calls (run_command_mock , clone_config , commit = DEMO_COMMIT )
333
- assert_submodule_calls (run_command_mock , clone_config )
334
- assert run_command_mock .call_count == expected_call_count
234
+ assert repo_exists is False
335
235
336
236
337
- def assert_standard_calls (mock : AsyncMock , cfg : CloneConfig , commit : str , * , partial_clone : bool = False ) -> None :
338
- """Assert that the standard clone sequence was called.
339
-
340
- Note: With GitPython, some operations are mocked differently as they don't use direct command line calls.
341
- """
342
- # Git version check should still happen
343
- # Note: GitPython may call git differently, so we check for any git version-related calls
344
- # The exact implementation may vary, so we focus on the core functionality
345
-
346
- # For partial clones, we might see different call patterns
347
- # The important thing is that the clone operation succeeded
348
237
349
238
350
- def assert_partial_clone_calls (mock : AsyncMock , cfg : CloneConfig , commit : str ) -> None :
351
- """Assert that the partial clone sequence was called."""
352
- assert_standard_calls (mock , cfg , commit = commit , partial_clone = True )
353
- # With GitPython, sparse-checkout operations may be called differently
354
239
355
240
356
- def assert_submodule_calls (mock : AsyncMock , cfg : CloneConfig ) -> None :
357
- """Assert that submodule update commands were called."""
358
- # With GitPython, submodule operations are handled through the repo object
359
- # The exact call pattern may differ from direct git commands
0 commit comments