(parentCtx context.Context, res updatepolicy.Result)
| 362 | } |
| 363 | |
| 364 | func handleOptionalUpdate(parentCtx context.Context, res updatepolicy.Result) { |
| 365 | binPath, _ := getCurrentBinaryPath() |
| 366 | if binPath != "" && autoupdate.IsPMManaged(binPath) { |
| 367 | pm := detectPackageManager(binPath) |
| 368 | switch pm { |
| 369 | case "homebrew": |
| 370 | fmt.Printf("⚠ Update available: %s → %s. For Homebrew, run 'brew update' and then 'brew upgrade tnr'.\n", |
| 371 | displayVersion(res.CurrentVersion), displayVersion(res.LatestVersion)) |
| 372 | case "scoop": |
| 373 | fmt.Printf("⚠ Update available: %s → %s. For Scoop, run 'scoop update tnr'.\n", |
| 374 | displayVersion(res.CurrentVersion), displayVersion(res.LatestVersion)) |
| 375 | case "winget": |
| 376 | fmt.Printf("⚠ Update available: %s → %s. For Windows Package Manager, run 'winget upgrade Thunder.tnr'.\n", |
| 377 | displayVersion(res.CurrentVersion), displayVersion(res.LatestVersion)) |
| 378 | default: |
| 379 | fmt.Printf("⚠ Update available: %s → %s. Update via your package manager (e.g. brew upgrade tnr).\n", |
| 380 | displayVersion(res.CurrentVersion), displayVersion(res.LatestVersion)) |
| 381 | } |
| 382 | return |
| 383 | } |
| 384 | |
| 385 | lastAttempt, err := updatepolicy.ReadOptionalUpdateAttempt() |
| 386 | if err != nil { |
| 387 | fmt.Fprintf(os.Stderr, "Warning: unable to read optional update cache: %v\n", err) |
| 388 | } |
| 389 | if !lastAttempt.IsZero() && time.Since(lastAttempt) < updatepolicy.OptionalUpdateTTL { |
| 390 | fmt.Printf("ℹ️ Update available: %s → %s. Automatic update skipped (last attempt %s). Reinstall from the latest release to update now.\n", |
| 391 | displayVersion(res.CurrentVersion), displayVersion(res.LatestVersion), lastAttempt.Format(time.RFC1123)) |
| 392 | return |
| 393 | } |
| 394 | |
| 395 | fmt.Printf("Automatically updating to %s. Please wait...\n", displayVersion(res.LatestVersion)) |
| 396 | |
| 397 | attemptTime := time.Now() |
| 398 | updateCtx, cancel := context.WithTimeout(parentCtx, 5*time.Minute) |
| 399 | defer cancel() |
| 400 | |
| 401 | updateErr := runSelfUpdate(updateCtx, res) |
| 402 | if writeErr := updatepolicy.WriteOptionalUpdateAttempt(attemptTime); writeErr != nil { |
| 403 | fmt.Fprintf(os.Stderr, "Warning: failed to record optional update attempt: %v\n", writeErr) |
| 404 | } |
| 405 | |
| 406 | if updateErr == nil { |
| 407 | fmt.Printf("Updated tnr to %s.\n", displayVersion(res.LatestVersion)) |
| 408 | } else { |
| 409 | // Capture optional update failures to Sentry |
| 410 | sentry.WithScope(func(scope *sentry.Scope) { |
| 411 | scope.SetTag("operation", "optional_update") |
| 412 | scope.SetTag("current_version", res.CurrentVersion) |
| 413 | scope.SetTag("target_version", res.LatestVersion) |
| 414 | scope.SetLevel(sentry.LevelWarning) |
| 415 | sentry.CaptureException(updateErr) |
| 416 | }) |
| 417 | fmt.Fprintf(os.Stderr, "Warning: optional update failed: %v\n", updateErr) |
| 418 | fmt.Printf("You can download the latest version from GitHub: https://github.com/Thunder-Compute/thunder-cli/releases/tag/%s and reinstall the CLI.\n", releaseTag(res)) |
| 419 | } |
| 420 | os.Exit(0) |
| 421 | } |
no test coverage detected