Skip to content

feat(hotfix): add finalize verb writing diverged state, tag, and release - #104

Merged
joshua-temple merged 3 commits into
mainfrom
feat/hotfix-finalize-verb
Jun 11, 2026
Merged

joshua-temple merged 3 commits into
mainfrom
feat/hotfix-finalize-verb

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Problem

A merged hotfix resolution leaves the integration branch ahead of the recorded
environment state. Nothing yet writes the diverged state back to trunk, mints the
hotfix version, or creates the release object, so the environment cannot rejoin
the pointer model cleanly.

Fix

Adds cascade hotfix finalize to the internal/hotfix package. After the
resolution PR merges and the build and deploy succeed, the verb:

  • cross-checks the merge SHA equals the env/<target> branch tip (fails on drift)
  • allocates the next free hotfix version: a nested vX.Y.Z-rc.N.hotfix.M segment
    for rc-based versions, or a reconciled patch bump (skipping existing tags) for
    published bases, so it never collides with the normal release sequence
  • snapshots the prior env state into the previous rollback ring (its first
    producer) and writes sha/version/ref/base_sha/patches/committed_* plus the
    build and deploy substates
  • carries base_sha forward and appends to patches when stacking a second hotfix
  • commits the manifest to trunk with the shared rebase-retry push and the
    [skip ci] convention
  • creates the hotfix tag and release object via release.Manage with a body
    recording the base version and the carried trunk commit; prerelease-env targets
    promote the release to a GitHub prerelease

The verb is idempotent on identical inputs: a rerun after the state already
records the merge SHA is a no-op (no double-applied patches, no re-snapshot).

A companion refactor extracts promote's commit-and-push-with-rebase-retry into
internal/git (CommitAndPushWithRetry, plus ListTags); promote delegates to
it so its behavior is unchanged and its existing tests stay green.

Adds regression tests in internal/release proving the RC tag and draft cleanup
paths (parseRCTag, cleanupRCTags, cleanupStaleDrafts) ignore hotfix tags.

Verification

  • go build ./...
  • go test ./... (1107 passing across 20 packages)
  • go test -race ./internal/hotfix/... ./internal/release/...
  • golangci-lint run ./internal/hotfix/... ./internal/release/... ./internal/promote/... ./internal/git/... (no issues)
  • e2e module builds (cd e2e && go build ./...)

Coverage is unit tests plus committed scratch-repo and release-stub integration
tests (plan, manual merge, finalize end to end). The act/gitea e2e for the hotfix
flow, including finalize, lands in the e2e harness unit per the implementation
plan; this PR does not wire the verb into a generated workflow yet.

Promote and hotfix finalize both write manifest state to trunk with the same commit-and-push-with-rebase-retry sequence. Extract it into internal/git as CommitAndPushWithRetry and ListTags, and have promote's CommitAndPush delegate so behavior stays identical.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
After a hotfix resolution PR merges and its build and deploy succeed, finalize cross-checks the merge SHA against the env branch tip, allocates the next free hotfix version (nested rc hotfix segment for rc-based versions, reconciled patch bump for published bases), snapshots prior state into the rollback ring, writes the divergence fields and build/deploy substates, commits the manifest to trunk, and creates the hotfix tag and release object. Prerelease-env targets promote the release to a prerelease. The verb is idempotent on identical inputs. Adds regression tests proving RC tag and draft cleanup ignore hotfix tags.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
Prior to this change, createRelease was passed prior.Version after
it had already been overwritten with the newly allocated hotfix version,
causing the release body to read "based on <hotfix>" rather than the true
pre-hotfix base version. Capture baseVersion before the mutation and pass
that instead.

Tighten the release-body test to assert the exact "based on v1.4.0-rc.2,"
phrase and assert the hotfix version does not appear in the based-on
position, so the test would have caught the original bug.

Remove the dead --repo flag from the finalize subcommand; it was wired
but never consumed and was documented as an unused placeholder.

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
@joshua-temple
joshua-temple merged commit 0e3ccc9 into main Jun 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant