feat(updater): add VersionGatherer extraction core and CLI gather seam

Give the Runner a way to read each component's CURRENT version so it can be
compared against the release sources already wired. Three pure extractors turn
raw system text into an updates.Version, each fail-closed:

  - versionFromCLI      — a `<tool> --version` banner   (k3s, cloudflared)
  - versionFromImageRef — a container image tag         (felis-api)
  - versionFromJarName  — a proxy jar filename          (velocity)

sysGatherer routes each Topology component to the right extractor over an
injected seam; every path is exercised with a fake runner, mirroring how the
release sources are proven against httptest.

The load-bearing case is k3s: its Git tag "v1.36.2+k3s1" parses stable, but a
registry cannot store '+', so the same build ships as image tag "v1.36.2-k3s1",
which parses as a prerelease unless repaired. versionFromImageRef normalizes
"-k3sN"/"-rke2rN" back to "+", so an image read and a CLI read agree instead of
the image masquerading as a prerelease and being barred from comparison.

Honest runtime state after this slice — a green suite is not "the updater runs
against real infra": only the CLI seam (execRunner) is wired, so of the four
tracked components just cloudflared is live end to end (gatherable AND
Scheduled/appliable). k3s is CLI-gatherable but Notify-only. felis-api and
velocity are NOT yet runtime-gatherable: their producing seams — a k8s read of
the control-plane Deployment image, and an off-cluster jar inspection — are left
nil, so both surface an explicit "gather seam not wired" error rather than a
wrong version. felis-api self-update is therefore not functional yet.

Remaining integration (tracked in doc.go): the two producing seams, the concrete
Notifier (SMTP + in-game), the Applier (image bump, cloudflared swap), the
`felis update` CLI + CronJob entry point, and the runtime append of the Pinned
Minecraft fleet.
This commit is contained in:
flyemoji committed 2026-07-05 04:05:56 +09:00
1 parent e574749877
commit 7db57b9fff
5 files changed
+462 -12

No files matched your search

+16 -10
View File
@@ -29,15 +29,21 @@
// routing/parse logic is verified, but that one component stays dark at runtime (its
// Latest errors, degrading to "latest unknown") until a real repository is configured.
//
// - NOT YET BUILT, but VERIFIABLE HERE (the next slice): the VersionGatherer's
// extraction core — command output (`k3s --version`), image tag
// (`rancher/k3s:v1.36.2-k3s1`) or jar filename → Version. That is logic over an
// exec/read seam, testable with a fake runner à la internal/reaper's ExecRunner,
// and load-bearing: a mis-read current version makes every plan wrong (spurious
// applies or missed upgrades). Only the seam's actual I/O is un-verifiable here.
// - ALSO BUILT + UNIT-VERIFIED: the VersionGatherer's extraction core and dispatch.
// Three pure extractors turn raw system text into a Version — a `--version` banner
// (k3s, cloudflared), a container image tag (felis-api), a proxy jar filename
// (velocity) — and sysGatherer routes each component to the right one over an
// injected seam, all exercised with a fake runner (gatherer_test.go). The
// load-bearing case is proven: k3s's registry tag "v1.36.2-k3s1" is repaired to the
// "+k3s1" build form the binary reports (a Docker tag cannot hold '+'), so an image
// read and a CLI read agree instead of the image masquerading as a prerelease. The
// CLI seam (execRunner) is wired for real; only its exec I/O is un-verified here.
//
// - REMAINING INTEGRATION (genuinely I/O-bound — needs a cluster/mailbox to exercise):
// the concrete Notifier (SMTP + in-game) and Applier (control-plane image bump,
// cloudflared swap), the `felis update` CLI + CronJob entry point, and the runtime
// append of the live Pinned Minecraft fleet.
// - REMAINING INTEGRATION (genuinely I/O-bound — needs a node/cluster/mailbox): the
// two current-version PRODUCING seams the gatherer still lacks — the k8s read of the
// control-plane Deployment's image (felis-api) and the off-cluster Velocity jar
// inspection, both left nil so those components surface a gather error rather than a
// wrong version — plus the concrete Notifier (SMTP + in-game) and Applier
// (control-plane image bump, cloudflared swap), the `felis update` CLI + CronJob
// entry point, and the runtime append of the live Pinned Minecraft fleet.
package updater