Skip to content

Commit 8575f47

Browse files
docs & tests maintenance: polish submodule flag docs, async helper, tidy tests
* **CLI** * Add example using `--include-submodules` in help text * Shorten `include_submodules` param description in `_async_main` * Re-order args in `ingest_async` call for readability * **Clone** * Convert `_checkout_partial_clone` to **async** and update docstring accordingly * **Schemas / Entrypoint** * Tighten wording in docstrings for `include_submodules` * **Tests** * Drop redundant `test_cli` case for options mix * Rename `test_clone_commit_without_branch` → `test_clone_commit` * Strengthen `test_clone_with_include_submodules` assertions
1 parent 39c14e8 commit 8575f47

File tree

6 files changed

+35
-47
lines changed

6 files changed

+35
-47
lines changed

src/gitingest/cli.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ def main(**cli_kwargs: Unpack[_CLIArgs]) -> None:
101101
$ gitingest https://github.com/user/private-repo -t ghp_token
102102
$ GITHUB_TOKEN=ghp_token gitingest https://github.com/user/private-repo
103103
104+
Include submodules:
105+
$ gitingest https://github.com/user/repo --include-submodules
106+
104107
"""
105108
asyncio.run(_async_main(**cli_kwargs))
106109

@@ -138,8 +141,7 @@ async def _async_main(
138141
include_gitignored : bool
139142
If ``True``, also ingest files matched by ``.gitignore`` or ``.gitingestignore`` (default: ``False``).
140143
include_submodules : bool
141-
If ``True``, recursively include and analyze all Git submodules within the repository.
142-
Set to ``False`` to ignore submodules during analysis (default is ``False``).
144+
If ``True``, recursively include all Git submodules within the repository (default: ``False``).
143145
token : str | None
144146
GitHub personal access token (PAT) for accessing private repositories.
145147
Can also be set via the ``GITHUB_TOKEN`` environment variable.
@@ -166,15 +168,15 @@ async def _async_main(
166168
click.echo(f"Analyzing source, output will be written to '{output_target}'...", err=True)
167169

168170
summary, _, _ = await ingest_async(
169-
source=source,
171+
source,
170172
max_file_size=max_size,
171173
include_patterns=include_patterns,
172174
exclude_patterns=exclude_patterns,
173175
branch=branch,
174-
include_submodules=include_submodules,
175-
output=output_target,
176176
include_gitignored=include_gitignored,
177+
include_submodules=include_submodules,
177178
token=token,
179+
output=output_target,
178180
)
179181
except Exception as exc:
180182
# Convert any exception into Click.Abort so that exit status is non-zero

src/gitingest/clone.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
4949
branch: str | None = config.branch
5050
tag: str | None = config.tag
5151
partial_clone: bool = config.subpath != "/"
52-
include_submodules: bool = config.include_submodules
5352

5453
# Create parent directory if it doesn't exist
5554
await ensure_directory(Path(local_path).parent)
@@ -64,7 +63,8 @@ async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
6463
clone_cmd += ["-c", create_git_auth_header(token, url=url)]
6564

6665
clone_cmd += ["clone", "--single-branch"]
67-
if include_submodules:
66+
67+
if config.include_submodules:
6868
clone_cmd += ["--recurse-submodules"]
6969

7070
if partial_clone:
@@ -96,28 +96,20 @@ async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
9696
await run_command(*checkout_cmd, "checkout", commit)
9797

9898

99-
def _checkout_partial_clone(config: CloneConfig, token: str | None) -> None:
100-
"""Handle sparse-checkout for partial clones.
101-
102-
This helper function sets the sparse-checkout configuration for a partial clone,
103-
optionally adjusting the subpath if ingesting from a file URL.
99+
async def _checkout_partial_clone(config: CloneConfig, token: str | None) -> None:
100+
"""Configure sparse-checkout for a partially cloned repository.
104101
105102
Parameters
106103
----------
107104
config : CloneConfig
108105
The configuration for cloning the repository, including subpath and blob flag.
109106
token : str | None
110107
GitHub personal access token (PAT) for accessing private repositories.
111-
Can also be set via the ``GITHUB_TOKEN`` environment variable.
112-
113-
Returns
114-
-------
115-
None
116108
117109
"""
118110
subpath = config.subpath.lstrip("/")
119111
if config.blob:
120-
# When ingesting from a file url (blob/branch/path/file.txt), we need to remove the file name.
112+
# Remove the file name from the subpath when ingesting from a file url (e.g. blob/branch/path/file.txt)
121113
subpath = str(Path(subpath).parent.as_posix())
122114
checkout_cmd = create_git_command(["git"], config.local_path, config.url, token)
123-
return run_command(*checkout_cmd, "sparse-checkout", "set", subpath)
115+
await run_command(*checkout_cmd, "sparse-checkout", "set", subpath)

src/gitingest/entrypoint.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async def ingest_async(
5454
include_gitignored : bool
5555
If ``True``, include files ignored by ``.gitignore`` and ``.gitingestignore`` (default: ``False``).
5656
include_submodules : bool
57-
If ``True``, recursively include and analyze all Git submodules within the repository (default: ``False``).
57+
If ``True``, recursively include all Git submodules within the repository (default: ``False``).
5858
token : str | None
5959
GitHub personal access token (PAT) for accessing private repositories.
6060
Can also be set via the ``GITHUB_TOKEN`` environment variable.
@@ -133,7 +133,7 @@ def ingest(
133133
include_gitignored : bool
134134
If ``True``, include files ignored by ``.gitignore`` and ``.gitingestignore`` (default: ``False``).
135135
include_submodules : bool
136-
If ``True``, recursively include and analyze all Git submodules within the repository (default: ``False``).
136+
If ``True``, recursively include all Git submodules within the repository (default: ``False``).
137137
token : str | None
138138
GitHub personal access token (PAT) for accessing private repositories.
139139
Can also be set via the ``GITHUB_TOKEN`` environment variable.

src/gitingest/schemas/ingestion.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
@dataclass
14-
class CloneConfig: # pylint: disable=too-many-instance-attributes, too-many-arguments
14+
class CloneConfig: # pylint: disable=too-many-instance-attributes
1515
"""Configuration for cloning a Git repository.
1616
1717
This class holds the necessary parameters for cloning a repository to a local path, including
@@ -82,7 +82,7 @@ class IngestionQuery(BaseModel): # pylint: disable=too-many-instance-attributes
8282
include_patterns : set[str] | None
8383
The patterns to include.
8484
include_submodules : bool
85-
The flag whether to include Git submodules in the analysis. (default: ``False``)
85+
Whether to include all Git submodules within the repository. (default: ``False``)
8686
8787
"""
8888

tests/test_cli.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,10 @@
2727
"tests/",
2828
"--include-pattern",
2929
"src/",
30-
],
31-
True,
32-
id="custom-options",
33-
),
34-
pytest.param(
35-
[
36-
"./",
37-
"--output",
38-
str(OUTPUT_FILE_NAME),
3930
"--include-submodules",
4031
],
4132
True,
42-
id="with-include-submodules",
33+
id="custom-options",
4334
),
4435
],
4536
)

tests/test_clone.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,10 @@ async def test_clone_default_shallow_clone(run_command_mock: AsyncMock) -> None:
181181

182182

183183
@pytest.mark.asyncio
184-
async def test_clone_commit_without_branch(run_command_mock: AsyncMock) -> None:
185-
"""Test cloning when a commit hash is provided but no branch is specified.
184+
async def test_clone_commit(run_command_mock: AsyncMock) -> None:
185+
"""Test cloning when a commit hash is provided.
186186
187-
Given a valid URL and a commit hash (but no branch):
187+
Given a valid URL and a commit hash:
188188
When ``clone_repo`` is called,
189189
Then the repository should be cloned and checked out at that commit.
190190
"""
@@ -420,19 +420,22 @@ async def test_clone_with_commit_and_subpath(run_command_mock: AsyncMock) -> Non
420420
async def test_clone_with_include_submodules(run_command_mock: AsyncMock) -> None:
421421
"""Test cloning a repository with submodules included.
422422
423-
Given a valid URL and include_submodules=True:
424-
When `clone_repo` is called,
425-
Then the repository should be cloned with --recurse-submodules in the git command.
423+
Given a valid URL and ``include_submodules=True``:
424+
When ``clone_repo`` is called,
425+
Then the repository should be cloned with ``--recurse-submodules`` in the git command.
426426
"""
427+
expected_call_count = 1 # No commit and no partial clone
427428
clone_config = CloneConfig(url=DEMO_URL, local_path=LOCAL_REPO_PATH, branch="main", include_submodules=True)
428429

429430
await clone_repo(clone_config)
430431

431-
# Check that --recurse-submodules is in the clone command
432-
found = False
433-
for call in run_command_mock.call_args_list:
434-
args = call[0]
435-
if "clone" in args and "--recurse-submodules" in args:
436-
found = True
437-
break
438-
assert found, "--recurse-submodules not found in git clone command when include_submodules=True"
432+
assert run_command_mock.call_count == expected_call_count
433+
run_command_mock.assert_called_once_with(
434+
"git",
435+
"clone",
436+
"--single-branch",
437+
"--recurse-submodules",
438+
"--depth=1",
439+
clone_config.url,
440+
clone_config.local_path,
441+
)

0 commit comments

Comments
 (0)