fix(ota): make publish_update.py work one-shot on Windows git-bash

Publishing the OTA from Windows git-bash failed at the scp step (2026-06-02):
- git-bash (MSYS) rewrote the /root/... env path to 'C:/Program Files/Git/root/...'
  before Python saw it → upload targeted a bogus remote dir.
- scp local source 'C:\...\dist' is parsed as host 'C' (drive letter = host).

Fixes: default runtime 1.0→1.1 (active channel, app.json runtimeVersion=1.1); scp
source passed as '.' with cwd=DIST (no drive letter); MSYS_NO_PATHCONV=1 in subprocess
env; defensive un-mangle of a git-bash-converted VPS_BASE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jtrzupek 2026-06-02 09:56:34 +02:00
parent 4bc594cde3
commit 5896b58688

View file

@ -29,7 +29,7 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent ROOT = Path(__file__).resolve().parent.parent
MOBILE = ROOT / "mobile" MOBILE = ROOT / "mobile"
DIST = MOBILE / "dist" DIST = MOBILE / "dist"
RUNTIME_DEFAULT = "1.0" # == EXPO_RUNTIME_VERSION w APK (zweryfikowane emulatorem 2026-05-31: app akceptuje TYLKO runtime 1.0). RUNTIME_DEFAULT = "1.1" # == EXPO_RUNTIME_VERSION w APK (bump 1.0→1.1 2026-06; aktywny kanał + app.json runtimeVersion=1.1).
# Operator config — set in your shell / .env.local before running this script. # Operator config — set in your shell / .env.local before running this script.
# Defaults are placeholders intended to fail loudly if you forgot to configure. # Defaults are placeholders intended to fail loudly if you forgot to configure.
VPS = os.environ.get("GOON_VPS_SSH", "root@your-vps.example.com") VPS = os.environ.get("GOON_VPS_SSH", "root@your-vps.example.com")
@ -38,6 +38,12 @@ PUBLIC_BASE = os.environ.get(
"GOON_PUBLIC_UPDATES_URL", "https://your-vps.example.com:8443/expo-updates/asset" "GOON_PUBLIC_UPDATES_URL", "https://your-vps.example.com:8443/expo-updates/asset"
) )
# git-bash (MSYS) na Windows konwertuje POSIX-owe ścieżki w env (`/root/...`) na
# `C:/Program Files/Git/root/...` ZANIM python je zobaczy → upload trafiał w złą ścieżkę
# (bug 2026-06-02). Odkręcamy częsty przypadek. Alternatywnie: uruchom z MSYS_NO_PATHCONV=1.
if "/Git/root/" in VPS_BASE:
VPS_BASE = VPS_BASE[VPS_BASE.index("/Git") + len("/Git"):]
def sha256_b64url(data: bytes) -> str: def sha256_b64url(data: bytes) -> str:
"""SHA-256 -> base64url bez padding (Expo Updates wymaga tego formatu).""" """SHA-256 -> base64url bez padding (Expo Updates wymaga tego formatu)."""
@ -51,10 +57,12 @@ def run(cmd: list[str], cwd: Path | None = None) -> None:
# jest bezpieczniejsze (brak shell interpolation), ale my podajemy list[str] # jest bezpieczniejsze (brak shell interpolation), ale my podajemy list[str]
# więc i tak nie ma shell injection risk. # więc i tak nie ma shell injection risk.
shell = sys.platform == "win32" and cmd[0] in ("npx", "npm", "scp", "ssh") shell = sys.platform == "win32" and cmd[0] in ("npx", "npm", "scp", "ssh")
# MSYS_NO_PATHCONV=1 — blokuje konwersję `/root/...` argów ssh/scp przez git-bash sh.
env = {**os.environ, "MSYS_NO_PATHCONV": "1"}
if shell: if shell:
subprocess.run(" ".join(cmd), cwd=cwd, check=True, shell=True) subprocess.run(" ".join(cmd), cwd=cwd, check=True, shell=True, env=env)
else: else:
subprocess.run(cmd, cwd=cwd, check=True) subprocess.run(cmd, cwd=cwd, check=True, env=env)
def main() -> int: def main() -> int:
@ -148,7 +156,9 @@ def main() -> int:
remote_dir = f"{VPS_BASE}/{args.runtime}/{update_id}" remote_dir = f"{VPS_BASE}/{args.runtime}/{update_id}"
print(f"\nUpload -> {remote_dir}") print(f"\nUpload -> {remote_dir}")
run(["ssh", VPS, f"mkdir -p {remote_dir}"]) run(["ssh", VPS, f"mkdir -p {remote_dir}"])
run(["scp", "-r", f"{DIST}/.", f"{VPS}:{remote_dir}/"]) # Źródło jako "." z cwd=DIST — Windows scp traktuje `C:\...` jako `host:path`
# (litera dysku = host), więc nie podajemy ścieżki z literą dysku (bug 2026-06-02).
run(["scp", "-r", ".", f"{VPS}:{remote_dir}/"], cwd=DIST)
# current.json wskazuje na nowy update_id # current.json wskazuje na nowy update_id
current = { current = {
@ -160,9 +170,9 @@ def main() -> int:
current_local.write_text(json.dumps(current, indent=2), encoding="utf-8") current_local.write_text(json.dumps(current, indent=2), encoding="utf-8")
run([ run([
"scp", "scp",
str(current_local), "current.json",
f"{VPS}:{VPS_BASE}/{args.runtime}/current.json", f"{VPS}:{VPS_BASE}/{args.runtime}/current.json",
]) ], cwd=DIST)
print(f"\nOK Update {update_id} live na runtime {args.runtime}") print(f"\nOK Update {update_id} live na runtime {args.runtime}")
print(f" Klienci dostaną bundle przy następnym launchu (lub Updates.checkForUpdate()).") print(f" Klienci dostaną bundle przy następnym launchu (lub Updates.checkForUpdate()).")