Files
releasekit/docs/release.md

216 lines
10 KiB
Markdown
Raw Permalink Normal View History

# ReleaseKit release procedure
ReleaseKit's deliverables are its source tag and a hosted Gitea page containing
the complete checked-in release note. Deliver the page locally after publication
or asynchronously through the prepared
[Woodpecker workflow](../examples/woodpecker/releasekit-source-delivery.yml).
Hosted-page delivery has a separate status from source-release completion and
carries no binary assets. The authoritative repository is `origin` at
`ssh://git@forge.maximumdirect.net:22222/base-layer/releasekit.git`, and the release
branch is `main`. The hosted Gitea destination is
`https://forge.maximumdirect.net/base-layer/releasekit`. 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
For local hosted-page delivery, save a Gitea personal access token in
`.releasekit/gitea-token` with owner-only file permissions. The file contains
only the token. ReleaseKit's profile selects this file as a fallback to
`RELEASEKIT_GITEA_TOKEN`; `.releasekit/` is already ignored. Its optional
`validation.forbidden_files` selection checks that this path is absent from the
committed candidate. Source publication requires no delivery token. The
[configuration reference](config.md) owns credential selection and validator
semantics.
Use a clean clone on `main`. The chosen build toolchain is Go 1.26.10. Make that
local installation the active `go` command for preparation, building the release
executable, and candidate validation:
```sh
export GOTOOLCHAIN=local
go version
```
Record the reported version with the validation results. The
[Go support policy](policy/release.md#consumer-minimum-and-release-toolchain) owns
series selection, consumer minima, patch exceptions, and validation scope.
The maintained [source-delivery image](../examples/woodpecker/releasekit-source-delivery.yml)
and [consumer template image](../examples/woodpecker/tag-delivery.yml) follow the
chosen build toolchain; update them together when that selection changes.
2026-10-10 04:03:42 +00:00
The current consumer minimum is Go 1.26.0, declared in [go.mod](../go.mod).
Keep it for a release unless release preparation deliberately selects a newer
series under the [Go support policy](policy/release.md#consumer-minimum-and-release-toolchain).
When increasing it, update `go.mod` to the first stable version of the selected
series, or to a higher patch when a dependency or specific fix requires one.
Make module changes before committing the candidate. Minimum increases must fit the
[compatibility policy](policy/release.md#versioning-and-compatibility); before
v1.0.0, an increase belongs in a minor release.
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://forge.maximumdirect.net/base-layer/releasekit/src/tag/vX.Y.Z/COPYRIGHT) |
[LICENSE](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/vX.Y.Z/LICENSE) |
[ATTRIBUTION](https://forge.maximumdirect.net/base-layer/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
```
2026-10-06 17:15:46 +00:00
The command always runs the offline default test suite,
`go test -mod=readonly -count=1 ./...`, with toolchain and module network
2026-10-06 17:15:46 +00:00
access disabled. Any profile `checks` run afterward as additional product
checks; they should not repeat the standard suite. The command 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.
## Deliver the hosted release page
After source publication succeeds, deliver the hosted page locally when
Woodpecker automation is inactive. From the same repository root, keep the
worktree clean and `HEAD` at the published tag's commit. Reuse the executable
built by the publication command:
```sh
.releasekit/bin/releasekit deliver vX.Y.Z
```
The command uses the configured Gitea destination and token source to deliver
the complete checked-in release note. Report its result separately from the
completed source release. For failed or uncertain delivery, follow the recovery
instructions below using the same immutable version.
2026-11-02 19:37:29 +00:00
## Resolve publication failures
Each publication invocation attempts to save its captured identity before the
tag push. The CLI reports the saved record path separately from publication
success or failure and, after a push or immediate-reconciliation error, prints a
copyable command that selects that exact record. Run that command, or use the
source-built executable prepared above, to make a separate later observation:
```sh
./.releasekit/bin/releasekit reconcile --record '/absolute/path/to/attempt-record.json'
```
2026-11-02 19:37:29 +00:00
The saved evidence fixes the original endpoint and tag identity. Later recovery
uses current supported transport settings for the recorded remote name, but it
does not substitute the current remote URL, inspect the local tag or current
HEAD, load a profile, rerun checks, or change repository state. A completed
observation reports `published`, `not_published`, or `conflict`; an incomplete
observation reports `unknown` with diagnostic context. Resolve an unknown result
by correcting the identified endpoint rewrite, transport configuration, or
missing evidence. For incomplete saved identity, select another record with the
required fields or use complete typed evidence through the Go API.
If command output was lost, list local attempts and explicitly select the
matching record by its module, full tag, and saved identity:
2026-11-02 19:37:29 +00:00
```sh
./.releasekit/bin/releasekit publication-attempts --repo "$PWD"
./.releasekit/bin/releasekit reconcile --record '/absolute/path/from-the-list/attempt-record.json'
2026-11-02 19:37:29 +00:00
```
2026-11-02 19:37:29 +00:00
Discovery only reads the local store. It neither queries remotes nor chooses an
attempt automatically. If the original recovery entry point is unavailable,
select another supported ReleaseKit CLI and pass the same record path explicitly.
An older record may lack the endpoint, tag-object ID, candidate commit, or
another field required for a conclusive result.
2026-11-02 19:37:29 +00:00
A later observation that the tag is absent describes the remote at that time;
it does not prove the version was never published. Never reuse a version known
to have been published, and preserve published tags and contents as immutable.
Keep removal of an unpublished local tag, candidate correction, and retry as
explicit operator decisions after reviewing the record and authoritative
remote state. A conflicting object requires resolving the conflict and selecting
an unused version when appropriate; do not move, overwrite, or delete a
published tag.
If record storage fails, ReleaseKit reports the recording warning separately;
the warning does not change the actual publication outcome. The saved handoff is
then unavailable. A Go caller that retained `PublicationResult.Evidence` can
still pass that typed evidence directly to `ReconcilePublication`. Process
termination before the record is written, removed storage, and older incomplete
records can leave no sufficient saved evidence for later recovery.
Later reconciliation adds no successful-push read-back, polling, CI, consumer
installation, or hosted-delivery gate. Hosted page delivery remains separate.
If validation or a guard fails before this invocation pushes, correct and
commit the candidate, publish `main`, and run the command again. A retained
2026-11-02 19:37:29 +00:00
local tag still requires reviewing the selected record and authoritative state
before deciding whether to remove it. The prepared
Woodpecker workflow builds the CLI from the tagged checkout, then uses
`ci-deliver` for 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"
GOTOOLCHAIN=local go mod download
mkdir -p .releasekit/bin
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go build -o .releasekit/bin/releasekit ./cmd/releasekit
.releasekit/bin/releasekit deliver "vX.Y.Z"
```
For an older tag whose CLI predates `token_file`, supply the token through its
environment variable when retrying that tagged tool:
```sh
RELEASEKIT_GITEA_TOKEN="$(cat .releasekit/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.