Skip to content

feat: immutable releases#14445

Merged
zerosnacks merged 19 commits into
masterfrom
feat/immutable-releases
Apr 28, 2026
Merged

feat: immutable releases#14445
zerosnacks merged 19 commits into
masterfrom
feat/immutable-releases

Conversation

@zerosnacks

@zerosnacks zerosnacks commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

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

@mablr mablr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sgtm.

  • stable is a silent alias for latest

Does Docker's stable tag become stale after this ?

Comment thread .github/workflows/release.yml
figtracer
figtracer previously approved these changes Apr 27, 2026

@figtracer figtracer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@zerosnacks

Copy link
Copy Markdown
Contributor Author

Sgtm.

  • stable is a silent alias for latest

Does Docker's stable tag become stale after this ?

The old workflow emitted :nightly and :latest but not :stable, I've updated the workflow so it does mutably tag :nightly and :latest for Docker for convenience again.

@zerosnacks zerosnacks requested a review from mablr April 27, 2026 10:59
zerosnacks and others added 2 commits April 27, 2026 13:49
- prepare creates the GitHub release as a draft up-front (with --verify-tag)
  so all matrix jobs upload assets to an existing draft.
- release matrix replaces softprops/action-gh-release with gh release upload
  --clobber against the draft.
- nightly releases are auto-published by a new publish-nightly job once all
  assets have been uploaded; stable releases are left as drafts for a
  maintainer to publish manually.
- prepare distinguishes existing draft (reuse) from already-published release
  (fail loudly), so a same-SHA nightly rerun after publication can't try to
  upload to an immutable release.

Amp-Thread-ID: https://ampcode.com/threads/T-019dced2-6c4a-76fb-af86-79fd948a0157
Co-authored-by: Amp <amp@ampcode.com>
mablr
mablr previously approved these changes Apr 27, 2026
@zerosnacks zerosnacks added the T-blocked Type: blocked label Apr 27, 2026
@zerosnacks zerosnacks marked this pull request as draft April 27, 2026 17:57
@zerosnacks zerosnacks removed the T-blocked Type: blocked label Apr 28, 2026
@zerosnacks zerosnacks marked this pull request as ready for review April 28, 2026 08:44
Comment thread foundryup/foundryup Outdated
Comment thread foundryup/foundryup Outdated
figtracer
figtracer previously approved these changes Apr 28, 2026
@zerosnacks zerosnacks requested a review from mablr April 28, 2026 09:41
env context is not available in job-level if expressions

Amp-Thread-ID: https://ampcode.com/threads/T-019dd37e-7210-77da-bf0e-1d77ccecb19e
Co-authored-by: Amp <amp@ampcode.com>
@zerosnacks zerosnacks merged commit 906020f into master Apr 28, 2026
17 checks passed
@zerosnacks zerosnacks deleted the feat/immutable-releases branch April 28, 2026 10:10
@github-project-automation github-project-automation Bot moved this to Done in Foundry Apr 28, 2026
zerosnacks added a commit to foundry-rs/foundry-toolchain that referenced this pull request Apr 28, 2026
Removes `rc` from the documented `version` input options, since it is no
longer a supported channel after foundry-rs/foundry#14445 (immutable
releases).

## Context

The Foundry release workflow previously supported a mutable `rc` Git tag
that was force-moved on each release candidate. With the immutable
releases PR (foundry-rs/foundry#14445), the `rc` channel is removed —
release candidates are now pre-release tags like `v1.6.0-rc1` and must
be installed by their explicit version.

## Changes

- `action.yml`: removed `rc` from the version description
- `README.md`: removed `rc` from the inputs table

## Behavior change for users

Once foundry-rs/foundry#14445 merges:

- `version: rc` → no longer works; users must pin the specific version
(e.g. `version: v1.6.0-rc1`)
- `version: stable` (default) → silently changes meaning, now resolves
via GitHub `/releases/latest`. Until `v1.7.0` is tagged, this returns
`v1.6.0-rc1` because GitHub considers it the latest non-prerelease
release
- `version: nightly` → still works (resolves to latest `nightly-{SHA}`)
- `version: v1.6.0` / `1.6.0` → still works

## Related

- foundry-rs/foundry#14445 — Foundry immutable releases PR

---------

Co-authored-by: Amp <amp@ampcode.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants