Files
ReleaseKit/docs/release.md

129 lines
6.2 KiB
Markdown

# ReleaseKit release procedure
ReleaseKit's deliverables are its source tag and a hosted Gitea page containing
the complete checked-in release note. The page is delivered asynchronously by
the prepared [Woodpecker workflow](../examples/woodpecker/releasekit-source-delivery.yml);
it is not a source-release completion check and carries no binary assets. The
authoritative repository is `origin` at
`https://gitea.maximumdirect.net/eric/ReleaseKit.git`, and the release branch
is `main`. A release completes when the intended annotated tag is successfully
pushed, or when one exact-object recovery query confirms that the push
succeeded. CI and consumer installation are not completion checks.
## Prepare a candidate
Use a local Go 1.25 toolchain and a clean clone. Start on `main`, choose an
unused stable `vMAJOR.MINOR.PATCH` version, and add
`docs/releases/<version>.md` with a first heading containing `ReleaseKit` and
the exact version. Summarize the change and any compatibility or upgrade impact.
End the note with the three license links at the immutable source tag:
```markdown
[COPYRIGHT](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/vX.Y.Z/COPYRIGHT) |
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/vX.Y.Z/LICENSE) |
[ATTRIBUTION](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/vX.Y.Z/docs/oss/attribution.md)
```
Replace every `vX.Y.Z` with the selected version. These are links to the same
release note's immutable source tree and also work when the note is used as a
hosted release body.
Commit the note and all candidate changes on `main`, then publish that commit
to `origin/main`:
```sh
git push origin main
```
ReleaseKit checks that the worktree is clean, the candidate is on `main`, the
authoritative branch identifies that commit, and the version is unused locally
and on `origin`.
## Prepare dependencies, then publish
Dependency preparation is separate from the offline candidate validation. Run
it from the captured candidate source before the release command:
```sh
GOTOOLCHAIN=local go mod download
```
Then run the single publication command from the repository root:
```sh
./scripts/release vX.Y.Z
```
The committed `releasekit.json` selects the offline default test suite:
`go test -mod=readonly -count=1 ./...`, with toolchain and module network
access disabled for validation. The command validates once, checks the
authoritative remote state, creates a local annotated tag from the captured
candidate and checked-in note, rechecks the tag and remote guards, and pushes
only that tag object. It prints the published version, commit, and tag object
on success. Exit status 0 means publication is confirmed; status 1 means a
known failure or conflict; status 2 means invalid input or profile; status 3
means the push outcome remains unknown and requires resolution.
The wrapper builds the native CLI into ignored `.releasekit/bin`, then invokes
it directly to preserve its exit status. The CLI comes from the source tree
being published, so this command also works
for ReleaseKit's first release before any released ReleaseKit executable
exists. It uses the local Go toolchain. Preparation must finish before the
offline validation begins.
## Resolve failures
A failed push triggers one exact authoritative tag query. An exact tag-object
match confirms publication even when Git reported an error. A proven absent tag
is `not_published`; a different object is a conflict; an unreadable query is
`unknown`. The command retains its local tag and reports the state, phase,
candidate commit, tag object, and captured publication endpoint when available.
Do not retry an unknown result until you resolve the authoritative ref at that
exact endpoint. Copy the reported endpoint value into the variable below using
normal shell quoting; retain the version and tag object from the same result.
Check that Git URL rewriting still resolves this value to itself before querying:
```sh
releasekit_endpoint='COPY_CAPTURED_ENDPOINT'
releasekit_version='vX.Y.Z'
test "$(git ls-remote --get-url -- "$releasekit_endpoint")" = "$releasekit_endpoint"
git ls-remote --refs -- "$releasekit_endpoint" "refs/tags/$releasekit_version"
```
A failed URL-equality check or remote query leaves the outcome unresolved.
Correct transport configuration before continuing. The reported endpoint may
be different from `origin`'s fetch URL or its current push URL; querying either
of those does not establish absence at the captured endpoint.
Compare the returned object ID with the tag object reported by the command.
An exact match confirms publication. If the ref is absent, the version was not
published; only then may you deliberately remove the unpublished local tag
with `git tag -d vX.Y.Z` before correcting the candidate or retrying. Do not
move, overwrite, or delete a tag that exists remotely. If a different object
uses the version, choose a new version after resolving the conflict.
If validation or a guard fails before this invocation pushes, correct and
commit the candidate, publish `main`, and run the command again. A retained
local tag still requires the authoritative-state check above before removal;
a concurrent publisher may already have published the version. The prepared Woodpecker workflow builds the CLI from the tagged
checkout and runs page-only delivery. To activate it after configuring the
destination and secret, copy it to `.woodpecker/releasekit-source-delivery.yml`
and add the Woodpecker repository secret `releasekit_gitea_token`. If page
delivery fails or is uncertain, inspect the hosted release and retry the same
immutable version from its tag:
```sh
git fetch origin "refs/tags/vX.Y.Z:refs/tags/vX.Y.Z"
git checkout --detach "vX.Y.Z"
mkdir -p .releasekit/bin
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go build -o .releasekit/bin/releasekit ./cmd/releasekit
RELEASEKIT_GITEA_TOKEN="$GITEA_TOKEN" .releasekit/bin/releasekit deliver "vX.Y.Z"
```
The root ignore file excludes `.releasekit/`. Delivery uses the committed note
and does not build consumer binaries, create a checksum manifest, or require a
previously released ReleaseKit executable. Keep source publication and hosted
page delivery status separate; retry only after resolving an uncertain remote
write. The workflow secret is named `releasekit_gitea_token` and is mapped to
`RELEASEKIT_GITEA_TOKEN` only in the delivery step.