Skip to content

feat: immutable releases#14445

Open
zerosnacks wants to merge 10 commits intomasterfrom
feat/immutable-releases
Open

feat: immutable releases#14445
zerosnacks wants to merge 10 commits intomasterfrom
feat/immutable-releases

Conversation

@zerosnacks
Copy link
Copy Markdown
Member

@zerosnacks zerosnacks commented Apr 24, 2026

Summary

Switches Foundry to fully immutable releases. No more mutable Git tags (nightly, stable, rc) that get force-moved on each release.

Changes

Release workflow (release.yml)

  • Removed mutable tag triggers (stable, rc, rc-*) — only v*.*.* semver tags trigger releases
  • Removed the "Update nightly release" step that overwrote the mutable nightly GitHub release
  • Removed the "Move nightly tag" step that force-moved the nightly tag to HEAD
  • Removed LAST_STABLE_VERSION env var
  • Removed cleanup job — no more pruning of old nightlies (immutable means permanent)
  • Each nightly gets its own immutable nightly-{SHA} release only
  • Changelog fromTag for stable releases now explicitly resolves to the previous v*.*.* tag, preventing nightlies from being picked as the base

Docker (docker-publish.yml)

  • Simplified tagging to derive directly from inputs.tag_name
  • Fixes workflow_call bug where nightlies got mis-tagged (event_name is workflow_call, not schedule)
  • Version tags get :v1.2.3, :v1.2, :v1 (standard Docker convention); everything else (including nightly-{SHA}) tagged as-is

foundryup (bash)

  • latest is now the default channel — uses /releases/latest GitHub API endpoint
  • stable is a silent alias for latest
  • nightly resolves to the latest nightly-{SHA} prerelease via GitHub API (per_page=10), excludes drafts
  • Specific versions (v1.6.0, nightly-{SHA}) still work directly
  • Added fetch() helper for silent HTTP requests (used by release resolution and version check)
  • Inlined release resolution at call sites, removed resolve_latest_release() function
  • Improved logging: fetch/resolve steps are now visible to the user
  • Fixed set -eo pipefail compatibility in fetch pipelines
  • check_installer_up_to_date() now uses fetch() helper
  • Bumped installer version to 1.8.0
  • Updated README with foundryup -i latest alternative

Scripts

  • .github/scripts/create-tag.js — removed force: true from createRef; now only swallows "already exists" errors (422) and rethrows unexpected failures
  • .github/scripts/move-tag.js — deleted
  • .github/scripts/prune-prereleases.js — deleted

User-facing behavior

Command Behavior
foundryup Installs latest release (resolved via /releases/latest)
foundryup -i latest Same as above
foundryup -i stable Silent alias for latest
foundryup -i nightly Installs latest nightly (resolved via API)
foundryup -i nightly-abc123... Installs that specific nightly
foundryup -i v1.6.0 Installs that exact version

⚠️ Note on current /releases/latest

The foundryup default (latest) resolves via GitHub's /releases/latest endpoint, which returns the most recent non-prerelease, non-draft release. Currently that is v1.6.0-rc1 — this will remain the default until v1.7.0 is tagged as a full release. This is expected behavior: GitHub considers v1.6.0-rc1 the latest release because it was not marked as a prerelease.

Migration

Old mutable tags (nightly, stable) will be frozen in place — not deleted. Old foundryup (v1.7.0) will still work with stale binaries and the existing check_installer_up_to_date() will prompt users to run foundryup --update.

Companion PR

zerosnacks and others added 2 commits April 24, 2026 15:30
- Remove mutable tag triggers (stable, rc, rc-*) from release workflow;
  only v*.*.* semver tags trigger releases now
- Remove mutable 'nightly' GitHub release overwrite; each nightly gets
  its own immutable nightly-{SHA} release only
- Delete move-tag.js; stop force-moving the nightly tag to HEAD
- Docker: stop tagging :nightly and :latest; use immutable
  :nightly-{short-sha} and :v*.*.* tags instead
- foundryup: resolve 'latest' and 'nightly' channels via GitHub API
  to find the actual immutable release tags
- foundryup: 'stable' is a silent alias for 'latest'
- Simplify prune-prereleases.js filter (no mutable nightly to protect)
- Bump foundryup installer version to 1.8.0

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>
- Docker: derive tags from inputs.tag_name directly, fixing
  workflow_call nightly mis-tagging
- Remove release pruning entirely (immutable means permanent)
- Delete prune-prereleases.js and cleanup job from release.yml
- Remove force: true from create-tag.js (invalid for createRef)

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>
Avoids pagination issue where 50+ nightlies could push the latest
stable release off the first page of results.

Amp-Thread-ID: https://ampcode.com/threads/T-019dbf9e-5115-77b9-a177-1af9d30af00c
Co-authored-by: Amp <amp@ampcode.com>
@zerosnacks zerosnacks marked this pull request as ready for review April 27, 2026 08:27
@zerosnacks zerosnacks marked this pull request as draft April 27, 2026 08:30
@zerosnacks zerosnacks marked this pull request as ready for review April 27, 2026 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant