From 4ab3aa0c6afffe8fb0370e975a9890d6618c88e5 Mon Sep 17 00:00:00 2001 From: ethernet Date: Thu, 24 Sep 2026 05:47:08 -0400 Subject: [PATCH] fix(desktop): restore PM-pinned Git for Windows product builds --- hermes_cli/main_desktop.py | 6 +++ .../test_desktop_build_git_windows.py | 37 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/hermes_cli/test_desktop_build_git_windows.py diff --git a/hermes_cli/main_desktop.py b/hermes_cli/main_desktop.py index 52e32a1c14..d9a2cb9a50 100644 --- a/hermes_cli/main_desktop.py +++ b/hermes_cli/main_desktop.py @@ -1202,6 +1202,12 @@ def build_prepared_desktop(desktop_dir: Path, *, source_mode: bool, npm: str, en build_label = "source build" if source_mode else "packaged app" print(f"→ Building desktop {build_label}...") build_env = dict(env) + if sys.platform == "win32": + # The installer stages pinned Git in its own PowerShell process. Product + # builds run later, often with every system git removed from PATH; the + # desktop stamp must still resolve this checkout's real HEAD. + import pm + build_env = pm.ensure("git", base_env=build_env).env if _force_adhoc_macos_signing(build_env, source_mode=source_mode): print(" → No Developer ID configured; ad-hoc signing this local rebuild " "(CSC_IDENTITY_AUTO_DISCOVERY=false)") diff --git a/tests/hermes_cli/test_desktop_build_git_windows.py b/tests/hermes_cli/test_desktop_build_git_windows.py new file mode 100644 index 0000000000..e4c6096ecc --- /dev/null +++ b/tests/hermes_cli/test_desktop_build_git_windows.py @@ -0,0 +1,37 @@ +"""The installer stage and later desktop product build are separate processes.""" +from __future__ import annotations + +from pathlib import Path +from types import SimpleNamespace + +import pytest + + +@pytest.mark.platforms("windows") +def test_packaged_desktop_build_restores_pm_git_for_stamp_and_pack( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch, +) -> None: + import pm + from hermes_cli import main_desktop + + desktop = tmp_path / "apps" / "desktop" + desktop.mkdir(parents=True) + original = {"PATH": "C:\\without-git", "HERMES_HOME": str(tmp_path)} + calls: list[tuple[list[str], dict[str, str]]] = [] + + def installed_git(*names: str, base_env: dict[str, str]) -> dict[str, str]: + assert names == ("git",) + assert base_env == original + return {**base_env, "PATH": "C:\\pm-pinned-git\\cmd;" + base_env["PATH"]} + + def run(command: list[str], *, env: dict[str, str], **_kwargs: object) -> None: + calls.append((command, env)) + + monkeypatch.setattr(pm, "ensure", lambda *names, base_env: SimpleNamespace(env=installed_git(*names, base_env=base_env))) + monkeypatch.setattr(main_desktop.subprocess, "run", run) + monkeypatch.setattr(main_desktop, "_promote_staged_desktop_app", lambda *_args: desktop / "Hermes.exe") + main_desktop.build_prepared_desktop(desktop, source_mode=False, npm="C:\\node\\npm.cmd", env=original) + + assert [command[2] for command, _ in calls] == ["build", "builder"] + assert all(env["PATH"].startswith("C:\\pm-pinned-git\\cmd;") for _, env in calls) + assert original["PATH"] == "C:\\without-git"