updatecheck

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 30, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package updatecheck implements the passive "new release available" check: it throttles GitHub release lookups to once per check interval, caches the result in the sprout state directory, and answers "is there a newer version than X" for the CLI notice and the WebUI banner.

All persistence is best-effort: any read/write failure degrades to "no cached state" rather than an error, because the check must never disrupt startup or command output.

Index

Constants

View Source
const (
	// CheckInterval is the minimum time between GitHub release lookups.
	// The unauthenticated GitHub API allows 60 req/hr per IP; one lookup
	// per process start at this throttle stays far below that even with
	// many sprout invocations, since only the first start in the window
	// hits the network.
	CheckInterval = 24 * time.Hour

	// NoticeInterval is how often the CLI re-shows the update notice for
	// the same newer version. Each new cached version notifies immediately.
	NoticeInterval = 24 * time.Hour
)

Variables

This section is empty.

Functions

func CachedNewer

func CachedNewer(current string, now time.Time) (latest string, ok bool)

CachedNewer is NoticeFor without the side effect, for read-only consumers like the WebUI bootstrap payload.

func FetchLatestTag

func FetchLatestTag(ctx context.Context) (string, error)

FetchLatestTag returns the most recent non-draft, non-prerelease release tag from GitHub. Bounded by fetchTimeout.

func FetchLatestTagLongTimeout

func FetchLatestTagLongTimeout(ctx context.Context) (string, error)

FetchLatestTagLongTimeout is FetchLatestTag with the upgrade command's generous 5-minute budget: the user explicitly asked for a version lookup, so a slow or proxied link gets the same patience the old inline implementation had.

func IsNewer

func IsNewer(current, latest string) bool

IsNewer reports whether latest is a strict semver upgrade over current. Either side failing to parse as semver ("dev", git-hash builds, empty strings) yields false — no notice rather than a wrong notice.

func NeedsCheck

func NeedsCheck(s State, now time.Time) bool

NeedsCheck reports whether the cached state is stale enough to justify another release lookup. A zero LastCheck (first run) always needs one; a future LastCheck (clock moved back) counts as recently checked so a skewed clock can't trigger a lookup on every start.

func NormalizeVersion

func NormalizeVersion(v string) string

NormalizeVersion strips a leading 'v' (or 'V') so v1.2.3 / V1.2.3 / 1.2.3 compare equal, then re-adds the 'v' because upstream release tags carry it. "dev" passes through unchanged.

func NoticeFor

func NoticeFor(current string, now time.Time) (latest string, ok bool)

NoticeFor returns the cached newer version when a notice is due: the cached LatestRelease must be a strict semver upgrade over current and not already shown for that version within NoticeInterval. When ok, the shown-marker is persisted so the caller can print unconditionally.

func RefreshMaybe

func RefreshMaybe(ctx context.Context, now time.Time)

RefreshMaybe runs a release lookup when the cached state is stale and persists the outcome. It is synchronous but bounded by fetchTimeout; callers invoke it from a goroutine so startup never waits on it.

The in-flight flag dedupes concurrent launches in one process (the interactive CLI and the in-process web server both call this). The lock is released during the network call so notice rendering and bootstrap reads never block on the fetch, and the merge re-reads state afterward so a marker persisted meanwhile survives.

func Skipped

func Skipped(current string, disabled bool) bool

Skipped resolves every skip condition for both the check and its notice: non-semver builds ("dev", empty) can't be compared, the env var opts out, CI environments shouldn't make network calls, and the config knob disables the feature. Callers fold nil-config into disabled=true (fail closed: no config, no GitHub call).

Types

type State

type State struct {
	// LastCheck is when the release lookup last ran (success or failure).
	// Failures advance it too, so an unreachable GitHub doesn't turn every
	// startup into a network attempt.
	LastCheck time.Time `json:"last_check,omitempty"`

	// LatestRelease is the newest stable release tag seen. Empty until the
	// first successful lookup.
	LatestRelease string `json:"latest_release,omitempty"`

	// NoticeShownAt / NoticeShownFor record when the update notice was
	// last printed and for which version, enforcing the once-per-notice-
	// interval nag limit.
	NoticeShownAt  time.Time `json:"notice_shown_at,omitempty"`
	NoticeShownFor string    `json:"notice_shown_for,omitempty"`
}

State is the persisted update-check cache.

func LoadState

func LoadState() State

LoadState reads the cached update-check state. Any failure — missing file, corrupt JSON, unwritable state dir — returns the zero State.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL