remotestate

package
v0.167.0 Latest Latest
Warning

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

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

Documentation

Overview

Package remotestate publishes one machine's WB fleet state to a shared store and reads every machine's state back. The store is pluggable; the snapshot format is not.

Index

Constants

View Source
const (
	StatusAttention = "attention"
	StatusError     = "error"
)

Status constants for RepositoryState.

View Source
const ClaimSchemaVersion = 1

ClaimSchemaVersion is the claim format this binary writes and the newest it can read.

View Source
const ConfigSnippet = `` /* 137-byte string literal not displayed */

ConfigSnippet is printed whenever the remote section is absent or incomplete, so the fix is copy-paste rather than documentation lookup.

View Source
const HubConfigSnippet = `` /* 180-byte string literal not displayed */

HubConfigSnippet is the explicit hosted alternative. It has no anonymous or insecure default and defaults to privacy-safe unpushed counts.

View Source
const SchemaVersion = 1

SchemaVersion is the snapshot format this binary writes and the newest it can read.

Variables

View Source
var ErrHubURL = errors.New("remote.url must be an HTTPS origin without credentials, query, or fragment, or an http:// origin on a loopback host")

ErrHubURL is the single explanation both the configuration loader and the HTTP provider give for a hub endpoint they will not talk to.

Functions

func Encode

func Encode(s Snapshot) ([]byte, error)

Encode renders a snapshot as YAML.

func EncodeClaim added in v0.45.0

func EncodeClaim(c Claim) ([]byte, error)

EncodeClaim renders a claim as YAML.

func ValidTaskName added in v0.45.0

func ValidTaskName(task string) error

ValidTaskName enforces the machine-name rule on task names, which also keeps claims/<task>.yaml a safe path.

func ValidateHubURL added in v0.124.5

func ValidateHubURL(raw string) error

ValidateHubURL accepts an HTTPS origin, and an http:// origin only when its host is a loopback address.

Plain http is otherwise refused because a machine credential travels in the Authorization header on every request. A loopback origin is the one case where there is no network to intercept: the self-hosted bench in spec/features/self-hosted-bench runs the hub inside the same daemon the provider talks to, reachable only from this machine, and demanding a certificate for 127.0.0.1 would mean "deploy a service" rather than "run wb".

Types

type Claim added in v0.45.0

type Claim struct {
	SchemaVersion int       `yaml:"schema_version" json:"schema_version"`
	Task          string    `yaml:"task" json:"task"`
	Login         string    `yaml:"login" json:"login"`
	Machine       string    `yaml:"machine" json:"machine"`
	ClaimedAt     time.Time `yaml:"claimed_at" json:"claimed_at"`
	Note          string    `yaml:"note,omitempty" json:"note,omitempty"`
}

Claim says one task is being worked on by one login/machine. The claim file's existence in the store IS the claim; releasing deletes it, so git history is the audit trail and no state field exists.

func DecodeClaim added in v0.45.0

func DecodeClaim(data []byte) (Claim, error)

DecodeClaim parses a claim, refusing formats newer than this binary knows.

func (Claim) Holder added in v0.45.0

func (c Claim) Holder() string

Holder identifies the claimant: "<login>/<machine>". Mutual exclusion is per machine — the same login on another machine is another holder.

type ClaimEntry added in v0.45.0

type ClaimEntry struct {
	Claim Claim  `json:"claim"`
	Error string `json:"error,omitempty"`
}

ClaimEntry is one claim as read from the store; Error is set when the file could not be decoded (Claim then carries only Task from the path).

type ClaimMode added in v0.45.0

type ClaimMode int

ClaimMode selects how an existing claim by someone else is treated.

const (
	// ClaimNormal refuses to touch anyone else's claim.
	ClaimNormal ClaimMode = iota
	// ClaimTakeOverStale replaces another holder's claim; callers must have
	// established staleness first — the provider does not judge it.
	ClaimTakeOverStale
	// ClaimForce replaces anything, including an unreadable claim file.
	ClaimForce
)

type ClaimOutcome added in v0.45.0

type ClaimOutcome struct {
	Kind     ClaimOutcomeKind `json:"kind"`
	Current  Claim            `json:"current"`
	Previous *Claim           `json:"previous,omitempty"` // set on took_over
	Location string           `json:"location,omitempty"` // commit SHA / URL
}

