307 lines
16 KiB
Markdown
307 lines
16 KiB
Markdown
# Deliver a tagged source release
|
|
|
|
Use `releasekit.Deliver` or the `deliver` command after a source tag exists.
|
|
Delivery status is separate from source publication: a delivery problem does
|
|
not move or remove the tag, and a retry can use the same immutable version.
|
|
The operation accepts historical lightweight and annotated tags, including a
|
|
detached checkout, when the checked-out `HEAD` identifies the selected tag
|
|
commit. It does not require the old remote `main` to match.
|
|
|
|
Delivery resolves the selected module's declaration and release note from the
|
|
captured commit. `Version` remains the semantic version; the full tag includes
|
|
the selected module's repository-relative physical path when it is nested. The
|
|
profile or API request selects the physical module directory. The optional API
|
|
`ExpectedTag` checks that a CI event's literal tag agrees with the derived tag
|
|
before any build or hosted request.
|
|
|
|
## CI preparation
|
|
|
|
Use `PrepareTaggedCheckout` when a disposable CI checkout must be verified
|
|
against the commit that triggered the job. It fetches only the selected tag
|
|
from the chosen remote (default `origin`), compares the peeled tag commit with
|
|
the expected commit, and checks out that commit detached. Fetch or checkout
|
|
conflicts are returned so the caller can replace or repair the workspace.
|
|
Cancellation is returned to the caller; the operation does not publish a tag
|
|
or hosted content.
|
|
|
|
```go
|
|
err := releasekit.PrepareTaggedCheckout(ctx, releasekit.TaggedCheckoutRequest{
|
|
RepositoryDir: repositoryDir,
|
|
Tag: "integrations/example/v1.2.3",
|
|
ExpectedCommit: ciCommit,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
```
|
|
|
|
For binary profiles, call `PrepareBuildDependencies` with a
|
|
`DependencyPreparationRequest` selecting the repository and module after
|
|
checkout preparation and before delivery. It runs `go mod download` in that
|
|
module with workspace discovery disabled and the available compatible local Go
|
|
toolchain.
|
|
The operation may use the network and updates the Go module cache while
|
|
preserving the caller's proxy, private-module, credential, and cache settings.
|
|
If checksums are missing, Go may update `go.sum`. For binary CI delivery, prepare
|
|
and commit the selected module's `go.sum` before tagging: delivery verifies the
|
|
tagged source remains clean after dependency preparation. See the
|
|
[Go Modules Reference](https://go.dev/ref/mod#go-mod-download). Cancellation
|
|
and command errors are returned. Page-only profiles do not need dependency
|
|
preparation.
|
|
|
|
Set `TaggedCheckoutRequest.VerifyOnly` when a bootstrap step already fetched and
|
|
detached the event tag. This mode checks the exact tag, expected commit, `HEAD`,
|
|
and clean worktree without fetching or changing the checkout. Both modes require
|
|
the full `Tag` and expected commit.
|
|
|
|
## Command line
|
|
|
|
Add a Gitea destination to the profile:
|
|
|
|
```json
|
|
{
|
|
"product": "Example",
|
|
"delivery": {
|
|
"base_url": "https://gitea.example",
|
|
"owner": "example",
|
|
"repository": "example",
|
|
"token_env": "RELEASEKIT_GITEA_TOKEN"
|
|
}
|
|
}
|
|
```
|
|
|
|
Fetch and check out the immutable tag, then deliver it:
|
|
|
|
```sh
|
|
git checkout --detach v1.2.3
|
|
RELEASEKIT_GITEA_TOKEN="$GITEA_TOKEN" releasekit deliver v1.2.3
|
|
```
|
|
|
|
The CLI reads the named token variable only for `deliver`; its default name is
|
|
`RELEASEKIT_GITEA_TOKEN`. It verifies the local checkout and hosted tag before
|
|
creating or accepting a hosted release page. The full checked-in note is the
|
|
hosted body. A retry accepts an identical page and matching attachments, adds
|
|
only missing assets, and reports conflicts without replacing content.
|
|
For nested modules, the note comes from that module's committed
|
|
`docs/releases/<version>.md`, and the hosted page is keyed by its complete tag.
|
|
|
|
With no build targets, delivery is page-only: no builder, version smoke check,
|
|
receipt, binary asset, or checksum manifest is involved. Committed module
|
|
directories and declaration links can be resolved from a sparse checkout;
|
|
page-only delivery needs the committed objects and note. Managed builds require
|
|
the selected source files to be materialized. With selected targets,
|
|
one `deliver` invocation builds the tagged source through the facade into
|
|
temporary storage and delivers the result. To retain artifacts for a retry or
|
|
separate credentials between build and delivery, use two invocations:
|
|
|
|
```sh
|
|
releasekit build --output dist v1.2.3
|
|
RELEASEKIT_GITEA_TOKEN="$GITEA_TOKEN" releasekit deliver --assets dist v1.2.3
|
|
```
|
|
|
|
The build command does not need delivery credentials. The `--assets DIR`
|
|
directory must contain the private `.releasekit-build.json` receipt created by
|
|
`build`. ReleaseKit checks its schema, repository, commit, version, resolved
|
|
module directory and path, full tag, normalized build settings, and artifact
|
|
declarations. Old receipts must be regenerated with the updated `build`
|
|
command. Delivery verifies the artifact bytes and sizes before making a hosted
|
|
request; caller-owned files remain available for retries.
|
|
Ordinary `deliver` does not download application dependencies or change the
|
|
checkout.
|
|
|
|
The result reports `complete`, `partial`, `conflict`, `unknown`, or
|
|
`not_attempted`, along with matching, uploaded, pending, conflicting, and
|
|
uncertain assets when known. These are disjoint current observations: an asset
|
|
appears in at most one category, and early failures may leave some declared
|
|
assets unreported. `Matching` means existing content matches; `Uploaded` means
|
|
an upload was confirmed during this invocation; `Pending` means known missing
|
|
work; `Conflicting` means different hosted content was found; `Uncertain` means
|
|
the remote state could not be resolved.
|
|
|
|
Fix local or preflight failures before retrying. For partial delivery, fix the
|
|
reported cause and retry the same version. Resolve an unknown remote outcome
|
|
before retrying. Investigate conflicts and use a new version if the source or
|
|
published content needs correction. If rebuilding could change bytes already
|
|
on the server, retain the original build output and retry with `--assets DIR`.
|
|
The command does not run candidate checks or publish tags.
|
|
|
|
## Go API
|
|
|
|
Pass the Gitea credential explicitly. Set `Build` to a `BuildSpec` to compile
|
|
selected targets as part of delivery. The facade verifies the local tag, clean
|
|
checkout, and committed release note before compiling. Managed output is stored
|
|
outside the checkout and removed when delivery returns. `Output` receives build
|
|
progress. With no build, or with an empty target set, delivery is page-only.
|
|
|
|
To deliver binaries built separately, set `Prebuilt` to the `BuildResult`.
|
|
ReleaseKit checks its repository, module directory, declared module path, full
|
|
tag, semantic version, tagged commit, normalized settings, and artifact evidence
|
|
against the selected committed module. Binary results must record verified
|
|
source. The current files are checked against their recorded digests before any
|
|
hosted request. The files remain caller-owned, so callers can retain the
|
|
original bytes for retries and are responsible for cleanup. With neither
|
|
artifact source, an empty managed target set, or a matching empty prebuilt
|
|
result, delivery is page-only. Do not set both `Build` and `Prebuilt` in one
|
|
request.
|
|
|
|
```go
|
|
result, err := releasekit.Deliver(ctx, releasekit.DeliveryRequest{
|
|
RepositoryDir: "/work/example",
|
|
ModuleDir: "integrations/example",
|
|
Product: "Example",
|
|
Version: "v1.2.3",
|
|
ExpectedTag: "integrations/example/v1.2.3", // optional CI event check
|
|
Destination: releasekit.GiteaDestination{
|
|
BaseURL: "https://gitea.example",
|
|
Owner: "example",
|
|
Repository: "example",
|
|
Token: token,
|
|
},
|
|
Build: &releasekit.BuildSpec{
|
|
MainPackage: "./cmd/example",
|
|
BinaryName: "example",
|
|
Targets: []releasekit.Target{{OS: "linux", Arch: "amd64"}},
|
|
},
|
|
})
|
|
if err != nil {
|
|
// Keep the returned state and any completed asset identities for recovery.
|
|
return err
|
|
}
|
|
fmt.Println(result.State, result.ReleaseURL)
|
|
```
|
|
|
|
See the [CLI contract](../cli.md), [configuration reference](../config.md),
|
|
and [Gitea integration guide](../integrations/gitea.md) for exact settings,
|
|
exit codes, and transport behavior.
|
|
|
|
## Woodpecker tag workflows
|
|
|
|
Use the maintained [tag-delivery workflow](../../examples/woodpecker/tag-delivery.yml)
|
|
in the consumer repository's `.woodpecker/` directory. Set `GO_IMAGE` to an
|
|
image with Git and a Go toolchain compatible with the consumer module and its
|
|
selected ReleaseKit version. Choose the patch used for the consumer's release
|
|
build and validation. The template uses `GOTOOLCHAIN=local`; Go does not download
|
|
a different toolchain. The tag's `go.mod` must select ReleaseKit as a module
|
|
dependency. For CLI-only consumers, use the versioned Go tool dependency
|
|
described in the [adoption guide](adoption.md). Ordinary package dependencies
|
|
also work with this template.
|
|
Configure the Woodpecker repository secret `releasekit_gitea_token`; the
|
|
template maps it to `RELEASEKIT_GITEA_TOKEN` for delivery. The repository needs
|
|
a `delivery` profile. Page-only and binary behavior both use this template; the
|
|
profile's build target list selects whether application binaries are built and
|
|
delivered.
|
|
|
|
Before running Go, the template fetches the explicit event tag, compares its
|
|
peeled commit with the provider's full commit ID without regard to hex case,
|
|
checks out that commit detached, and confirms the source tree is clean. It then
|
|
copies the tagged `go.mod` and any `go.sum` to a temporary directory outside
|
|
the checkout. `go list -m` confirms that the module selects ReleaseKit; Go uses
|
|
an alternate `-modfile` to prepare dependencies and build the selected
|
|
`cmd/releasekit` package without changing the tagged module files. The template
|
|
invokes that executable with `CI_WORKSPACE`, `CI_COMMIT_SHA`, and
|
|
`CI_COMMIT_TAG`. A cleanup trap removes the temporary metadata and executable.
|
|
|
|
Tool bootstrap and application artifact preparation are separate. The bootstrap
|
|
resolves and builds ReleaseKit from the tagged consumer's module configuration.
|
|
After the workflow verifies and checks out the event tag, the resulting CLI uses
|
|
`ci-deliver --prepared` to repeat the tag, commit, HEAD, and cleanliness checks
|
|
without another fetch or checkout. It loads the tagged profile and downloads
|
|
application dependencies only when build targets are selected; it builds and
|
|
delivers those targets with the note page. Source-only profiles skip application
|
|
dependency downloads and binary work. Dependency preparation for binaries may
|
|
use the network. Prepare and commit the selected module's `go.sum` before
|
|
tagging; an uncommitted change makes the later delivery source check fail. A
|
|
retry still uses the same immutable tag and that tag's module settings, even
|
|
after the default branch selects a newer ReleaseKit version.
|
|
|
|
The root-only [`tag-delivery.yml`](../../examples/woodpecker/tag-delivery.yml)
|
|
keeps the small default profile and root-module bootstrap. For consumers that
|
|
release several modules from one repository, copy the contents of the maintained
|
|
[multi-module example](../../examples/multi-module/) to the consumer repository
|
|
root and use its [`woodpecker.yml`](../../examples/multi-module/woodpecker.yml),
|
|
[`release-modules.tsv`](../../examples/multi-module/release-modules.tsv), and
|
|
shared selector. The event tag chooses one row from the tagged checkout; the
|
|
profile and physical module must agree, and ReleaseKit verifies the derived tag.
|
|
The example covers source-only integration pages and a binary core module.
|
|
|
|
If the application does not declare ReleaseKit as a module dependency, install
|
|
the executable separately and invoke the same `ci-deliver` command. For
|
|
ReleaseKit's own source workflow, the maintained
|
|
[source-delivery template](../../examples/woodpecker/releasekit-source-delivery.yml)
|
|
checks out the tag and self-bootstraps `./cmd/releasekit` into temporary storage.
|
|
Its readonly tool build uses committed module metadata and can fetch missing
|
|
dependencies through normal Go proxy, private-module, checksum, and cache
|
|
settings. Tool bootstrap follows tag verification; offline candidate validation
|
|
and application artifact compilation retain their separate environments.
|
|
|
|
The normal Go module and build caches are sufficient. Cache mounts may be added
|
|
as deployment configuration when they help the runner; they are not needed by
|
|
the template. A separately installed executable can be installed with
|
|
`go install gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@PIN`, then run
|
|
with the same arguments:
|
|
|
|
```sh
|
|
releasekit ci-deliver --repo "$CI_WORKSPACE" --commit "$CI_COMMIT_SHA" "$CI_COMMIT_TAG"
|
|
```
|
|
|
|
The module-based workflow follows the ReleaseKit version selected by the tagged
|
|
consumer's `go.mod`, so retries use that source's original selection. Update the
|
|
consumer module configuration when adopting a newer ReleaseKit version and
|
|
verify it with a tag fixture. The command and profile behavior are documented
|
|
in the [CLI contract](../cli.md) and [configuration reference](../config.md).
|
|
|
|
Woodpecker runs delivery after the tag event, independently from the source
|
|
publication result. Read its workflow status as delivery status: a delivery
|
|
failure does not undo source publication. A failed, partial, or uncertain run
|
|
can be inspected and retried against the same immutable tag and commit; do not
|
|
move the tag to make a retry pass. See
|
|
[Woodpecker's environment reference](https://woodpecker-ci.org/docs/usage/environment)
|
|
for runner-provided tag and commit variables and
|
|
[workflow syntax](https://woodpecker-ci.org/docs/usage/workflow-syntax) for tag
|
|
events, sequential steps, and the shared workspace.
|
|
|
|
## Investigating module checksum mismatches
|
|
|
|
During tool installation or dependency preparation, a checksum mismatch means
|
|
the bytes Go read differ from a recorded checksum. The message alone does not
|
|
identify whether those bytes came from the local cache or a remote source.
|
|
Keep checksum verification enabled and retain the error, selected version,
|
|
and relevant `go.sum` entries. Go's [module authentication reference](https://go.dev/ref/mod#authenticating)
|
|
describes these checks.
|
|
|
|
To isolate a public ReleaseKit download from application settings and the
|
|
existing module cache, run the following with a compatible local Go toolchain.
|
|
Replace `v0.2.0` with the affected version. This diagnostic accesses the public
|
|
Go proxy and checksum database and retains its temporary directory for inspection.
|
|
|
|
```sh
|
|
(
|
|
checksum_dir=$(mktemp -d) || exit 1
|
|
printf 'Checksum investigation directory: %s\n' "$checksum_dir"
|
|
cd "$checksum_dir" || exit 1
|
|
GOENV=off GOFLAGS= GOWORK=off GOTOOLCHAIN=local \
|
|
GOPRIVATE= GONOPROXY= GONOSUMDB= \
|
|
GOPROXY=https://proxy.golang.org GOSUMDB=sum.golang.org \
|
|
GOMODCACHE="$checksum_dir/modules" \
|
|
go mod download -json gitea.maximumdirect.net/eric/ReleaseKit@v0.2.0
|
|
)
|
|
```
|
|
|
|
A successful isolated download establishes that this version verifies through
|
|
the selected proxy. Compare its `GoMod`, `GoModSum`, and `Sum` with the affected
|
|
cache and the application's recorded checksums. Locate the original cache with
|
|
`go env GOMODCACHE`; Go stores downloaded module metadata separately from the
|
|
extracted source. See the [module cache reference](https://go.dev/ref/mod#module-cache).
|
|
|
|
Once a stale cache entry is confirmed, preserve a copy, quarantine that entry
|
|
while no Go process is using it, and retry normal dependency preparation. For
|
|
a confirmed stale `.mod`, quarantine that file alone. Preserve application
|
|
checksums and published tags. Routine downloads can continue to use the normal
|
|
module cache.
|
|
|
|
If the isolated download also fails, investigate the selected proxy, tagged
|
|
source, and recorded checksums with the maintainer before changing local state.
|
|
Record any difference between proxy and direct fetching. A confirmed cache
|
|
problem can be repaired locally; changes to published source follow the
|
|
maintainer's immutable-release procedure.
|