fix: synchronize the engine submodule URL before updating
build / mod (push) Failing after 18s

Reproduce stale upstream configuration with real local Git repositories, including the already-matching pin fast path.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
2026-11-03 00:18:41 +03:00
parent e70d7a667b
commit d3378b37a2
2 changed files with 72 additions and 4 deletions
+9 -4
View File
@@ -73,13 +73,12 @@ def engine_identity() -> str:
def fork():
"""Initialize the exact gitlink; never replace a modified developer checkout."""
expected = engine_commit()
matched = False
if (FORK / ".git").exists():
current = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=FORK, text=True).strip()
if current == expected:
print(f"horizon/: закреплённый коммит {expected}")
return
matched = current == expected
dirty = subprocess.check_output(["git", "status", "--porcelain"], cwd=FORK, text=True).strip()
if dirty:
if not matched and dirty:
sys.exit("horizon/: есть изменения при другом закреплённом SHA; сохраните их перед обновлением сабмодуля")
if (FORK / ".git").is_dir():
# Migrate the old standalone clone without deleting it or any local branches.
@@ -88,6 +87,12 @@ def fork():
run(["git", "remote", "set-url", "origin", url], cwd=FORK)
elif FORK.exists() and any(FORK.iterdir()):
sys.exit("horizon/: непустой каталог без Git; сохраните его перед инициализацией сабмодуля")
# Existing clones cache the previous upstream URL in local Git configuration.
# Synchronize even when HEAD already matches: the next pin may exist only in our fork.
run(["git", "submodule", "sync", "--recursive", "--", "horizon"], cwd=ROOT)
if matched:
print(f"horizon/: закреплённый коммит {expected}")
return
run(["git", "submodule", "update", "--init", "--recursive", "--", "horizon"], cwd=ROOT)
current = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=FORK, text=True).strip()
if current != expected:
+63
View File
@@ -0,0 +1,63 @@
"""Real Git migration regression; no network, user settings or player data."""
import importlib.util
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
from unittest.mock import patch
SPEC = importlib.util.spec_from_file_location("airdef_build", Path(__file__).with_name("airdef.py"))
airdef = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(airdef)
def git(at, *args):
return subprocess.check_output(["git", "-C", str(at), *args], text=True, stderr=subprocess.STDOUT).strip()
def init(at):
at.mkdir()
git(at, "init", "-q")
git(at, "config", "user.name", "Test")
git(at, "config", "user.email", "test@example.invalid")
def commit(at, text):
(at / "engine.txt").write_text(text)
git(at, "add", "engine.txt")
git(at, "commit", "-qm", text)
return git(at, "rev-parse", "HEAD")
class ForkMigrationTests(unittest.TestCase):
def test_stale_local_url_is_synced_before_fetching_new_pin(self):
with tempfile.TemporaryDirectory(prefix="airdef-fork-test-") as tmp, patch.dict(os.environ, {"GIT_ALLOW_PROTOCOL": "file"}):
root = Path(tmp)
source, parent = root / "source", root / "airdef"
init(source)
old = commit(source, "old")
canonical = root / "canonical.git"
git(root, "clone", "--bare", str(source), str(canonical))
init(parent)
git(parent, "submodule", "add", str(canonical), "horizon")
child = parent / "horizon"
new = commit(source, "new-fork-only-pin")
git(source, "push", str(canonical), "HEAD")
git(parent, "update-index", "--cacheinfo", f"160000,{new},horizon")
stale = str(root / "missing-upstream.git")
git(parent, "config", "submodule.horizon.url", stale)
git(child, "remote", "set-url", "origin", stale)
self.assertEqual(git(child, "rev-parse", "HEAD"), old)
with patch.object(airdef, "ROOT", parent), patch.object(airdef, "FORK", child):
airdef.fork()
self.assertEqual(git(child, "rev-parse", "HEAD"), new)
self.assertEqual(git(child, "remote", "get-url", "origin"), str(canonical))
# The fast path must also repair stale configuration for the next update.
git(child, "remote", "set-url", "origin", stale)
airdef.fork()
self.assertEqual(git(child, "remote", "get-url", "origin"), str(canonical))
if __name__ == "__main__":
unittest.main()