Skip to content

Commit 7b4e61e

Browse files
EliahKaganclaude
andcommitted
Add a test that required submodules are initialized
This adds the new test, `test_required_submodule_is_initialized`, to `test_fixture_health.py`. For the gitdb and smmap submodules, the test asserts that the working tree directory exists and contains a `.git` marker (file or directory). The failure message reminds the developer to run `git submodule update --init --recursive`. This is a regression test for a different contract than the preexisting `test_fixture_dir_is_trusted_by_git` in `test_fixture_health.py`. That test verifies git's willingness to operate in each fixture directory (the `safe.directory` / dubious-ownership contract). This one verifies that the directories are populated at all. A bug where they were not populated affected Arch Linux in gitpython-developers#1713 when `init-tests-after-clone.sh` stopped running `git submodule update` on CI. The visible failure was a cascade of test failures across `test_docs.py`, `test_repo.py`, and `test_submodule.py` -- tests that don't set out to check submodule presence but fail when the submodules aren't there. This test checks for that explicitly, with a single clear assertion. The test skips when the source tree is not a git clone (no `.git` at `REPO_ROOT`). This is to accommodate setups that run pytest from an extracted release tarball and prepare submodules in a separately-pointed tree via `GIT_PYTHON_TEST_GIT_REPO_BASE` (e.g. OpenIndiana's package build). In such setups, `git submodule update` cannot operate on the source tree, and the submodule paths checked here would never be populated there, but the test suite still works because `rorepo` points elsewhere. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0081133 commit 7b4e61e

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

test/test_fixture_health.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@
4545
),
4646
]
4747

48+
# Submodule working trees that must be present and initialized for the
49+
# test suite to operate normally: gitdb at `git/ext/gitdb`, and smmap
50+
# nested inside gitdb at `git/ext/gitdb/gitdb/ext/smmap`. The paths
51+
# below are anchored at REPO_ROOT (the GitPython source tree), not at
52+
# any rorepo redirection target.
53+
SUBMODULE_DIRS = [
54+
pytest.param(REPO_ROOT / "git" / "ext" / "gitdb", id="gitdb"),
55+
pytest.param(
56+
REPO_ROOT / "git" / "ext" / "gitdb" / "gitdb" / "ext" / "smmap",
57+
id="smmap",
58+
),
59+
]
60+
4861

4962
@pytest.mark.parametrize("fixture_dir", FIXTURE_DIRS)
5063
def test_fixture_dir_is_trusted_by_git(fixture_dir: Path) -> None:
@@ -89,3 +102,40 @@ def test_fixture_dir_is_trusted_by_git(fixture_dir: Path) -> None:
89102
"This usually means the directory is not an initialized git "
90103
"repository (its `.git` marker may be stale or pointing elsewhere)."
91104
)
105+
106+
107+
@pytest.mark.parametrize("submodule_dir", SUBMODULE_DIRS)
108+
def test_required_submodule_is_initialized(submodule_dir: Path) -> None:
109+
"""The submodule's working tree is present and initialized.
110+
111+
Failure means the source tree is a git clone but the submodule's
112+
working tree hasn't been populated. Skipped when the source tree
113+
itself isn't a git clone (e.g. an extracted release tarball), since
114+
``git submodule update`` cannot operate there; setups that handle
115+
submodules in a separately-prepared tree (via
116+
``GIT_PYTHON_TEST_GIT_REPO_BASE``) are exempted from this check.
117+
"""
118+
if not (REPO_ROOT / ".git").exists():
119+
pytest.skip(
120+
"Source tree is not a git clone (no .git in REPO_ROOT); submodules "
121+
"cannot be initialized via `git submodule update` here. Setups "
122+
"that prepare submodules in a separately-pointed tree (via "
123+
"GIT_PYTHON_TEST_GIT_REPO_BASE) are exempted from this check."
124+
)
125+
# The assertion messages below recommend `git submodule update --init
126+
# --recursive` rather than `init-tests-after-clone.sh`, even though the
127+
# latter is the documented entry point for first-time test setup. Two
128+
# reasons: the script performs `git reset --hard` operations that can
129+
# destroy local work, and #1713 showed the script itself can carry
130+
# submodule-init regressions, in which case recommending it would lead
131+
# developers in a circle. The direct git command is a safe minimal fix
132+
# for this test's specific failure mode and bypasses any such regression.
133+
assert submodule_dir.is_dir(), (
134+
f"Submodule working tree missing: {submodule_dir}.\n"
135+
"Run `git submodule update --init --recursive` from the repo root."
136+
)
137+
assert (submodule_dir / ".git").exists(), (
138+
f"Submodule directory exists but has no .git marker: {submodule_dir}.\n"
139+
"The submodule hasn't been initialized. "
140+
"Run `git submodule update --init --recursive` from the repo root."
141+
)

0 commit comments

Comments
 (0)