| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 863bb76 commit 59af963
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -223,6 +223,11 @@ jobs: | |||
| 223 | 223 | ||
| 224 | 224 | - name: Test with pytest | |
| 225 | 225 | run: | | |
| 226 | + if [[ "$RUNNER_OS" == "Windows" && -z "${GIT_PYTHON_GIT_EXECUTABLE+x}" ]]; then | ||
| 227 | + # Absolute paths let Windows share minimum-version probes. | ||
| 228 | + git_executable="$(python -c 'import os, shutil; print(os.path.abspath(shutil.which("git")))')" | ||
| 229 | + export GIT_PYTHON_GIT_EXECUTABLE="$git_executable" | ||
| 230 | + fi | ||
| 226 | 231 | pytest --color=yes -p no:sugar --instafail -vv --durations=30 \ | |
| 227 | 232 | --junitxml=test-results/pytest.xml --backend-report=test-results/backend.json | |
| 228 | 233 | continue-on-error: false | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -53,6 +53,24 @@ The prepared environments in this checkout are `.venv` (CLI) and `.tox/gix` | |||
| 53 | 53 | --backend-report=.cache/gix-coverage.json | |
| 54 | 54 | ``` | |
| 55 | 55 | ||
| 56 | + On Windows, use Git Bash, as CI does, and the environments' `Scripts` | ||
| 57 | + directories. To retain CI's coverage and pytest options: | ||
| 58 | + | ||
| 59 | + ```sh | ||
| 60 | + .venv/Scripts/python.exe test/run-local.py --color=yes -p no:sugar --instafail -vv --durations=30 \ | ||
| 61 | + --junitxml=.cache/windows-cli.xml --backend-report=.cache/windows-cli.json | ||
| 62 | + .tox/gix/Scripts/python.exe test/run-local.py --color=yes -p no:sugar --instafail -vv --durations=30 \ | ||
| 63 | + --junitxml=.cache/windows-gix.xml --backend-report=.cache/windows-gix.json | ||
| 64 | + ``` | ||
| 65 | + | ||
| 66 | + The Windows runner resolves `git.exe` from `PATH` to an absolute path so | ||
| 67 | + GitPython can share minimum-version checks. An explicit | ||
| 68 | + `GIT_PYTHON_GIT_EXECUTABLE` override is preserved and also used for the runner's | ||
| 69 | + direct Git commands. Git Bash normally selects `mingw64/bin/git.exe`; the | ||
| 70 | + `cmd/git.exe` and `bin/git.exe` launchers add overhead to local measurements. | ||
| 71 | + The private config retains CI's `core.autocrlf=true` on Windows and appends | ||
| 72 | + the test aliases directly, matching CI without introducing config includes. | ||
| 73 | + | ||
| 56 | 74 | The runner uses local version tags, creates an isolated Git configuration, | |
| 57 | 75 | prepares the historical test fixture inside a temporary shared clone, gives | |
| 58 | 76 | pytest a separate temporary root for each run, and disables package-index | |
@@ -518,6 +536,35 @@ repository-open benchmark above measures the affected operation separately. | |||
| 518 | 536 | Logs, profiles, JUnit results and backend reports are retained locally under | |
| 519 | 537 | `.cache/ci-performance/`. | |
| 520 | 538 | ||
| 539 | + ### Submodule fixture process overhead on Windows | ||
| 540 | + | ||
| 541 | + Windows CI and the local runner now resolve `git.exe` from `PATH` to an | ||
| 542 | + absolute `GIT_PYTHON_GIT_EXECUTABLE` when no override was supplied. This enables | ||
| 543 | + the existing minimum-version cache without changing the library's executable | ||
| 544 | + lookup or cache invalidation. Submodule fixtures also pass `skip_hooks=True` | ||
| 545 | + when committing their test history; the library default and dedicated hook | ||
| 546 | + tests continue to run hooks. | ||
| 547 | + | ||
| 548 | + A serial Windows comparison on CPython 3.12.13, Git 2.55.0.windows.5 and | ||
| 549 | + GixPython 0.1.0 selected the Windows destination-name rejection tests, | ||
| 550 | + `test_update_no_fetch_restores_deinitialized_submodule`, and | ||
| 551 | + `test_update_no_fetch_is_recursive`. Both runs used the direct Git executable | ||
| 552 | + on `PATH`, CI's flat alias config and `core.autocrlf=true`, with profiling | ||
| 553 | + enabled and coverage disabled. All 37 cases passed in both runs. | ||
| 554 | + | ||
| 555 | + | Test invocation and fixtures | Pytest time | Git launches | Version probes | Hook launches | | ||
| 556 | + | --- | ---: | ---: | ---: | ---: | | ||
| 557 | + | `GIT_PYTHON_GIT_EXECUTABLE=git`, fixture hooks enabled | 87.10s | 1,437 | 403 | 177 | | ||
| 558 | + | Absolute executable, fixture hooks skipped | 77.20s | 1,128 | 271 | 0 | | ||
| 559 | + | ||
| 560 | + The 309 eliminated launches comprise 132 redundant version probes and three | ||
| 561 | + hook checks for each of 59 fixture commits. This sample was about 11% faster; | ||
| 562 | + it is not a full-suite speedup estimate. Git Bash CI already selects | ||
| 563 | + `mingw64/bin/git.exe` and appends the alias config directly, so correcting the | ||
| 564 | + local runner's launcher/config differences is not an additional CI gain. | ||
| 565 | + Logs, profiles, JUnit results and operation reports are retained locally under | ||
| 566 | + `.cache/test-cleanup/windows-submodule-{baseline,optimized}*`. | ||
| 567 | + | ||
| 521 | 568 | ### Test-suite setup measurements | |
| 522 | 569 | ||
| 523 | 570 | The fixture optimizations below are implemented as separate commits, each | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | 7 | import os | |
| 8 | 8 | from pathlib import Path | |
| 9 | + import shutil | ||
| 9 | 10 | import socket | |
| 10 | 11 | import subprocess | |
| 11 | 12 | import sys | |
@@ -18,7 +19,14 @@ def main(): | |||
| 18 | 19 | with TemporaryDirectory(prefix="gitpython-local-tests-") as directory: | |
| 19 | 20 | temporary = Path(directory) | |
| 20 | 21 | config = temporary / "gitconfig" | |
| 21 | - config.write_text("[user]\nname = GitPython Tests\nemail = tests@example.invalid\n", encoding="utf-8") | ||
| 22 | + text = "[user]\nname = GitPython Tests\nemail = tests@example.invalid\n" | ||
| 23 | + if sys.platform == "win32": | ||
| 24 | + # Match CI's Git for Windows setting despite disabling system config. | ||
| 25 | + text += "[core]\nautocrlf = true\n" | ||
| 26 | + # CI appends these aliases directly. An include forces Gix to reload its | ||
| 27 | + # configuration before every operation because included files can change. | ||
| 28 | + text += (root / "test/fixtures/.gitconfig").read_text(encoding="utf-8") | ||
| 29 | + config.write_text(text, encoding="utf-8") | ||
| 22 | 30 | env = { | |
| 23 | 31 | **os.environ, | |
| 24 | 32 | "GIT_CONFIG_NOSYSTEM": "1", | |
@@ -28,11 +36,17 @@ def main(): | |||
| 28 | 36 | "PIP_FIND_LINKS": os.environ.get("PIP_FIND_LINKS", str(root / ".cache/gix-wheels")), | |
| 29 | 37 | "UV_OFFLINE": "1", | |
| 30 | 38 | } | |
| 39 | + if sys.platform == "win32" and "GIT_PYTHON_GIT_EXECUTABLE" not in env: | ||
| 40 | + executable = shutil.which("git") | ||
| 41 | + if executable is None: | ||
| 42 | + raise RuntimeError("Git executable not found in PATH") | ||
| 43 | + # Windows can share minimum-version checks for an absolute path. | ||
| 44 | + env["GIT_PYTHON_GIT_EXECUTABLE"] = os.path.abspath(executable) | ||
| 45 | + git_executable = env.get("GIT_PYTHON_GIT_EXECUTABLE", "git") | ||
| 31 | 46 | ||
| 32 | 47 | def git(*args, cwd=root): | |
| 33 | - return subprocess.check_output(["git", *map(str, args)], cwd=cwd, env=env, text=True).strip() | ||
| 48 | + return subprocess.check_output([git_executable, *map(str, args)], cwd=cwd, env=env, text=True).strip() | ||
| 34 | 49 | ||
| 35 | - git("config", "--file", config, "include.path", root / "test/fixtures/.gitconfig") | ||
| 36 | 50 | fixture = temporary / "repo" | |
| 37 | 51 | git("clone", "--shared", "--no-checkout", root, fixture) | |
| 38 | 52 | git("checkout", "--detach", git("rev-parse", "HEAD"), cwd=fixture) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -198,8 +198,9 @@ def test_git_daemon_releases_port_and_can_restart(tmp_path): | |||
| 198 | 198 | with suppress(ConnectionResetError): # Git for Windows resets rejected requests. | |
| 199 | 199 | assert connection.recv(1) == b"" | |
| 200 | 200 | ||
| 201 | + # Windows can take just over two seconds to refuse a closed loopback port. | ||
| 201 | 202 | with pytest.raises(ConnectionRefusedError): | |
| 202 | - with socket.create_connection(address, timeout=2): | ||
| 203 | + with socket.create_connection(address, timeout=5): | ||
| 203 | 204 | pass | |
| 204 | 205 | ||
| 205 | 206 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments