feat(upgrade): add tiger upgrade self-update command#163
Conversation
64b1f3d to
6ebfc38
Compare
Port Ghost's upgrade command to Tiger CLI. `tiger upgrade` (alias `update`) downloads the latest release archive for the current platform from releases_url, verifies its SHA-256 checksum, extracts the `tiger` binary, and atomically replaces the running binary in place. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6ebfc38 to
56afd5c
Compare
Askir
left a comment
There was a problem hiding this comment.
Looks good to me!! Since you build a --version flag and also allow --force we could have an integration test I think, where you'd actually run this agains the live CDN in github actions? Not sure if worth it, but I guess breaking the upgrade command would be quite ugly since it impacts everyone so maybe it is.
| // Kick off a background check for a newer release so the network | ||
| // fetch overlaps with the command's actual work; the result is | ||
| // printed in PersistentPostRunE. Gated to interactive, non-CI | ||
| // terminals. `version --check` runs its own synchronous check. | ||
| isVersionCheckCmd := cmd.Name() == "version" && cmd.Flag("check") != nil && cmd.Flag("check").Changed | ||
| if cfg.VersionCheck && !skipUpdateCheck && !isVersionCheckCmd && | ||
| !util.IsCI() && util.IsTerminal(cmd.ErrOrStderr()) { | ||
| versionCheckCh = make(chan *version.CheckResult, 1) |
There was a problem hiding this comment.
I think these checks also pass during the tiger upgrade command which is probably a bit counter intuitive since it'll post that there is a new version available when upgrading? Or is there a gate somewhere that I am missing?
| if err := cmd.Flags().MarkHidden("version"); err != nil { | ||
| panic(err) | ||
| } | ||
| cmd.Flags().BoolVar(&force, "force", false, "reinstall even if the current version already matches, or the binary was installed via a package manager") |
There was a problem hiding this comment.
Is the "replace despite package manager used" truly intended? Do the package managers not trip over it if you change the binaries out underneath them? 😅 I guess its very niche probably a non-issue.
There was a problem hiding this comment.
By default, it is refused, with the right package-manager command shown instead. --force is a hidden escape hatch (it warns before proceeding), mainly for when the tap/repo lags behind a release or the install-method detection guesses wrong.
And the package managers don't trip over it: the next brew upgrade / apt install just overwrites our binary with its own copy, so the drift self-heals.
The whole mechanism is inspired by ghost's upgrade command, which gates package-manager installs the same way.
| } | ||
|
|
||
| if runtime.GOOS == "windows" { | ||
| cleanupStaleOldBinaries(currentBinaryPath) |
There was a problem hiding this comment.
This is only called here right? So we always keep the old one until the next upgrade? I guess that's not necessarily bad as a backup anyway. Just good to know.
There was a problem hiding this comment.
Right, and it's forced rather than chosen: this branch is Windows-only, and Windows locks a running executable, so the process can't delete its own .exe, only rename it. The earliest opportunity to remove the .old. file is a future invocation, which is what this call does. On Linux/macOS there's no leftover at all; the rename overwrites in place.
… test Address PR review feedback: - Skip the background version check when running `tiger upgrade` (and its `update` alias). The command does its own synchronous check, and the post-run hook would otherwise print "a new release is available" right after a successful upgrade, since the running process still reports the old version. - Add TestUpgradeLiveCDNIntegration: builds a dev binary, upgrades it in place via `tiger upgrade --version <latest> --force` against the live release CDN (real download, checksum verification, binary replacement), then verifies the replaced binary runs and reports the new version. Gated behind TIGER_UPGRADE_INTEGRATION so plain `go test ./...` stays offline; enabled in the CI test workflow so it runs on every PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`tiger upgrade --version <older>` previously printed "Upgrading tiger 0.20.5 → v0.20.4", which misdescribes the operation. Pick the verb by comparing the current and target versions, falling back to "Upgrading" when the current version is unparsable (e.g. dev builds). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
What
Adds a
tiger upgradeself-update command and reworks the update notifier to check on every invocation, reconciled so the notifier points users at the path that works for their install method.tiger upgrade: replaces the running binary with the latest release: checklatest.txt→ download the platform archive → verify SHA-256 → extract → atomic in-place swap.Breaking config change:
version_check_interval→version_check(bool, defaulttrue). A load-time migration preserves intent for existing configs (interval == 0stays disabled); explicitversion_check/TIGER_VERSION_CHECKwins.config set version_check_intervalnow errors.