From 71d64880d961028d37b6af6a3b639f00b22f9ba9 Mon Sep 17 00:00:00 2001 From: emozilla Date: Fri, 29 May 2026 00:11:14 -0400 Subject: [PATCH] fix(installer): pass --branch to hermes update in the --update flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The install is a detached-HEAD checkout of a pinned commit. Without --branch, 'hermes update' fell back to its default (main) and switched the checkout to main — a divergent branch that lacks the desktop CLI command — so the update targeted the wrong branch and the rebuild stage failed with 'invalid choice: desktop'. Thread BUILD_PIN_BRANCH (the branch this installer was built against, and the same branch the desktop detected the update on) into 'hermes update --branch ' so update + rebuild stay on-branch. --- .../src-tauri/src/update.rs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/bootstrap-installer/src-tauri/src/update.rs b/apps/bootstrap-installer/src-tauri/src/update.rs index 599b7d395f..b7f147020f 100644 --- a/apps/bootstrap-installer/src-tauri/src/update.rs +++ b/apps/bootstrap-installer/src-tauri/src/update.rs @@ -99,12 +99,27 @@ async fn run_update(app: AppHandle) -> Result<()> { wait_for_venv_free(&install_root, &app).await; // ---- stage 1: hermes update ----------------------------------------- + // Pass --branch so `hermes update` targets the branch this installer was + // built/pinned against (BUILD_PIN_BRANCH), NOT its built-in default of + // `main`. The install was a detached-HEAD checkout of a specific commit; + // without --branch, `hermes update` switches the checkout to `main` (a + // divergent branch that may not even have the desktop CLI command), then + // reports "already up to date" against the wrong branch. The desktop + // detected the update against this same branch, so we must update against + // it too. + let pin_branch = option_env_string("BUILD_PIN_BRANCH"); + let mut update_args: Vec<&str> = vec!["update", "--yes", "--gateway"]; + if let Some(b) = pin_branch.as_deref() { + update_args.push("--branch"); + update_args.push(b); + } + emit_stage(&app, "update", StageState::Running, None, None); let started = Instant::now(); let update = run_streamed( &app, &hermes, - &["update", "--yes", "--gateway"], + &update_args, &install_root, Some("update"), ) @@ -376,6 +391,18 @@ fn stage_info(name: &str, title: &str) -> StageInfo { } } +// option_env! only accepts string literals, so the build-time pins are read +// by their literal names here. Mirrors bootstrap.rs's helper of the same name +// (kept local rather than shared because option_env! can't be parameterized). +fn option_env_string(key: &str) -> Option { + let val = match key { + "BUILD_PIN_COMMIT" => option_env!("BUILD_PIN_COMMIT"), + "BUILD_PIN_BRANCH" => option_env!("BUILD_PIN_BRANCH"), + _ => None, + }; + val.map(|s| s.to_string()) +} + fn emit(app: &AppHandle, event: BootstrapEvent) { if let Err(e) = app.emit(BootstrapEvent::CHANNEL, &event) { tracing::warn!(?e, "failed to emit update event");