fix(desktop): diagnose esbuild ignore-scripts build failures
When a desktop build fails because esbuild's platform binary (@esbuild/<platform>) was never staged - typically because ignore-scripts=true skips esbuild's postinstall - print an actionable diagnosis with the fix instead of leaving only the raw build error. Fixes #53082
This commit is contained in:
@@ -1228,6 +1228,22 @@ def _promote_staged_desktop_app(
|
||||
return packaged_executable
|
||||
|
||||
|
||||
def _diagnose_esbuild_ignore_scripts(output: Optional[str]) -> None:
|
||||
"""Print an actionable hint when a desktop build failed because esbuild's platform
|
||||
binary was never staged (`ignore-scripts=true` skips esbuild's postinstall, so the
|
||||
``@esbuild/<platform>`` optional dependency is absent) — #53082. Best-effort: only
|
||||
adds context, never masks the original error."""
|
||||
text = output or ""
|
||||
if not ("@esbuild/" in text and "could not be found" in text) and "ignore-scripts" not in text:
|
||||
return
|
||||
print(" ⚠ This looks like esbuild's native binary is missing — commonly caused by")
|
||||
print(" `ignore-scripts=true` in your npm config, which skips esbuild's postinstall")
|
||||
print(" that stages the @esbuild/<platform> package.")
|
||||
print(" Fix: run `npm config get ignore-scripts` — if true, either set it to false")
|
||||
print(" (`npm config set ignore-scripts false`), then reinstall: `npm ci` in the repo root,")
|
||||
print(" or stage the binary directly: `node node_modules/esbuild/install.js` in apps/desktop.")
|
||||
|
||||
|
||||
def build_prepared_desktop(desktop_dir: Path, *, source_mode: bool, npm: str, env: dict,
|
||||
icons: Path | None = None) -> Optional[Path]:
|
||||
"""Build prepared desktop sources, then publish the verified staged app."""
|
||||
@@ -1264,6 +1280,9 @@ def build_prepared_desktop(desktop_dir: Path, *, source_mode: bool, npm: str, en
|
||||
_promote_staged_desktop_app(desktop_dir, staging_dir) if staging_dir is not None else None
|
||||
)
|
||||
return packaged_executable
|
||||
except subprocess.CalledProcessError as exc:
|
||||
_diagnose_esbuild_ignore_scripts(exc.output)
|
||||
raise
|
||||
finally:
|
||||
if staging_dir is not None:
|
||||
_discard_desktop_staging(staging_dir)
|
||||
|
||||
33
tests/hermes_cli/test_desktop_esbuild_ignore_scripts.py
Normal file
33
tests/hermes_cli/test_desktop_esbuild_ignore_scripts.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""Regression tests for the esbuild / ignore-scripts build-failure diagnosis (#53082)."""
|
||||
|
||||
import io
|
||||
import contextlib
|
||||
|
||||
from hermes_cli.main_desktop import _diagnose_esbuild_ignore_scripts
|
||||
|
||||
|
||||
def _hintprinted(output: str | None) -> bool:
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
_diagnose_esbuild_ignore_scripts(output)
|
||||
return "esbuild" in buf.getvalue()
|
||||
|
||||
|
||||
def test_diagnose_triggers_on_missing_esbuild_binary() -> None:
|
||||
output = (
|
||||
"Error: The package \"@esbuild/darwin-arm64\" could not be found, "
|
||||
"and is needed by esbuild."
|
||||
)
|
||||
assert _hintprinted(output)
|
||||
|
||||
|
||||
def test_diagnose_triggers_on_ignore_scripts_mention() -> None:
|
||||
assert _hintprinted("npm error code ERESOLVE\nnpm warn config ignore-scripts=true")
|
||||
|
||||
|
||||
def test_diagnose_silent_on_unrelated_failure() -> None:
|
||||
assert not _hintprinted("vite build failed: unexpected token in index.html")
|
||||
|
||||
|
||||
def test_diagnose_silent_on_none_output() -> None:
|
||||
assert not _hintprinted(None)
|
||||
Reference in New Issue
Block a user