pkg

package
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: BSD-2-Clause Imports: 19 Imported by: 0

Documentation

Overview

Package pkg provides the core domain types and logic for the go-version-watcher service:

  • Version — parsed Go release version with (major, minor, patch) comparison
  • GoDevClient — queries https://go.dev/dl/?mode=json for the max stable version
  • Cursor — single LastSeenVersion dedup state persisted to disk
  • TaskPublisher — sends the CreateTaskCommand for the Go update runbook
  • Watcher — the Poll loop tying it all together

See [[Go Version Watcher]] for the design, [[Watcher Writing Guide]] for the producer-side contract and [[Agent Task File Contract]] for the frontmatter/body shape this watcher emits.

Index

Constants

View Source
const DefaultCursorPath = "/data/cursor.json"

DefaultCursorPath is the default cursor persistence location. k8s mounts /data as a PVC; main.go binds CURSOR_PATH=DefaultCursorPath.

View Source
const DefaultGoDevURL = "https://go.dev/dl/?mode=json"

DefaultGoDevURL is the go.dev release-list endpoint returning the JSON array of releases (including unstable ones — the client filters to stable).

Variables

This section is empty.

Functions

func BuildCreateCommand

func BuildCreateCommand(
	ctx context.Context,
	newVersion string,
	previousVersion string,
	releaseKind string,
	cfg TaskConfig,
) (task.CreateCommand, error)

BuildCreateCommand assembles the CreateTaskCommand for a new Go version. newVersion and previousVersion are canonical go-version strings (e.g. "go1.27.0"); releaseKind is "minor" or "patch". The title and body are rendered from cfg.TitleTemplate / cfg.BodyTemplate (or the package defaults when nil); any template-execution failure is returned as a wrapped error.

func DeriveTaskID

func DeriveTaskID(version string) uuid.UUID

DeriveTaskID returns a UUID5 derived deterministically from the Go version string (e.g. "go1.27.0").

Uniqueness set rationale (per [[Watcher Writing Guide]] § Deterministic task_identifier):

  • Same version → same task_id → controller dedup makes re-emit a no-op.
  • A newer version → new name → new task_id → fresh task.

func NewResetCursorHandler added in v0.3.0

func NewResetCursorHandler(cursorPath string) http.Handler

NewResetCursorHandler returns an HTTP handler that deletes the cursor file at cursorPath, so the next poll cold-starts (re-seeds). A missing file is treated as success (already reset).

Wrap with libhttp.NewDangerousHandlerWrapper at the call site to require a passphrase — the bare handler does not enforce auth.

func NewSetCursorHandler added in v0.3.0

func NewSetCursorHandler(cursorPath string) http.Handler

NewSetCursorHandler returns an HTTP handler that validates the {version} URL variable as a Go version (e.g. go1.26.5) and writes it as the cursor's LastSeenVersion. Setting it to a version lower than the current latest makes the next poll emit a task; setting it to the current latest suppresses emit.

Wrap with libhttp.NewDangerousHandlerWrapper at the call site to require a passphrase — the bare handler does not enforce auth.

Route: /setcursor/{version}. Invalid version → 400.

func NewTriggerHandler added in v0.3.0

func NewTriggerHandler(watcher Watcher) http.Handler

NewTriggerHandler returns an HTTP handler that invokes the watcher's Poll once immediately, so an operator can force a poll cycle without waiting for the interval tick (e.g. for live end-to-end testing after a cursor reset/set).

func ParseTaskTemplate added in v0.5.0

func ParseTaskTemplate(ctx context.Context, name, text string) (*template.Template, error)

ParseTaskTemplate parses text as a named Go text/template and validates it by rendering against sample data, so a template referencing an unknown field fails fast at startup rather than silently skipping every emit. Empty text returns (nil, nil) ⇒ the built-in default is used.

func SaveCursor

func SaveCursor(ctx context.Context, path string, c *Cursor) error

SaveCursor persists cursor state to path atomically via temp file + rename.

Types

type Cursor

type Cursor struct {
	LastSeenVersion string `json:"last_seen_version"`
}

Cursor is the single-value dedup state: the last Go version the watcher has seen and acted on. Empty LastSeenVersion means cold start (no prior run).

Concurrency: not safe for concurrent use. The Watcher loads at poll start and saves at poll end (single goroutine).

func LoadCursor

func LoadCursor(ctx context.Context, path string) (*Cursor, error)

LoadCursor reads cursor state from path. Missing file → fresh empty cursor (cold start is valid). Corrupt file → error (caller should refuse to advance).

type GoDevClient

type GoDevClient interface {
	// LatestStable returns the maximum stable Go version reported by go.dev.
	// It returns an error when the request fails, the response is malformed, or
	// no stable, parseable version is present.
	LatestStable(ctx context.Context) (Version, error)
}

GoDevClient is the upstream-source surface for the go-version watcher.

func NewGoDevClient

func NewGoDevClient(httpClient *http.Client, url string) GoDevClient

NewGoDevClient returns the production GoDevClient backed by the given HTTP client and URL (typically DefaultGoDevURL).

type Metrics

type Metrics interface {
	// IncPollCycle — result: "success" | "go_dev_error" | "build_error"
	IncPollCycle(result string)

	// IncPublished — status: "create" | "error"
	IncPublished(status string)

	// IncFilterSkipped — reason: "version_unchanged"
	IncFilterSkipped(reason string)
}

Metrics is the observable counter surface required by [[Watcher Writing Guide]] § Required observability.

func NewMetrics

func NewMetrics(registerer prometheus.Registerer) Metrics

NewMetrics returns the Prometheus-backed Metrics implementation registered against the supplied Registerer. Pass nil for the default registry. Pre-initialises every label combination so Prometheus exposes a zero series before the first event fires.

type TaskConfig

type TaskConfig struct {
	Stage    string // "dev" or "prod" — frontmatter `stage`
	Assignee string // frontmatter `assignee` (default "human")
	Status   string // frontmatter `status` (default "in_progress")
	Phase    string // frontmatter `phase` (default "todo")
	Suffix   string // optional title/filename suffix appended as " - <suffix>"; empty = none

	// TitleTemplate overrides the emitted-task title; nil ⇒ defaultTitleTemplate.
	TitleTemplate *template.Template
	// BodyTemplate overrides the emitted-task body; nil ⇒ defaultBodyTemplate.
	BodyTemplate *template.Template
}

TaskConfig groups per-task envelope settings (stage routing + emitted-task frontmatter knobs).

type TaskPublisher

type TaskPublisher interface {
	PublishCreate(ctx context.Context, cmd task.CreateCommand) bool
}

TaskPublisher sends a pre-built CreateTaskCommand via the supplied CreateCommandSender. Returns true on successful send, false on error.

func NewTaskPublisher

func NewTaskPublisher(sender task.CreateCommandSender, metrics Metrics) TaskPublisher

NewTaskPublisher returns a TaskPublisher that wraps the given sender + metrics.

type Version

type Version struct {
	Major int
	Minor int
	Patch int
	Raw   string
}

Version is a parsed Go release version. Patch defaults to 0 when the source string omits it (e.g. "go1.27" → patch 0). Raw preserves the original string.

func ParseVersion

func ParseVersion(ctx context.Context, s string) (Version, error)

ParseVersion parses a Go release version string of the form go<major>.<minor>[.<patch>]. A missing patch component defaults to 0. Returns an error if the string does not match the expected shape.

func (Version) Compare

func (v Version) Compare(other Version) int

Compare orders two versions by (major, minor, patch). It returns a negative number when v < other, zero when equal, and a positive number when v > other.

func (Version) Less

func (v Version) Less(other Version) bool

Less reports whether v sorts before other by (major, minor, patch).

func (Version) Number

func (v Version) Number() string

Number returns the numeric "<major>.<minor>.<patch>" form without the "go" prefix, used in the human-readable task title.

func (Version) String

func (v Version) String() string

String returns the canonical "go<major>.<minor>.<patch>" form. It is derived from the parsed components, not Raw, so it always includes the patch.

type Watcher

type Watcher interface {
	// Poll runs one scan cycle. Safe to call repeatedly on an interval.
	Poll(ctx context.Context) error
}

Watcher polls go.dev for the max stable Go version and publishes a CreateTaskCommand when it advances beyond the cursor.

func NewWatcher

func NewWatcher(
	client GoDevClient,
	publisher TaskPublisher,
	metrics Metrics,
	cursorPath string,
	cfg TaskConfig,
	seedVersion string,
) Watcher

NewWatcher wires the watcher's collaborators.

seedVersion, when non-empty, is the Go version the cursor is seeded with on cold start instead of the current latest, so the first poll can emit a task for the current latest. Empty means seed to latest and emit nothing.

Directories

Path Synopsis
Package factory wires concrete dependencies for the go-version-watcher binary.
Package factory wires concrete dependencies for the go-version-watcher binary.

Jump to

Keyboard shortcuts

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