ClaimOutcome reports a Claim call so commands own all messaging.

type ClaimOutcomeKind added in v0.45.0

type ClaimOutcomeKind string

ClaimOutcomeKind is what a Claim call did.

const (
	ClaimAcquired  ClaimOutcomeKind = "acquired"
	ClaimRefreshed ClaimOutcomeKind = "refreshed"
	// ClaimHeld means no write happened; Current is the other holder's claim.
	ClaimHeld     ClaimOutcomeKind = "held"
	ClaimTookOver ClaimOutcomeKind = "took_over"
)

type Config

type Config struct {
	Provider  string        `yaml:"provider"`
	Repo      string        `yaml:"repo"`
	URL       string        `yaml:"url"`
	TokenFile string        `yaml:"token_file"`
	Machine   string        `yaml:"machine"`
	Publish   PublishConfig `yaml:"publish"`
}

Config is the remote section of ~/.config/wb/wb.yaml.

func LoadConfig

func LoadConfig(path string) (Config, error)

LoadConfig reads the remote section from path. A missing file or section is an UnconfiguredError; a present but invalid value is a plain error.

func (Config) RepoName

func (c Config) RepoName() string

RepoName returns the part of Repo after the slash.

func (Config) RepoOwner

func (c Config) RepoOwner() string

RepoOwner returns the part of Repo before the slash.

func (Config) StoreID added in v0.129.0

func (c Config) StoreID() string

StoreID is the non-secret stable identity written into machine snapshots so status can reveal when machines publish through different providers.

type Entry

type Entry struct {
	Snapshot Snapshot `json:"snapshot"`
	Error    string   `json:"error,omitempty"`
}

Entry is one machine as read from the store. Error is set when the stored snapshot could not be decoded; Snapshot then carries only Login/Machine.

type Provider

type Provider interface {
	// Publish overwrites the caller's own login/machine entry. It is
	// self-contained: implementations refresh their own view of the store
	// before writing, so callers never need a separate refresh step first.
	Publish(ctx context.Context, snapshot Snapshot) (PublishResult, error)
	// List returns every machine currently in the store, including the
	// caller's own last-published entry, sorted by Key(). It is also
	// self-contained, refreshing the store view itself before reading.
	List(ctx context.Context) ([]Entry, error)
	// Claim acquires or refreshes a claim on a task. It is self-contained:
	// implementations refresh the store view before acting. The provider never
	// judges staleness; ClaimTakeOverStale merely authorizes replacing another
	// holder — commands establish staleness first.
	//
	// expectedHolder is the "<login>/<machine>" the caller judged stale and
	// is authorizing replacement of; it is "" for ClaimNormal and
	// ClaimForce, which do not need one. For ClaimTakeOverStale it is a
	// precondition: a hub provider maps this to a conditional PUT keyed on
	// the current holder, and a git-backed provider re-checks it against
	// the freshly fetched store before writing. If the actual current
	// holder no longer matches (they released and a third party claimed,
	// or refreshed away their own staleness, between the caller's judgment
	// and this call), the provider must not replace them — it reports an
	// ordinary ClaimHeld naming the real current holder instead.
	Claim(ctx context.Context, claim Claim, mode ClaimMode, expectedHolder string) (ClaimOutcome, error)
	// Release removes a claim. It is self-contained, refreshing the store view
	// before acting.
	Release(ctx context.Context, task, login, machine string, force bool) (ReleaseOutcome, error)
	// Claims returns every claim currently in the store, sorted by task name.
	// It is self-contained, refreshing the store view itself before reading.
	Claims(ctx context.Context) ([]ClaimEntry, error)
}

Provider is a shared store of machine snapshots. Implementations must be safe to call from several machines at once; the git provider relies on per-machine files plus rebase for that.

type PublishConfig

type PublishConfig struct {
	Unpushed Redaction `yaml:"unpushed"`
}

PublishConfig tunes what a snapshot contains.

type PublishResult

type PublishResult struct {
	Location string `json:"location"`
}

PublishResult says where a snapshot landed: a commit SHA for a git store, a URL for a hub.

type PullRequestState added in v0.112.0

type PullRequestState struct {
	Number int    `yaml:"number" json:"number"`
	URL    string `yaml:"url" json:"url"`
	State  string `yaml:"state" json:"state"`
}

PullRequestState is the navigable PR evidence that was available when the machine published its worktree snapshot. It deliberately omits commit and local checkout details that the hosted dashboard does not need.

type Redaction

type Redaction string

Redaction selects how unpushed commits are published.

const (
	// RedactNone publishes `git log --oneline` subjects of unpushed commits.
	RedactNone Redaction = "subjects"
	// RedactUnpushed publishes only the number of unpushed commits.
	RedactUnpushed Redaction = "counts"
)

type ReleaseOutcome added in v0.45.0

type ReleaseOutcome struct {
	Kind     ReleaseOutcomeKind `json:"kind"`
	Current  *Claim             `json:"current,omitempty"`
	Location string             `json:"location,omitempty"`
}

ReleaseOutcome reports a Release call.

type ReleaseOutcomeKind added in v0.45.0

type ReleaseOutcomeKind string

ReleaseOutcomeKind is what a Release call did.

const (
	Released ReleaseOutcomeKind = "released"
	// ReleaseNoop: no claim existed; releasing is idempotent.
	ReleaseNoop ReleaseOutcomeKind = "noop"
	// ReleaseHeldByOther: refused (force was false); Current names the holder.
	ReleaseHeldByOther ReleaseOutcomeKind = "held_by_other"
)

type RepositoryInput

type RepositoryInput struct {
	Repository string
	Path       string
	Status     gitops.RepoStatus
	Tracking   gitops.TrackingState
	Err        error
}

RepositoryInput is the per-repository scan result Build consumes. Err set means the scan itself failed; Status and Tracking are then ignored.

type RepositoryState

type RepositoryState struct {
	Repository       string                  `yaml:"repository" json:"repository"`
	Path             string                  `yaml:"path" json:"path"`
	Status           string                  `yaml:"status" json:"status"` // attention | error
	Summary          string                  `yaml:"summary,omitempty" json:"summary,omitempty"`
	Branch           string                  `yaml:"branch,omitempty" json:"branch,omitempty"`
	Upstream         string                  `yaml:"upstream,omitempty" json:"upstream,omitempty"`
	Ahead            int                     `yaml:"ahead,omitempty" json:"ahead,omitempty"`
	Behind           int                     `yaml:"behind,omitempty" json:"behind,omitempty"`
	Modified         []string                `yaml:"modified,omitempty" json:"modified,omitempty"`
	Untracked        []string                `yaml:"untracked,omitempty" json:"untracked,omitempty"`
	Conflicted       []string                `yaml:"conflicted,omitempty" json:"conflicted,omitempty"`
	Unpushed         []string                `yaml:"unpushed,omitempty" json:"unpushed,omitempty"`
	UnpushedBranches []gitops.UnpushedBranch `yaml:"unpushed_branches,omitempty" json:"unpushed_branches,omitempty"`
	UnpushedCount    int                     `yaml:"unpushed_count,omitempty" json:"unpushed_count,omitempty"`
	Stashed          []string                `yaml:"stashed,omitempty" json:"stashed,omitempty"`
	Error            string                  `yaml:"error,omitempty" json:"error,omitempty"`
}

RepositoryState is one non-clean repository on the publishing machine.

type Snapshot

type Snapshot struct {
	SchemaVersion int       `yaml:"schema_version" json:"schema_version"`
	Login         string    `yaml:"login" json:"login"`
	Machine       string    `yaml:"machine" json:"machine"`
	PublishedAt   time.Time `yaml:"published_at" json:"published_at"`
	// LastSeenAt records the last time this machine acted through the store
	// via a claim mutation (claim, refresh, release, take-over); it is
	// stamped by the provider, never by Build. Zero means no claim activity
	// has been recorded. See Heartbeat.
	LastSeenAt          time.Time         `yaml:"last_seen_at,omitempty" json:"last_seen_at,omitempty"`
	WBVersion           string            `yaml:"wb_version" json:"wb_version"`
	RemoteStore         string            `yaml:"remote_store,omitempty" json:"remote_store,omitempty"`
	ProjectsRoot        string            `yaml:"projects_root" json:"projects_root"`
	RepositoriesScanned int               `yaml:"repositories_scanned" json:"repositories_scanned"`
	KnownRepositories   []string          `yaml:"known_repositories,omitempty" json:"known_repositories,omitempty"`
	Repositories        []RepositoryState `yaml:"repositories" json:"repositories"`
	Worktrees           []WorktreeState   `yaml:"worktrees" json:"worktrees"`
}

Snapshot is one machine's published fleet state.

func Build

func Build(identity Snapshot, repos []RepositoryInput, wts []worktrees.ListResult, redaction Redaction) Snapshot

Build assembles a snapshot. identity supplies Login, Machine, PublishedAt, WBVersion, and ProjectsRoot; everything else is derived here. Clean repositories are counted but not listed. Output is sorted by repository.

func Decode

func Decode(data []byte) (Snapshot, error)

Decode parses a snapshot, refusing formats newer than this binary knows.

func (Snapshot) Heartbeat added in v0.54.0

func (s Snapshot) Heartbeat() time.Time

Heartbeat is the effective liveness signal for staleness judgments: the later of PublishedAt (last full scan) and LastSeenAt (last claim-mutation activity through the store). This is the single definition of that max — callers must not compute it themselves.

func (Snapshot) Key

func (s Snapshot) Key() string

Key identifies the machine inside a store: "<login>/<machine>".

type StatusProvider added in v0.116.0

type StatusProvider interface {
	Status(ctx context.Context) (StatusSnapshot, error)
}

StatusProvider is the optional provider capability used by remote status to refresh once and read both projections from that same store view. Providers that cannot batch the reads keep the Provider contract below; ReadStatus falls back to its two self-contained methods.

type StatusSnapshot added in v0.116.0

type StatusSnapshot struct {
	Machines []Entry      `json:"machines"`
	Claims   []ClaimEntry `json:"claims"`
}

StatusSnapshot is one consistent read of the machine snapshots and task claims currently held by a remote store.

func ReadStatus added in v0.116.0

func ReadStatus(ctx context.Context, provider Provider) (StatusSnapshot, error)

ReadStatus returns the machine and claim projections needed by remote status. A provider-level Status implementation can share one refresh; the fallback preserves compatibility with providers that expose only the self-contained Provider methods.

type UnconfiguredError

type UnconfiguredError struct {
	Path    string
	Missing []string
	Snippet string
}

UnconfiguredError reports a missing or incomplete remote section. Commands map it to the usage exit code.

func (*UnconfiguredError) Error

func (e *UnconfiguredError) Error() string

type WorktreeState

type WorktreeState struct {
	Task        string `yaml:"task" json:"task"`
	TaskSummary string `yaml:"task_summary,omitempty" json:"task_summary,omitempty"`
	Stream      string `yaml:"stream,omitempty" json:"stream,omitempty"`
	Repository  string `yaml:"repository" json:"repository"`
	Branch      string `yaml:"branch" json:"branch"`
	HeadSHA     string `yaml:"head_sha" json:"head_sha"`
	Dir         string `yaml:"dir" json:"dir"`
	Lifecycle   string `yaml:"lifecycle,omitempty" json:"lifecycle,omitempty"`
	// OwnerState is worktrees.ListResult.OwnerState: "active", "orphaned", or
	// "unknown". Empty only if the underlying scan left it unset.
	OwnerState     string            `yaml:"owner_state,omitempty" json:"owner_state,omitempty"`
	Owner          string            `yaml:"owner,omitempty" json:"owner,omitempty"`
	LastActivityAt time.Time         `yaml:"last_activity_at,omitempty" json:"last_activity_at,omitempty"`
	NeedsAttention bool              `yaml:"needs_attention,omitempty" json:"needs_attention,omitempty"`
	Attention      string            `yaml:"attention,omitempty" json:"attention,omitempty"`
	PullRequest    *PullRequestState `yaml:"pull_request,omitempty" json:"pull_request,omitempty"`
}

WorktreeState is one WB task worktree on the publishing machine, whether or not its owning session is still alive.

Directories

Path Synopsis
Package gitrepo stores machine snapshots in a git repository: one file per machine, history for free, no server.
Package gitrepo stores machine snapshots in a git repository: one file per machine, history for free, no server.

Jump to

Keyboard shortcuts

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