Skip to content

chore(self-update): clearer Windows hint, surface xattr failures#23

Merged
epodivilov merged 2 commits into
mainfrom
chore/self-update-windows-error
Jun 20, 2026
Merged

chore(self-update): clearer Windows hint, surface xattr failures#23
epodivilov merged 2 commits into
mainfrom
chore/self-update-windows-error

Conversation

@epodivilov

Copy link
Copy Markdown
Owner

What

  • detectBinaryName now branches on win32 before falling through to the generic "Unsupported platform" error, returning "Windows is not supported by self-update; reinstall via install.ps1". The previous message gave Windows users no clue that the install script supports their platform.
  • macOS quarantine removal is extracted into a small tryRemoveMacosQuarantine(targetPath, deps) helper. Failures (missing xattr, non-zero exit, thrown error) now surface as ui.warn(...) instead of being silently swallowed. The update itself still succeeds — quarantine removal is best-effort.

Why

Bun.spawnSync(["xattr", ...]) previously returned a result that was ignored entirely (no exit-code check), and the try/catch only caught throws. On a system without xattr, or when the attribute is missing, the user got no feedback at all — and no hint about why Gatekeeper might keep blocking the new binary.

For Windows the generic "Unsupported platform: win32/..." was actively misleading: install.ps1 ships exactly this CLI, but nothing in the error pointed there.

Design

  • detectBinaryName(platform, arch) now takes its inputs as parameters instead of reading process.* inline. The CLI caller passes process.platform / process.arch; tests pass strings. Pure function, deterministic.
  • A new injected dep QuarantineRemover = (path: string) => Result<void> lets downloadBinary accept either the real Bun.spawnSync based remover (defaultQuarantineRemover) or a fake in tests. downloadBinary also takes platform and a warn callback in its deps bag, so neither process.platform nor ui is referenced inside.
  • The composition root in selfUpdateCommand wires defaultQuarantineRemover and ui.warn. No container change needed — the dep is local to this command.

Tests

src/cli/commands/self-update.test.ts covers:

  • detectBinaryName("win32", "x64") returns the Windows-specific message; it is not the generic fallback.
  • detectBinaryName("freebsd", "x64") and detectBinaryName("linux", "ia32") keep the generic Unsupported platform: … message.
  • detectBinaryName("darwin", "arm64") / ("linux", "x64") succeed with the expected binary names.
  • tryRemoveMacosQuarantine does not warn on success and does warn (without throwing) on failure, surfacing the underlying error and the manual fix command.

Checks

pnpm typecheck && pnpm lint && pnpm test — all green locally (502 pass, 0 fail).

Closes Vikunja #43 (id 215)

Detect Windows in detectBinaryName and return a message that points
users at install.ps1 instead of the generic "Unsupported platform"
fallback, which gives no clue that Windows is actually supported via
the install script.

Extract the macOS quarantine removal into a small, injectable helper.
The previous implementation swallowed every failure silently, leaving
the user without any feedback when xattr was missing or errored — and
without any hint why Gatekeeper might still block the new binary.
Failures now surface as ui.warn() without failing the update, since
quarantine removal is best-effort.

Add unit tests for the Windows branch, the generic fallback, and the
quarantine warn-on-failure path.
- tryRemoveMacosQuarantine now try/catches the injected remover so a
  buggy or future remover that throws synchronously still degrades to
  a warning instead of failing the update, matching the documented
  best-effort contract.
- Add positive test for detectBinaryName("darwin", "x64") — previously
  only darwin/arm64 and linux/x64 had positive assertions.
- Replace misleading "non-Error" test (which actually passed an Error)
  with two tests that genuinely exercise the synchronous-throw path:
  one with a thrown Error, one with a thrown non-Error primitive.
@epodivilov epodivilov merged commit 673cfa0 into main Jun 20, 2026
1 check passed
@epodivilov epodivilov deleted the chore/self-update-windows-error branch June 20, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant