Skip to content

feat(updater): add PinnedVersion config for pinning to a specific release#4

Merged
TeoSlayer merged 2 commits into
mainfrom
feat/pinned-version
May 29, 2026
Merged

feat(updater): add PinnedVersion config for pinning to a specific release#4
TeoSlayer merged 2 commits into
mainfrom
feat/pinned-version

Conversation

@hank-pilot
Copy link
Copy Markdown
Contributor

What

Adds a PinnedVersion field to Config that locks the updater to a specific release tag instead of always chasing /releases/latest.

Why

Currently the updater can only auto-follow the latest release. There's no way to:

  • Pin a node to a known-good version
  • Run a canary / staged rollout
  • Downgrade to a previous release
  • Stay on a version while testing

How

  • Config.PinnedVersion string — when set (e.g. "v1.10.5"), the updater fetches that exact release via GET /repos/{repo}/releases/tags/{tag}, installs it if different from current, then idles. Clear it to resume auto-updating.
  • checkOnce() short-circuits to checkPinnedVersion() when pinned
  • fetchReleaseByTag(tag) added alongside existing fetchLatestRelease()
  • Both delegate to a shared fetchRelease(tag) (empty tag → /latest)

Tests

5 new tests, all passing:

  • TestCheckPinnedVersion_AlreadyInstalled — no network call when already on pinned version
  • TestCheckPinnedVersion_InstallsWhenDifferent — fetches and applies pinned release
  • TestCheckPinnedVersion_InvalidVersion — unparseable pin logs error, doesn't panic
  • TestFetchReleaseByTag — hits correct API endpoint
  • TestFetchReleaseByTag_NotFound — 404 on non-existent tag

…ease

Add Config.PinnedVersion field that locks the updater to an exact
release tag. When set, the updater fetches the release via
/releases/tags/{tag} instead of /releases/latest, applies it if
the current install differs, then idles — it will not chase newer
releases. Clear the field to resume auto-updating.

Includes:
- checkPinnedVersion() path in checkOnce() — early return when pinned
- fetchReleaseByTag() using the GitHub releases/tags/{tag} endpoint
- Refactored fetchLatestRelease() → fetchRelease(tag) internally
- 5 new tests covering: already-installed no-op, installs-when-different,
  invalid-version error handling, by-tag fetch, tag-not-found error
- README updated with pinning usage examples
@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Three new end-to-end tests exercising the full lifecycle:

- TestE2E_PinnedVersionLifecycle: 5-step lifecycle covering pin,
  un-pin, downgrade pin, re-pin, already-pinned no-op
- TestE2E_PinnedVersionStaysPinnedAcrossTicks: verifies that a
  pinned version does not auto-update across multiple ticks even
  when a newer release exists
- TestE2E_NoPinFollowsLatest: verifies the default behaviour
  (no pin) still follows the latest release
@TeoSlayer TeoSlayer merged commit b55cd60 into main May 29, 2026
2 checks passed
@matthew-pilot
Copy link
Copy Markdown
Collaborator

Merged cleanup complete.

🤖 matthew-pilot — merged-cleanup handler

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants