update

package
v0.1.0-rc1 Latest Latest
Warning

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

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package update reports whether a newer fft release is available.

It is deliberately a best-effort background chore: nothing it does may delay or fail a command. The result of the last check is cached for Interval, so the network is consulted at most once a day, and every failure — no network, a rate limit, a repository with no releases yet — is swallowed.

Index

Constants

View Source
const (
	// DefaultURL is GitHub's latest-release endpoint for fft. It is
	// unauthenticated: the rate limit it shares with the rest of the machine is
	// 60 requests an hour, and one a day per user is comfortably inside it.
	DefaultURL = "https://api.github.com/repos/Joessst-Dev/fft-cli/releases/latest"

	// Interval is how long a cached answer is trusted before GitHub is asked
	// again.
	Interval = 24 * time.Hour

	// Timeout bounds a single check. It is short on purpose: the check runs
	// alongside the command, and a user on a plane must not wait for it.
	Timeout = 1500 * time.Millisecond
)

Variables

This section is empty.

Functions

func Comparable

func Comparable(v string) bool

Comparable reports whether v has a place in the version ordering at all — that is, whether it is a real semver version rather than "dev", "", or a branch name.

A build that is not comparable is never told to upgrade, and must never be told it is up to date either: the honest answer about it is "unknown".

func DefaultCachePath

func DefaultCachePath() (string, error)

DefaultCachePath is $XDG_CACHE_HOME/fft/update.json, falling back to ~/.cache/fft/update.json.

func Newer

func Newer(current, latest string) bool

Newer reports whether latest is a later release than current.

The comparison is a real semver parse, because the obvious string comparison gets v1.10.0 vs v1.9.0 exactly backwards. Anything that is not a semver version — "dev", "", a branch name — compares as no answer at all, which is what suppresses the notice on a local build.

Types

type Checker

type Checker struct {
	// contains filtered or unexported fields
}

Checker asks GitHub for the latest release and remembers the answer.

The zero value is not usable; call New. A Checker is safe to use from the background goroutine that owns it, and holds no state beyond its configuration — the cache lives in a file.

func New

func New(version, cachePath string, opts ...Option) *Checker

New returns a Checker for the running fft version, caching its answer in the file at cachePath.

version is the fft build's own version, used both as the User-Agent GitHub asks callers to send and as the left-hand side of the version comparison.

func (*Checker) Cached

func (c *Checker) Cached() (State, bool)

Cached returns the last stored result, and whether it is fresh enough to use instead of asking GitHub again.

A missing, unreadable or corrupt cache file is reported as a zero State that is not fresh: a cache we cannot understand is one we do not have. A CheckedAt in the future is not fresh either — a clock that jumped must not silence the check forever.

func (*Checker) Claim

func (c *Checker) Claim() error

Claim records that a check is being made, before it is made.

The process does not necessarily outlive the check. A command that finishes in milliseconds exits while the request to GitHub is still in flight, and the background goroutine dies with it, having written nothing at all — so the next invocation would find the same stale cache and ask again, and so would the one after that. A user whose commands are fast, or whose network is simply down, would hit GitHub every single time they typed fft.

Stamping the cache first costs one small write a day and makes that impossible. What was already known is carried over: the claim records when we asked, not what we learned.

func (*Checker) Current

func (c *Checker) Current() string

Current is the fft version this Checker compares releases against.

func (*Checker) Notice

func (c *Checker) Notice(s State) string

Notice is the line to show the user, or "" when there is nothing to say — fft is current, the release is older, or either version is not a version we can compare.

func (*Checker) Refresh

func (c *Checker) Refresh(ctx context.Context) (State, error)

Refresh asks GitHub for the latest release, ignoring the cache's age, and stores what it learns.

The cache is stamped with the current time even when the request fails, so that a broken network costs one request a day rather than one per command. On failure the previously known release is kept: it is old information, but it is not wrong, and dropping it would silence the notice for a day.

type Option

type Option func(*Checker)

Option configures a Checker.

func WithClock

func WithClock(now func() time.Time) Option

WithClock replaces time.Now, so that a spec can age the cache without sleeping.

func WithURL

func WithURL(url string) Option

WithURL replaces the release endpoint. Specs point it at an httptest server; production leaves it at DefaultURL.

type State

type State struct {
	CheckedAt     time.Time `json:"checkedAt"`
	LatestVersion string    `json:"latestVersion,omitempty"`
	URL           string    `json:"url,omitempty"`
}

State is what the cache file holds: the outcome of the last check.

CheckedAt is stamped even when the check failed, which is the point of it — without it a user with no network would ask GitHub on every single invocation.

Jump to

Keyboard shortcuts

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