Skip to content

fix: resolve immutable release workflow and VERSION file timing issues#6187

Merged
jdx merged 1 commit intomainfrom
fix/immutable-release-workflow
Sep 5, 2025
Merged

fix: resolve immutable release workflow and VERSION file timing issues#6187
jdx merged 1 commit intomainfrom
fix/immutable-release-workflow

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Sep 5, 2025

Summary

This PR fixes two critical issues in the release process:

  1. Immutable release error: GitHub releases cannot be modified once created, preventing asset uploads
  2. VERSION file published too early: VERSION was published before release was finalized

Problems

1. Immutable Release Error

  • GitHub releases cannot add assets after creation (even drafts)
  • The workflow was trying to upload assets after release creation, causing failures
  • Need to create release with all assets in a single atomic operation

2. VERSION File Timing

  • VERSION file was created and published to R2/Cloudflare during release preparation
  • If the GitHub release failed, VERSION was already out there pointing to a non-existent release
  • This could break installations that depend on the VERSION file

Solution

Release Creation

  • Create a draft release with all assets in a single gh release create --draft command
  • This allows the release to be reviewed before making it public
  • Assets are uploaded atomically with the release creation
  • Publish the draft release as the final step after everything else succeeds

VERSION File Timing

  • Split release.sh into preparation and publishing phases
  • Created new publish-release.sh script that runs AFTER draft release is created
  • Moved VERSION file creation and R2 publishing after draft release exists
  • Separated npm, Cloudflare worker, and redirect into individual workflow steps for better visibility
  • Only publish the GitHub release (make it public) after everything succeeds

New Release Flow

  1. release-plz creates and pushes git tag with release notes
  2. release.yml workflow triggers on tag push
  3. Workflow builds all assets and prepares release artifacts
  4. Draft GitHub release created with all assets in single atomic command
  5. VERSION file created and published to R2
  6. npm package published (@jdxcode/mise)
  7. Cloudflare worker deployed
  8. Redirect updated (allowed to fail)
  9. Draft release is published (made public) as the final step

Benefits

  • ✅ Release can be reviewed in draft state before publishing
  • ✅ Assets are uploaded atomically with release creation (no immutability issues)
  • ✅ VERSION file only exists for successfully created releases
  • ✅ Each deployment step is isolated for better debugging and visibility
  • ✅ Release is only made public after everything else succeeds
  • ✅ If any step fails, the release remains in draft and can be manually fixed or deleted

Files Changed

  • .github/workflows/release.yml - Create draft release atomically, separate deployment steps, publish as final step
  • xtasks/release-plz - Remove GitHub release creation (only creates git tag)
  • scripts/release.sh - Remove publishing logic (only prepares artifacts)
  • scripts/publish-release.sh - New script for VERSION file and R2 publishing

Test plan

  • Verify the release workflow runs successfully on next tag push
  • Confirm draft GitHub release is created with all assets atomically
  • Check VERSION file is created after draft release exists
  • Verify npm publishing shows as separate step
  • Verify Cloudflare worker deployment shows as separate step
  • Verify redirect update shows as separate step (and can fail without blocking)
  • Verify draft release is published only after all steps succeed
  • Test failure scenario: if any step fails, release should remain in draft

Fixes: https://github.com/jdx/mise/actions/runs/17492019918/job/49686112317

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings September 5, 2025 12:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes a release workflow issue where GitHub releases were becoming immutable before assets could be uploaded. The solution restructures the release process to ensure a single, consistent workflow that creates draft releases for asset uploads before publishing.

  • Removed duplicate GitHub release creation from the release-plz script
  • Modified the main release workflow to create releases as drafts initially
  • Added a step to publish the release after assets are uploaded

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
xtasks/release-plz Removed GitHub release creation, leaving only git tag creation and push
.github/workflows/release.yml Modified release creation to use draft state initially, then publish after asset upload

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

generate_release_notes: true
generate_release_notes: false
token: ${{ secrets.RTX_GITHUB_BOT_TOKEN }}
- run: gh release edit --draft=false "$(./scripts/get-version.sh)"
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

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

The gh release edit command uses a shell command substitution that may not return the expected tag version. Consider using ${{github.ref_name}} instead of $(./scripts/get-version.sh) for consistency with the file upload step above, or ensure the script returns the correct tag format.

Suggested change
- run: gh release edit --draft=false "$(./scripts/get-version.sh)"
- run: gh release edit --draft=false "${{ github.ref_name }}"

Copilot uses AI. Check for mistakes.
cursor[bot]

This comment was marked as outdated.

@jdx jdx force-pushed the fix/immutable-release-workflow branch 2 times, most recently from 1c5aae3 to 720c728 Compare September 5, 2025 12:33
@jdx jdx changed the title fix: resolve immutable release workflow issue fix: resolve immutable release workflow and VERSION file timing issues Sep 5, 2025
@jdx jdx force-pushed the fix/immutable-release-workflow branch 3 times, most recently from 3429f1e to a2d16dd Compare September 5, 2025 12:39
cursor[bot]

This comment was marked as outdated.

@jdx jdx force-pushed the fix/immutable-release-workflow branch from a2d16dd to 77397d7 Compare September 5, 2025 12:46
cursor[bot]

This comment was marked as outdated.

This PR fixes critical issues in the release process:

1. **Immutable release error**: GitHub releases cannot be modified once created.
   Fixed by creating a draft release with all assets in a single atomic command,
   then publishing it after all other steps succeed.

2. **VERSION file published too early**: The VERSION file was being created and
   published to R2/Cloudflare before the GitHub release was finalized, causing
   issues if the release failed. Fixed by moving VERSION file creation and
   publishing to after the GitHub release is successfully created.

3. **Release notes extraction**: Fixed incomplete capture of git tag messages
   and proper handling of special characters in release notes.

Changes:
- Modified release workflow to create draft release with all assets atomically
- Fixed release notes extraction to include full tag message (using %(contents))
- Use --notes-file for safe handling of special characters and multi-line content
- Split release.sh into artifact preparation and publishing phases
- Created new publish-release.sh script for VERSION file and CDN publishing
- Separated npm, Cloudflare worker, and redirect into individual workflow steps
- Added all required Cloudflare environment variables to deployment steps
- Added final step to publish the draft release after everything succeeds
- Removed release creation from release-plz script (only creates git tag now)

The new release flow:
1. release-plz creates and pushes git tag with release notes
2. release.yml workflow triggers on tag push
3. Workflow builds all assets and prepares release artifacts
4. Draft GitHub release created with all assets in single command
5. VERSION file created and published to R2
6. npm package published
7. Cloudflare worker deployed
8. Redirect updated (allowed to fail)
9. Draft release is published (made public) as the final step

This ensures:
- Release can be reviewed in draft state before publishing
- Assets are uploaded atomically with release creation
- Release notes are fully captured and properly escaped
- VERSION file only exists for successfully created releases
- Each deployment step is isolated for better debugging and visibility
- Release is only made public after everything else succeeds

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@jdx jdx force-pushed the fix/immutable-release-workflow branch from 77397d7 to 3382cca Compare September 5, 2025 12:52
@jdx jdx merged commit 17fa6ab into main Sep 5, 2025
17 checks passed
@jdx jdx deleted the fix/immutable-release-workflow branch September 5, 2025 12:56
@github-actions
Copy link

github-actions bot commented Sep 5, 2025

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.8.21 x -- echo 19.2 ± 0.5 18.5 25.1 1.00
mise x -- echo 19.4 ± 0.4 18.6 20.9 1.01 ± 0.04

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.8.21 env 18.7 ± 1.0 17.9 38.1 1.00
mise env 19.0 ± 0.7 18.1 23.8 1.02 ± 0.06

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.8.21 hook-env 18.4 ± 0.4 17.6 19.5 1.00 ± 0.03
mise hook-env 18.4 ± 0.3 17.7 20.5 1.00

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.8.21 ls 16.5 ± 0.3 16.0 17.5 1.00
mise ls 16.9 ± 0.4 16.1 18.2 1.02 ± 0.03

xtasks/test/perf

Command mise-2025.8.21 mise Variance
install (cached) 165ms ✅ 103ms +60%
ls (cached) 63ms 63ms +0%
bin-paths (cached) 66ms 66ms +0%
task-ls (cached) 491ms 486ms +1%

✅ Performance improvement: install cached is 60%

jdx pushed a commit that referenced this pull request Sep 5, 2025
### 🐛 Bug Fixes

- python nested venv path order by
[@elvismacak](https://github.com/elvismacak) in
[#6124](#6124)
- resolve immutable release workflow and VERSION file timing issues by
[@jdx](https://github.com/jdx) in
[#6187](#6187)

### New Contributors

- @elvismacak made their first contribution in
[#6124](#6124)
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Sep 8, 2025
## [2025.9.5](https://github.com/jdx/mise/compare/v2025.9.4..v2025.9.5) - 2025-09-06

### 🚀 Features

- **(task)** add timeout support for task execution by @jdx in [#6216](jdx/mise#6216)
- **(task)** sub-tasks in run lists by @jdx in [#6212](jdx/mise#6212)

### Chore

- fix npm publish action by @jdx in [14f4b09](jdx/mise@14f4b09)
- fix cloudflare release action by @jdx in [00afa25](jdx/mise@00afa25)
- fix git-cliff for release notes by @jdx in [15a9aed](jdx/mise@15a9aed)

## [2025.9.4](https://github.com/jdx/mise/compare/v2025.9.3..v2025.9.4) - 2025-09-06

### Chore

- fix git-cliff on release by @jdx in [3c388f2](jdx/mise@3c388f2)

## [2025.9.3](https://github.com/jdx/mise/compare/v2025.9.2..v2025.9.3) - 2025-09-06

### 🚀 Features

- **(backend)** improve http error when platform url missing; list available platforms by @jdx in [#6200](jdx/mise#6200)
- **(cli)** support scoped packages for all backend types by @earlgray283 in [#6213](jdx/mise#6213)
- **(http)** add URL replacement feature for HTTP requests by @ThomasSteinbach in [#6207](jdx/mise#6207)

### 🐛 Bug Fixes

- **(backend)** preserve arch underscores in platform keys by @jdx in [#6202](jdx/mise#6202)
- **(task)** resolve hanging issue with multiple depends_post by @jdx in [#6206](jdx/mise#6206)
- couldn't download node binary in Alpine, even if it exists in the mirror url by @Hazer in [#5972](jdx/mise#5972)
- **breaking** use config_root for env._.path by @jdx in [#6204](jdx/mise#6204)
- bugfix for paths that include spaces by @karim-elkholy in [#6210](jdx/mise#6210)

### 📚 Documentation

- improve release notes generation by @jdx in [#6197](jdx/mise#6197)
- fix release changelog contributor reporting by @jdx in [#6201](jdx/mise#6201)

### Chore

- use fine-grained gh token by @jdx in [#6208](jdx/mise#6208)
- use settings.local.json for claude config by @jdx in [fd0fba9](jdx/mise@fd0fba9)

### New Contributors

- @ThomasSteinbach made their first contribution in [#6207](jdx/mise#6207)
- @earlgray283 made their first contribution in [#6213](jdx/mise#6213)
- @karim-elkholy made their first contribution in [#6210](jdx/mise#6210)
- @Hazer made their first contribution in [#5972](jdx/mise#5972)

## [2025.9.2](https://github.com/jdx/mise/compare/v2025.9.1..v2025.9.2) - 2025-09-05

### 🐛 Bug Fixes

- **(ci)** set required environment variables for npm publishing by @jdx in [#6189](jdx/mise#6189)
- **(release)** clean up extra newlines in release notes formatting by @jdx in [#6190](jdx/mise#6190)
- **(release)** add proper newline after New Contributors section in cliff template by @jdx in [#6194](jdx/mise#6194)
- **(release)** fix changelog formatting to remove extra blank lines by @jdx in [#6195](jdx/mise#6195)
- **(release)** restore proper newline after New Contributors section by @jdx in [#6196](jdx/mise#6196)

### 🚜 Refactor

- **(ci)** split release workflow into separate specialized workflows by @jdx in [#6193](jdx/mise#6193)

### Chore

- **(release)** require GitHub Actions environment for release-plz script by @jdx in [#6191](jdx/mise#6191)

## [2025.9.1](https://github.com/jdx/mise/compare/v2025.9.0..v2025.9.1) - 2025-09-05

### 🐛 Bug Fixes

- python nested venv path order by @elvismacak in [#6124](jdx/mise#6124)
- resolve immutable release workflow and VERSION file timing issues by @jdx in [#6187](jdx/mise#6187)

### New Contributors

- @elvismacak made their first contribution in [#6124](jdx/mise#6124)

## [2025.9.0](https://github.com/jdx/mise/compare/v2025.8.21..v2025.9.0) - 2025-09-05

### 🚀 Features

- allow set/unset backend aliases by @roele in [#6172](jdx/mise#6172)

### 🐛 Bug Fixes

- **(aqua)** respect order of asset_strs by @risu729 in [#6143](jdx/mise#6143)
- **(java)** treat freebsd as linux (assuming linux compatability) by @roele in [#6161](jdx/mise#6161)
- **(nushell/windows)** Fix $env.PATH getting converted to a string by @zackyancey in [#6157](jdx/mise#6157)
- **(sync)** create uv_versions_path dir if it doesn't exist by @risu729 in [#6142](jdx/mise#6142)
- **(ubi)** show relevent error messages for v-prefixed tags by @risu729 in [#6183](jdx/mise#6183)
- remove nodejs/golang alias migrate code by @risu729 in [#6141](jdx/mise#6141)
- mise activate not working on powershell v5 by @L0RD-ZER0 in [#6168](jdx/mise#6168)

### 📚 Documentation

- **(task)** remove word "additional" to avoid confusions by @risu729 in [#6159](jdx/mise#6159)

### Chore

- update Cargo.lock by @risu729 in [#6184](jdx/mise#6184)

### New Contributors

- @zackyancey made their first contribution in [#6157](jdx/mise#6157)
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.

2 participants