14 KiB
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.
err := releasekit.PrepareTaggedCheckout(ctx, releasekit.TaggedCheckoutRequest{
RepositoryDir: repositoryDir,
Version: version,
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; see the
Go Modules Reference. Cancellation
and command errors are returned. Page-only profiles do not need dependency
preparation.
Command line
Add a Gitea destination to the profile:
{
"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:
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. 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:
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.
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, configuration reference, and Gitea integration guide for exact settings, exit codes, and transport behavior.
Woodpecker tag workflows
Use the maintained tag-delivery workflow
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. 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.
Afterward, ci-deliver loads the 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 and may
update an uncommitted checksum file in the checkout. A retry still uses the
same immutable tag and that tag's module settings, even after the default branch
selects a newer ReleaseKit version.
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
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:
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 and configuration reference.
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 for runner-provided tag and commit variables and 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
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.
(
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.
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.