199 lines
11 KiB
Markdown
199 lines
11 KiB
Markdown
# CommandKit release procedure
|
||
|
||
## Scope and release order
|
||
|
||
CommandKit publishes source-only Go module releases. Each module has an
|
||
independent version and immutable annotated tag. A successful source-tag push
|
||
completes the source release. A separate local delivery command can publish a
|
||
Gitea release page; there are no binaries,
|
||
checksums, or other delivery assets. CI, module proxy availability, and consumer
|
||
installation are not completion gates.
|
||
|
||
Publish in dependency order: core, then `ckconfig`, then `ckprompt`. The
|
||
integration modules require the preceding CommandKit releases, so prepare and
|
||
publish each module only after its CommandKit dependencies are available. A root
|
||
release runs only the root module's default suite; it need not run suites for
|
||
independently released integrations.
|
||
|
||
Use branch `main`, remote `origin`, and expected effective push endpoint
|
||
`ssh://git@forge.maximumdirect.net:22222/base-layer/commandkit.git`. The selected
|
||
module profile enforces the endpoint. The maintainer needs the selected
|
||
[release toolchain](#release-toolchain), Git push access, and a POSIX shell.
|
||
This procedure follows the [release policy](policy/release.md); release-note
|
||
footers follow the [OSS discoverability policy](policy/oss.md#discoverability).
|
||
|
||
ReleaseKit v0.9.0 (`go.maximumdirect.net/releasekit`) owns candidate validation,
|
||
publication guards, tag creation, tag publication, and outcome reporting.
|
||
Its pinned public contracts are the
|
||
[CLI reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/cli.md),
|
||
[profile reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/config.md),
|
||
the [publication guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/publish.md),
|
||
and the [delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/delivery.md).
|
||
The repository selects one default module suite per invocation. The launcher
|
||
uses the root module’s registered tool with native host settings and read-only
|
||
module metadata.
|
||
|
||
## Release toolchain
|
||
|
||
The selected release toolchain is **Go 1.27.0**. Core and ckprompt declare a
|
||
consumer minimum of **Go 1.26.0**; ckconfig requires **Go 1.27.0**. Maintainers
|
||
use Go 1.27.0 for dependency preparation, candidate validation, and ReleaseKit
|
||
execution. The
|
||
[consumer guide](consumers/guide.md#go-compatibility) and
|
||
[release policy](policy/release.md#consumer-minimum-and-release-toolchain)
|
||
describe these selections.
|
||
|
||
Select Go 1.27.0 on `PATH`; the launcher uses `GOTOOLCHAIN=local`. If needed,
|
||
install it with the standard Go tools:
|
||
|
||
```sh
|
||
GOWORK=off GOTOOLCHAIN=local go install golang.org/dl/go1.27.0@latest
|
||
go1.27.0 download
|
||
export PATH="$(go1.27.0 env GOROOT)/bin:$PATH"
|
||
hash -r
|
||
GOWORK=off GOTOOLCHAIN=local go version
|
||
```
|
||
|
||
## Modules, versions, notes, and shared files
|
||
|
||
Select exactly one module with the launcher:
|
||
|
||
| Selector | Physical module directory | Release note | Full tag |
|
||
| --- | --- | --- | --- |
|
||
| `core` | repository root | `docs/releases/<version>.md` | `<version>` |
|
||
| `ckconfig` | `integrations/ckconfig` | `integrations/ckconfig/docs/releases/<version>.md` | `integrations/ckconfig/<version>` |
|
||
| `ckprompt` | `integrations/ckprompt` | `integrations/ckprompt/docs/releases/<version>.md` | `integrations/ckprompt/<version>` |
|
||
|
||
Use a fresh stable semantic version (`vMAJOR.MINOR.PATCH`) for the selected
|
||
module. Before `v1.0.0`, a minor release may change a documented contract when
|
||
its note explains the impact and consumer action. Never reuse a published
|
||
version. Each release note starts with a product title and exact version, gives
|
||
a proportionate summary and compatibility guidance, and ends with immutable
|
||
links to that module's local grant, license, and attribution paths. The full tag
|
||
in each URL includes the integration directory where applicable. For future
|
||
notes, use `https://forge.maximumdirect.net/base-layer/commandkit/src/tag/FULL_TAG/`
|
||
followed by the repository-relative path: `COPYRIGHT`, `LICENSE`, and
|
||
`docs/oss/attribution.md` for core, or those paths prefixed with the selected
|
||
integration directory. Future tag URLs need not resolve before publication.
|
||
|
||
All three release profiles explicitly select the repository-root `COPYRIGHT`,
|
||
`LICENSE`, and `docs/oss/attribution.md` through `validation.shared_files`.
|
||
ReleaseKit requires these committed files to exist in the candidate. The list
|
||
does not expand Go validation scope; see the pinned [profile reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/config.md).
|
||
|
||
Each integration also distributes its own `COPYRIGHT`, `LICENSE`, and
|
||
`docs/oss/attribution.md`. These module-local materials are separate from the
|
||
explicit root shared-file list and remain subject to the [OSS policy](policy/oss.md).
|
||
Automatic module file inputs include applicable module-local files and stop at
|
||
independent nested-module boundaries. Their inclusion does not itself enable
|
||
license or content validation.
|
||
|
||
Each profile selects Go formatting, Markdown links, workspace-file and local
|
||
replacement checks, and forbids the committed `.releasekit/gitea-token` path.
|
||
These upstream checks inspect committed inputs; module file selection stops at
|
||
independent module boundaries, while the forbidden path covers the repository.
|
||
They do not replace domain review. Publication also runs the selected module’s
|
||
standard offline suite and ReleaseKit’s candidate/note and publication guards.
|
||
|
||
## Prepare and publish one candidate
|
||
|
||
Prepare dependencies in the selected module before the candidate is finalized.
|
||
Do this after the preceding CommandKit module has been published and before the
|
||
selected candidate suite is run. For `core`, run the command at the repository
|
||
root; for integrations, run it from that module directory. Commit any resulting
|
||
`go.mod` or `go.sum` changes with the release candidate. The sum files must
|
||
reflect dependencies actually downloaded for that module; do not fabricate
|
||
future sums.
|
||
|
||
Then commit the selected module's release note and all intended candidate
|
||
changes on `main`, and publish the candidate commit to `origin`. Set one
|
||
module directory and version from the table above, then run the corresponding
|
||
publication command:
|
||
|
||
```sh
|
||
module_dir=.
|
||
(cd "$module_dir" && GOWORK=off GOTOOLCHAIN=local go mod download)
|
||
# Commit reviewed dependency changes and the selected module's note on main.
|
||
git push origin HEAD:refs/heads/main
|
||
./scripts/release core vX.Y.Z
|
||
# For integrations use: ./scripts/release ckconfig vX.Y.Z
|
||
# or: ./scripts/release ckprompt vX.Y.Z
|
||
```
|
||
|
||
Run only the command for the selected module. Its profile runs the complete
|
||
offline deterministic default suite once for that module, checks candidate and
|
||
remote guards, creates the annotated tag from the matching note, and pushes
|
||
only that full tag. `./scripts/releasekit core check vX.Y.Z` is an optional
|
||
diagnostic, not a required pre-publication step: publication repeats validation.
|
||
Use the relevant integration selector and its version when diagnosing that
|
||
module. Inspect the registered tool with `./scripts/releasekit version`. The
|
||
launcher does not push `main`; publish the
|
||
candidate commit first. Successful source publication does not wait for CI,
|
||
proxy availability, or downstream installation.
|
||
|
||
## Completion and ambiguous publication
|
||
|
||
A successful push to the expected endpoint completes the source release.
|
||
ReleaseKit also attempts to save private publication evidence under the
|
||
repository's Git common directory, shared by linked worktrees. It reports the
|
||
saved record path or a recording warning separately from publication status;
|
||
a storage failure does not change publication status. Records can contain
|
||
credential-bearing endpoints. Retain them privately while recovery is needed
|
||
and remove them when their recovery value expires; retention is maintainer-owned.
|
||
|
||
On an ambiguous result, use the recovery command printed for that invocation's
|
||
saved record. To discover records and explicitly select the matching attempt,
|
||
the shared helper can also be used:
|
||
|
||
```sh
|
||
./scripts/releasekit publication-attempts
|
||
./scripts/releasekit reconcile --record /absolute/path/to/attempt.json
|
||
```
|
||
|
||
Replace the example record path with the saved path for the intended attempt.
|
||
Relative record paths resolve from the repository root.
|
||
Discovery lists local evidence without querying remotes or selecting an attempt.
|
||
Reconciliation observes the recorded endpoint, full tag, and tag object without
|
||
rerunning candidate validation or changing tags. It distinguishes confirmed
|
||
publication, current absence, conflict, and an unresolved observation. Current
|
||
absence does not prove that a version was never published. The pinned
|
||
[CLI reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/cli.md#recover-a-saved-publication-attempt-or-discover-local-attempts)
|
||
owns recovery statuses and structured output; the
|
||
[publication guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/publish.md#retain-and-reconcile-publication-evidence)
|
||
describes record storage and recovery entry points.
|
||
|
||
If no usable record was saved, use the exact endpoint, full tag, and annotated
|
||
tag object reported by that invocation. Query only that exact tag ref at the
|
||
captured endpoint. An exact tag-object match confirms publication, a different
|
||
object is a conflict, successful output without the ref shows current absence,
|
||
and a failed query leaves the result unresolved. Do not infer the captured
|
||
endpoint's state from another remote or a rewritten URL. Resolve unknown
|
||
publication state before retrying.
|
||
|
||
ReleaseKit may retain a local tag after a failed push. Remove an unpublished
|
||
local tag only after proving absence at the captured endpoint and confirming
|
||
that the tag was never published or used by another release channel. Never
|
||
move, overwrite, recreate, or delete a published tag. Resolve conflicts with a
|
||
fresh version; corrections to published source require a new version.
|
||
|
||
## Hosted delivery
|
||
|
||
After source publication, check out the original tagged source with a clean
|
||
worktree and index, then deliver the selected module's page:
|
||
|
||
```sh
|
||
./scripts/releasekit core deliver vX.Y.Z
|
||
# Or use ckconfig or ckprompt with that module's semantic version.
|
||
```
|
||
|
||
The profile derives the full module-specific tag from the version. Delivery
|
||
uses the checked-in release note as a page-only body and reports its own outcome
|
||
and URL separately from source publication. Retry later from the same original
|
||
tagged source. The pinned [delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/docs/consumers/delivery.md)
|
||
owns delivery and retry behavior.
|
||
|
||
A nonblank `RELEASEKIT_GITEA_TOKEN` takes precedence over the repository-relative
|
||
`.releasekit/gitea-token` file. Keep the credential directory ignored and retain
|
||
its local contents. Credentials and Gitea availability do not gate source
|
||
publication.
|