feat: add zemo upgrade command#12
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a self-updater that downloads the latest release from GitHub and replaces the running binary in place. Closes the user-experience gap with similar single-binary CLIs (
deno upgrade,bun upgrade,rustup self update) and removes the need to re-run the README curl one-liner.This PR also bumps the version to 0.3.0, intended to be tagged immediately after merge.
Supported targets
-Dtarget=x86_64-linux-gnu, so musl-built binaries refuse to upgrade rather than risk landing a glibc binary on Alpine/musl-only systems.zemo upgrade#11 — needs zip extraction and the running-.exeself-replacement workaround.zemo upgradeon Windows fails fast withUnsupportedTargetinstead of confusing gzip errors.Related issue
Closes #10. Windows support tracked in #11.
Changes
Command.upgrade: upgrade.UpgradeModevariant incli.zig; routed fromparseArgsand dispatched inrun.zemo upgrade(download + replace) andzemo upgrade --check(version compare only, no filesystem changes).src/upgrade.zigmodule with helpers split by responsibility:assetName,binaryBasename,compareVersions,findAssetUrl,parseReleaseJson.fetchLatestReleaseJson,downloadToMemory,extractZemoBinary,installPath,replaceBinary.assetNameis intentionally strict: only emits an asset name for targets whose released artifact matches the local ABI. Linux is gated onbuiltin.abi == .gnu; Windows always returnsUnsupportedTargetfor now.std.http.Client) with proper User-Agent (zemo/0.3.0 (+https://github.com/hidetzu/zemo)) andAccept: */*headers — tighter UA strings get rejected by GitHub Releases CDN.std.compress.flate.Decompress(gzip) +std.tar.Iterator.<install_path>.newwith mode 0o755, thenrenameAbsoluteover the running binary.VERSIONconstant updated from0.2.0to0.3.0.Testing
zig build testpasses locally (host is Linux musl; affectedassetNametest correctly skips and the newassetName: rejects musl Linuxtest exercises the negative path)x86_64-linux-gnu,x86_64-linux-musl,x86_64-macos,aarch64-macos,x86_64-windowsall build greenzemo upgrade --checkagainst the live GitHub API correctly reportsAlready up to date (v0.3.0)after self-bump (andNewer version available: ...when VERSION is artificially lowered)zemo upgradeend-to-end: temporarily lowered VERSION to0.0.1, ran/tmp/zemo-test upgrade, observedDownloading zemo-x86_64-linux-gnu.tar.gz...andUpgraded v0.0.1 -> v0.2.0./tmp/zemo-test --versionthen reportedzemo 0.2.0, confirming the binary was replaced.New tests added (in
upgrade.zig):assetName: returns asset for current target— runs only onlinux + x86_64 + gnu,macos + (x86_64|aarch64); skips otherwise so cross-target test runs stay green.assetName: rejects musl Linux to avoid replacing musl with glibc binary— explicit negative test.assetName: rejects Windows until #11 lands zip extraction— explicit negative test.compareVersions: equal / older / newer / handles \v` prefix / invalid input` — five cases covering the comparison enum.parseReleaseJson: extracts tag_name and assets(with deliberately-included unknown fields to validateignore_unknown_fields) andparseReleaseJson: invalid JSON returns error.findAssetUrl: returns URL when asset name matchesandfindAssetUrl: returns null when not found.installPath: returns absolute non-empty path.parseArgstests covering both upgrade modes plus invalid-arg paths.HTTP / archive / replacement paths are intentionally untested at the unit level (mirrors the project convention from
fetchLatestReleaseJson/git.isGitRepostyle); validated via the manual smoke test above.Notes for reviewers
zemo-upgradeUA worked forapi.github.combut produced HTTP 400 fromreleases/download/...(which redirects toobjects.githubusercontent.com). Switching to the proper<product>/<version> (+<url>)form fixed it.fetchLatestReleaseJsonstill useszemo-upgradefor now — could be unified in a follow-up but isn't strictly necessary.replaceBinaryuses@enumFromInt(0o755)to construct an executablestd.Io.File.Permissions. For Windows thePermissionsshape is different, which is why Windows support is deferred (feat: add Windows support tozemo upgrade#11).std.fs.path.basename, which lets us ignore the platform-specific top-level directory inside the tarball (zemo-x86_64-linux-gnu/zemoetc.).downloadToMemoryandextractZemoBinaryboth keep buffers in memory rather than streaming to disk. Acceptable for the current binary size; can revisit if releases grow.git checkout main && git pull && git tag v0.3.0 && git push origin v0.3.0.