mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
fix(scripts/release): promote stable on immutable releases (#30745)
## Problem `./scripts/release_promote_stable.sh v2.37.4` failed today with: ``` edit release failed: PATCH https://api.github.com/repos/coder/coder/releases/403906567: 404 Not Found ``` Releases on this repo are immutable (`gh release view v2.37.4 --json isImmutable` → `true`). `promoteVersionToStable` cloned the entire `RepositoryRelease` into `EditRelease`, so the PATCH carried `tag_name`, `target_commitish` and the assets. GitHub rejects that on an immutable release even when the values are unchanged, and answers 404 rather than 422. The same edit with only `body`, `prerelease` and `make_latest` succeeds (that's how v2.37.4 was promoted by hand). ## Change - Build a minimal `RepositoryRelease{Body, Prerelease, MakeLatest}` for the edit. - Drop the `Draft: false` assignment (published releases are never drafts, and `draft` is not an editable field on immutable releases). - Dry-run now logs the body diff instead of a diff of the whole object. - Remove the now-unused `cloneRelease` helper. Verified with `go test ./scripts/release/` and a `promote --dry-run` against v2.36.7. Every release published since immutable releases were enabled is affected, so without this the command cannot promote anything. Related: the release-process review notes that this step is also missing from the runbook and should become a workflow job on every `.0` mainline release. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
+12
-14
@@ -236,33 +236,31 @@ func (r *releaseCommand) promoteVersionToStable(ctx context.Context, inv *serpen
|
||||
|
||||
logger.Info(ctx, "promoting selected version to stable")
|
||||
|
||||
// Update the release to latest.
|
||||
updatedNewStable := cloneRelease(newStable)
|
||||
|
||||
// Update the release to latest. Only send the fields we change:
|
||||
// releases on this repo are immutable, and GitHub rejects an edit
|
||||
// that carries the tag, target commitish or assets of an immutable
|
||||
// release (it answers 404 Not Found), even when those values are
|
||||
// unchanged. Body, prerelease and make_latest remain editable.
|
||||
updatedBody := removeMainlineBlurb(newStable.GetBody())
|
||||
updatedBody = addStableSince(time.Now().UTC(), updatedBody)
|
||||
updatedNewStable.Body = github.String(updatedBody)
|
||||
updatedNewStable.MakeLatest = github.String("true")
|
||||
updatedNewStable.Prerelease = github.Bool(false)
|
||||
updatedNewStable.Draft = github.Bool(false)
|
||||
edit := &github.RepositoryRelease{
|
||||
Body: github.String(updatedBody),
|
||||
MakeLatest: github.String("true"),
|
||||
Prerelease: github.Bool(false),
|
||||
}
|
||||
if !r.dryRun {
|
||||
_, _, err = client.Repositories.EditRelease(ctx, owner, repo, newStable.GetID(), updatedNewStable)
|
||||
_, _, err = client.Repositories.EditRelease(ctx, owner, repo, newStable.GetID(), edit)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("edit release failed: %w", err)
|
||||
}
|
||||
logger.Info(ctx, "selected version promoted to stable", slog.F("url", newStable.GetHTMLURL()))
|
||||
} else {
|
||||
logger.Info(ctx, "dry-run: release not updated", slog.F("uncommitted_changes", cmp.Diff(newStable, updatedNewStable)))
|
||||
logger.Info(ctx, "dry-run: release not updated", slog.F("body_diff", cmp.Diff(newStable.GetBody(), updatedBody)))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cloneRelease(r *github.RepositoryRelease) *github.RepositoryRelease {
|
||||
rr := *r
|
||||
return &rr
|
||||
}
|
||||
|
||||
// addStableSince adds a stable since note to the release body.
|
||||
//
|
||||
// Example:
|
||||
|
||||
Reference in New Issue
Block a user