FJ-27: Add fj version update to self-replace the binary; split version into show/check/update #34
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/version-update-subcommands-FJ-27"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Resolves FJ-27.
Summary
Splits
fj versioninto ashow/check/updatesubcommand group matching the referenceytCLI, and adds a self-replacingupdatethat downloads the newest build for the running binary's train and platform, verifies its SHA256, and atomically swaps the running executable.Changes
VersionCommandbecomes a wrapper struct holding an optionalVersionSubcommand(Showalways available;Check/Updategated behind the existingupdate-checkfeature), following theRelease/Tag/Useridiom. Barefj versionstill defaults toshowwith the banner,--verbose, and--jsonunchanged.--checkflag is removed in favor offj version check, preserving the up-to-date / behind / ahead / latest-behind output and--json.--trainworks on bothcheckandupdate. The check logic now returns typedReleaseStatus/LatestStatussocheckandupdateshare it.fj version update: resolves the active train (bakedFJ_TRAIN, overridable by--train), runs the check, and prints "already current" and exits 0 without touching the binary when up to date. When behind it downloads the platform artifact (fj-linux-x86_64/fj-windows-x86_64.exevialatest_arch()) from the Generic Packages registry, verifies SHA256 against the registry digest, then replaces the running binary viaself-replace, reporting old -> new.forgejo_apiclient'slist_package_files(anonymous, like the existing release check). No manifest changes and no CI changes were needed. Both trains download from the version-pinned path.../generic/forgejo-cli/{version}/{file}(the release binary is published to packages, not as a Release asset).self-replaceis added as an optional dep wired intoupdate-check; a plaincargo buildpulls in neither it nor the new code. All download/replace logic stays in thefjbinary crate, sofj-core/fj-clientgain no deps.msg-version-update-*Fluent IDs (downloading, verifying, replaced, already_current, checksum_mismatch, permission_denied) added to all locales; the update-check hint now points atfj version check.Verification
cargo build(feature off) andcargo build --features update-checkboth pass.cargo fmt --check,cargo clippy --all-targets(both feature configs), andcargo test(both configs) all pass.cargo tree -p fj-client -p fj-core -e normal | grep -E 'clap|crossterm|fluent'returns nothing;fj-coregains noself-replace.fj version --helplistsshow/check/update;fj version update --helpshows--train; barefj versionprints the banner plus thefj version checkhint;fj version --jsonemits the banner JSON.fj version --helplists onlyshow; barefj versionprints the banner with no update hint.Note on the YouTrack trailer
The commit uses a bare
#FJ-27reference (no inlineState Donecommand) per the repo's documented policy: YouTrack applies VCS commit commands on push, not on merge, so aState Donecommand would transition the issue prematurely when the branch is pushed. State changes are made via the YouTrack MCP/board instead.Bring `fj version` in line with the reference `yt` CLI by converting the flat `VersionCommand` flag struct into a subcommand group (`show`, `check`, `update`) via the same wrapper-struct idiom as `Release`/`Tag`/`User`. Bare `fj version` still defaults to `show`, keeping the banner, `--verbose`, and `--json` output unchanged. The `--check` flag is removed; `fj version check` replaces it and preserves the existing up-to-date / behind / ahead / latest-behind messages and `--train` override. `show`, `check`, and `update` share the train-resolution and check logic, which now returns typed `ReleaseStatus`/`LatestStatus` values instead of printing inline. `fj version update` resolves the active train (baked `FJ_TRAIN`, overridable by `--train`), runs the check, and exits 0 with an "already current" message when up to date without touching the binary. When behind, it downloads the platform artifact for the running binary's train and target (`fj-linux-x86_64` / `fj-windows-x86_64.exe` via `latest_arch()`) from the Generic Packages registry, verifies its SHA256 against the registry digest, then atomically swaps the running executable with `self-replace`. The release binary lives at the version-pinned Generic Packages path (the create-release workflow makes a tagless Release entry; the binary is published to packages), so both trains download from `.../generic/forgejo-cli/{version}/{file}`. Forgejo computes a sha256 for every package file, fetched via the `forgejo_api` client's `list_package_files` (anonymous, like the existing release check) - no new manifest fields or CI changes. On a checksum mismatch, permission error, or download failure the staged temp file is discarded and the running binary is left unchanged. `self-replace` is added as an optional dep wired into the `update-check` feature; a plain `cargo build` pulls in neither it nor any of the new check/update code. All download/replace logic stays in the `fj` binary crate, so `fj-core`/`fj-client` gain no deps and the MCP-reuse grep still returns nothing. New `msg-version-update-*` Fluent IDs (downloading, verifying, replaced, already_current, checksum_mismatch, permission_denied) are added to all locales, and the update-check hint now points at `fj version check`. #FJ-27 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>