Skip to content

refactor: migrate self-update to the update-rs crate#1885

Merged
notheotherben merged 4 commits into
mainfrom
feature/update-rs-migration
Jun 21, 2026
Merged

refactor: migrate self-update to the update-rs crate#1885
notheotherben merged 4 commits into
mainfrom
feature/update-rs-migration

Conversation

@notheotherben

@notheotherben notheotherben commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

Replaces the hand-rolled src/update/ self-update module with the external update-rs crate (0.4.0) — which was extracted from this project. The ~1,400-line module collapses to a small src/update.rs plus the dependency, with no change to the gt update UX or the Go-style release asset naming, and keeping Git-Tool's original update --state relaunch convention.

What changed

  • Cargo.tomlupdate-rs = { version = "0.4", features = ["opentelemetry"] }. The shared human-errors 0.2.3, opentelemetry 0.32 and tracing-opentelemetry 0.33 all unify to single versions with the existing tracing-batteries stack, so update_rs::Error is our engine::Error (no conversion) and the global trace propagator is shared across the three update processes.
  • src/update.rsmanager() builds a GitHubSource for SierraSoftworks/git-tool (naming::go("git-tool")git-tool-<os>-<arch>[.exe], v tag prefix) and installs a GitToolLauncher that relaunches via gt update --state <json> (overriding update-rs's resume_args).
  • commands/update.rs — the hidden --state arg drives resume (resume_from_arg); list/select/rollback go through the crate's Release/get_variant. The --list formatting is a pure format_release_list helper, and resume is covered by a network-free test (resume failures bubble up without the command reporting to Sentry).
  • main.rs — no argv scanning. --update-resume-internal is kept as a tolerated hidden global so clap still accepts relaunches emitted by currently-installed releases (--update-resume-internal <s> --trace-context <c> update --state <s>); the update --state sub-command drives the resume.
  • commands/open.rs — the passive "update available" check uses the new manager.

Telemetry & trace continuity

Trace-context propagation across the three update phases is handled natively by update-rs (the context rides inside the serialized update state), so no --trace-context argument is needed on the relaunch. update-rs emits its own #[instrument] spans for the update (its opentelemetry feature), which flow into the existing tracing → Honeycomb pipeline. The previous test-only GITHUB_TOKEN injection is no longer needed: production was already unauthenticated (no regression), and the update path's only mandatory-network test is now a pure unit test.

Verification

  • cargo test --features pure-tests → 226 passed, 27 ignored; the new resume test and the list-formatting test are network-free.
  • commands::open::tests::run (live update check) passes and correctly reports the latest release.
  • gt update --list against real GitHub lists releases with correct markers.
  • Relaunch handling smoke-tested both ways: gt update --state '{"phase":"no-update"}' exits 0, and the legacy --update-resume-internal <s> --trace-context <c> update --state <s> form (what installed v3.11 binaries emit) is tolerated and resumes via the sub-command — so in-flight cross-version updates keep working.
  • cargo fmt --check clean; no new clippy warnings.

Recommended before release: a manual end-to-end three-phase update on each OS (e.g. gt update v3.11.0 to roll back, then gt update to roll forward) to exercise download → replace → cleanup and confirm no UAC prompt on Windows.

🤖 Generated with Claude Code

Replace the hand-rolled `src/update/` module (the three-phase
download/replace/relaunch state machine, GitHub source, retrying filesystem
and process launcher) with the external `update-rs` crate, which was extracted
from this project. The whole module becomes a 22-line `src/update.rs` that just
configures the updater for Git-Tool's releases.

- Cargo.toml: depend on `update-rs` 0.3 with the `opentelemetry` feature. The
  shared `human-errors`, `opentelemetry` and `tracing-opentelemetry` versions
  unify with the existing telemetry stack, so `update_rs::Error` is our
  `engine::Error` (no conversion) and the global trace propagator is shared
  across the three update processes.
- src/update.rs: `manager()` builds a `GitHubSource` for
  `SierraSoftworks/git-tool` using the Go-style `git-tool-<os>-<arch>[.exe]`
  asset naming (`naming::go`) and the `v` tag prefix — unchanged from before.
- main.rs: detect the resume flag by scanning argv at the top of `host()`
  (before clap) and hand off to `resume_from_arg`. This stays compatible with
  older binaries that relaunch with a trailing `update --state` sub-command,
  and lets the updater continue the distributed trace carried in the state.
  Removes the legacy rewrite branch and the `--update-resume-internal` arg.
- commands/update.rs: drop the internal `--state` flag (resume now lives in
  main); select/install via the crate's `Release`/`get_variant`. The
  `--list` formatting moves to a pure `format_release_list` helper with a
  network-independent unit test (replacing the old live-GitHub test).
- commands/open.rs: the passive update check uses the new manager.

Trace-context propagation across the update phases is now handled natively by
update-rs (inside the serialized state), so the bespoke `--trace-context`
relaunch wiring is gone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.89474% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.07%. Comparing base (3ae3187) to head (ee6f087).

Files with missing lines Patch % Lines
src/commands/update.rs 85.71% 7 Missing ⚠️
src/engine/http.rs 80.00% 3 Missing ⚠️
src/update.rs 70.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1885      +/-   ##
==========================================
+ Coverage   89.66%   90.07%   +0.40%     
==========================================
  Files         107      102       -5     
  Lines        9307     8653     -654     
==========================================
- Hits         8345     7794     -551     
+ Misses        962      859     -103     
Files with missing lines Coverage Δ
src/commands/open.rs 95.12% <100.00%> (-0.12%) ⬇️
src/main.rs 42.46% <100.00%> (+2.20%) ⬆️
src/engine/http.rs 85.96% <80.00%> (-0.40%) ⬇️
src/update.rs 70.00% <70.00%> (ø)
src/commands/update.rs 89.69% <85.71%> (+4.63%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Adopt update-rs 0.4's customizable launcher to restore Git-Tool's original
relaunch convention: a `GitToolLauncher` (overriding `resume_args`) relaunches
the binary as `gt update --state <json>` rather than with the library's default
`--update-resume-internal` flag. This keeps resume handling in the `update`
command (parsed by clap, and unit-testable) instead of an argv pre-scan in
`main`.

- Cargo.toml: update-rs 0.3 -> 0.4.
- src/update.rs: install `GitToolLauncher` on the manager.
- commands/update.rs: re-add the hidden `--state` arg; `run` resumes from it via
  `resume_from_arg`. Add a (network-free) test that resume failures bubble up
  without being reported to Sentry by the command.
- main.rs: drop the argv pre-scan; keep `--update-resume-internal` as a tolerated
  hidden global so clap still accepts the relaunch emitted by currently-installed
  releases (which pass `--update-resume-internal <s> --trace-context <c>
  update --state <s>`) — the `update --state` sub-command drives the resume.

The trace context still rides inside the serialized state (update-rs's
`opentelemetry` feature), so the relaunch needs no `--trace-context` argument.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
notheotherben and others added 2 commits June 21, 2026 17:15
Now that update-rs 0.4.1 exposes `GitHubSource::with_client`, build a reqwest
client carrying Git-Tool's `User-Agent` (`Git-Tool/<version>`) and pass it to the
updater, so self-update requests are attributed to Git-Tool and pick up its
client configuration rather than update-rs's generic default client. `http_client`
is a single place to grow that configuration (proxy, timeouts, ...) later.

Bumps the dependency to update-rs 0.4.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Instead of the updater constructing its own reqwest client, hand it Git-Tool's
central one. `update::manager` now takes `&Core` and passes
`core.http_client().reqwest_client()` to update-rs, so self-update requests share
Git-Tool's client configuration and connection pool.

To make that possible the central `TrueHttpClient` now owns a single reqwest
client (built once, with a default `Git-Tool/<version>` User-Agent) rather than
creating one per request, and the `HttpClient` trait exposes it via
`reqwest_client()`. Call sites that set a per-request User-Agent (the GitHub
registry/service) still override the default, so their behaviour is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@notheotherben notheotherben merged commit f5dee87 into main Jun 21, 2026
11 of 12 checks passed
@notheotherben notheotherben deleted the feature/update-rs-migration branch June 21, 2026 18:17
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