Expose tagged-source delivery through facade and CLI

This commit is contained in:
2026-10-05 20:39:33 +00:00
parent eb2cab78bb
commit bdf6a155b5
23 changed files with 1215 additions and 40 deletions

View File

@@ -1,6 +1,6 @@
# Command line
ReleaseKit currently provides four commands.
ReleaseKit currently provides five commands.
Print the executable version:
@@ -72,3 +72,32 @@ The command returns status 0 on completion, 1 for build or output failure, and
tree and does not perform candidate validation or remote publication. `check`
and `publish` run the same configured build after their one candidate
validation, using temporary output outside the worktree.
Deliver a tagged source release to Gitea:
```sh
go run ./cmd/releasekit deliver [--repo DIR] [--config FILE] [--assets DIR] VERSION
```
`deliver` requires a `delivery` profile object and its configured token
environment variable, which defaults to `RELEASEKIT_GITEA_TOKEN`. It verifies
the local tag, clean tagged checkout, hosted tag, and committed release note,
then creates or finds the release page and reports delivery state separately
from source publication. Historical lightweight tags and detached checkouts
are supported when `HEAD` is the selected tag commit; delivery does not require
the former remote `main` to match.
When the profile has build targets and `--assets` is omitted, `deliver` builds
the tagged source into temporary storage and uploads its binaries and complete
`SHA256SUMS`. When `--assets DIR` is supplied, that directory must contain the
private `.releasekit-build.json` receipt and matching unchanged artifacts.
Profiles without targets use page-only delivery and need no receipt, binary
build, or manifest. `deliver` never runs candidate checks or publishes a tag.
The command returns 0 for complete delivery, 1 for a known failure, conflict,
or partial delivery, 2 for usage, profile, or missing-credential errors, and 3
when a remote write remains uncertain. The result lists matching, uploaded,
pending, conflicting, and uncertain assets as available. Retry the same version
with the same tagged source and destination; matching content is kept and only
missing assets are added. See the [delivery consumer guide](consumers/delivery.md)
and [Gitea integration guide](integrations/gitea.md).

View File

@@ -12,6 +12,7 @@ The current profile fields are:
| `remote` | No | Selected Git remote; defaults to `origin`. |
| `checks` | No | Ordered child commands, each with an argument vector and optional environment map. |
| `build` | No | Optional main package, binary name, and selected `GOOS/GOARCH` target strings. |
| `delivery` | No | Optional Gitea `base_url`, `owner`, `repository`, and `token_env` settings for tagged-source delivery. |
Each check requires a nonempty `args` array whose first element names the
executable. Arguments are passed directly to the child process; ReleaseKit does
@@ -24,12 +25,23 @@ Unknown fields are rejected so a setting cannot be silently ignored. The
target requires the package and binary name; each target is written as one
`GOOS/GOARCH` pair. An omitted or empty target list means no binary work.
The `delivery` object contains `base_url`, `owner`, `repository`, and optional
`token_env`. Its values are required when running `deliver`, but credentials are
not required for `check`, `publish`, or `build`. `token_env` names the
environment variable containing the Gitea token; it defaults to
`RELEASEKIT_GITEA_TOKEN`. The CLI reads this variable only for `deliver` and
passes its value explicitly to the library operation.
The `check` and `publish` commands use `product`, `remote`, and `checks`, and
build selected targets after the single validation callback. If `checks` is
omitted or empty, it runs `go test -mod=readonly -count=1 ./...` with Go module
and toolchain network access disabled. If checks are configured, they replace
that default and run in order. The `build` command uses the selected build
settings and writes binaries to `dist` unless `--output` selects another path.
The `deliver` command uses the delivery destination and token, then either
builds selected tagged-source targets into temporary storage or loads verified
assets from the directory selected by `--assets`. An absent build object or an
empty target set selects page-only delivery.
ReleaseKit's source-only publication profile is
[releasekit.json](../releasekit.json).

View File

@@ -66,3 +66,9 @@ profile and writes a private receipt alongside its artifacts. `check` and
`publish` run selected builds after their one validation callback using
temporary output outside the worktree; those candidate checks do not write a
receipt or leave build files in the repository.
For delivery from a tagged checkout, `deliver` builds selected tagged-source
targets into temporary storage by default. Use `--assets DIR` to deliver a
separate build output; ReleaseKit requires its receipt and verifies the source,
build settings, and artifact hashes before the first Gitea write. See the
[delivery consumer guide](delivery.md) for page-only delivery and retry states.

View File

@@ -0,0 +1,81 @@
# 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.
## 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.
With no build targets, delivery is page-only: no builder, version smoke check,
receipt, binary asset, or checksum manifest is involved. With selected targets,
the command builds the tagged source into temporary storage and delivers the
result. To use artifacts built separately, pass `--assets DIR`; the directory
must contain the private `.releasekit-build.json` receipt created by `build`.
ReleaseKit checks the receipt's repository, commit, version, resolved build
settings, and file hashes before making a remote request.
The result reports `complete`, `partial`, `conflict`, `unknown`, or
`not_attempted`, along with matching, uploaded, pending, conflicting, and
uncertain assets when known. Exit status 3 means a remote write could not be
resolved; inspect the same version and retry only after the remote state is
understood. The command does not run candidate checks or publish tags.
## Go API
Pass the Gitea credential explicitly. A `BuildResult` may be supplied for a
binary-producing release; it must identify the same tagged repository commit
and selected version, and its local artifacts must still match their digests.
Leave `Build` nil for a source-only release.
```go
result, err := releasekit.Deliver(ctx, releasekit.DeliveryRequest{
RepositoryDir: "/work/example",
Product: "Example",
Version: "v1.2.3",
Destination: releasekit.GiteaDestination{
BaseURL: "https://gitea.example",
Owner: "example",
Repository: "example",
Token: token,
},
})
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.

View File

@@ -1,9 +1,11 @@
# Gitea release pages
ReleaseKit's internal Gitea client verifies a hosted source tag, finds or
creates its stable release page, inspects existing assets, and uploads missing
assets. The public delivery facade and CLI workflow are planned separately;
this guide describes the implemented internal operations.
ReleaseKit's public `Deliver` operation and `deliver` command verify tagged
source, find or create its stable release page, inspect existing assets, and
upload missing assets through the internal Gitea client. Page-only and
binary-producing profiles use the same delivery path. The
[consumer delivery guide](../consumers/delivery.md) covers caller workflows;
this guide describes the Gitea protocol and its failure behavior.
The caller supplies the Gitea base URL, owner, repository name, and token
explicitly. The client does not read ambient credentials. The token is sent in

View File

@@ -26,13 +26,15 @@ Implemented internal packages:
creates and pushes exact annotated tag objects.
- `internal/publish` coordinates local and remote guards around one validation
run and reports the publication state reached by that invocation.
- `internal/delivery` verifies a tagged checkout and coordinates note, build
identity, hosted page, asset inspection, and additive upload outcomes.
- `cmd/releasekit/internal/cli` parses implemented commands, loads strict JSON
profiles, adapts configured checks, and writes and validates private local
build receipts.
build receipts used for delivery.
The executable controller uses the runtime facade and the command-owned CLI
adapter. The adapter uses the process runner and imports neither public facade.
The publication operation coordinates the candidate and Git packages. The
internal Gitea client is documented in the
[Gitea integration guide](../integrations/gitea.md); delivery orchestration will
use it when that facade and CLI work lands.
[Gitea integration guide](../integrations/gitea.md); tagged-source orchestration
is exposed through the public delivery facade and CLI.

View File

@@ -1,6 +1,6 @@
# ReleaseKit staged implementation plan
Status: In progress. Stages 1–14 are complete; later stages remain pending.
Status: In progress. Stages 1–15 are complete; later stages remain pending.
Date: 2026-10-05
@@ -794,7 +794,7 @@ an ambiguous acknowledgment. Published manifest constraints hold across reruns.
## Stage 15: Expose tagged-source delivery through the facade and CLI
Status: Pending. Depends on Stage 14.
Status: Complete. Depends on Stage 14.
1. Implement `Deliver`, its facade-owned request/result values, and conversions.
Bind source note, resolved build settings, tag commit, and hosted repository
@@ -818,6 +818,21 @@ receipt, tampered assets, and missing credentials prevent relevant writes.
Candidate tests and Git publication are not run by delivery. A delivery failure
leaves the existing source tag intact and reports only delivery failure.
Evidence: `releasekit.Deliver` and `releasekit deliver` now verify lightweight or
annotated local tags from clean, attached or detached checkouts, compare the
hosted tag commit, and use the note read from the tagged commit. The CLI loads
delivery credentials only for delivery; it builds selected tagged-source
artifacts in temporary storage or verifies a supplied build receipt and its
artifact hashes before calling the facade. Page-only fixtures create and reuse
the complete note without a main package, receipt, manifest, build, or upload.
Binary fixtures build a tagged-source executable, upload it with `SHA256SUMS`,
and accept matching page and asset content on rerun. Local server tests verify
that wrong hosted and local commits, stale build settings, tampered receipt
assets, and missing credentials prevent remote writes; the tag remains intact
after delivery failure. `go test ./...`, `go run ./internal/apicheck`, and the
Markdown whitespace check pass. All delivery checks use a local HTTP fixture;
no live Gitea service or credentials were used.
## Stage 16: Provide the common Woodpecker integration
Status: Pending. Depends on Stage 15.

View File

@@ -56,9 +56,9 @@ cleanup.
The [architecture policy](../policy/architecture.md) owns the adopted
responsibility and dependency rules, including the runtime version boundary.
The root `releasekit` package provides the public facade for candidate
validation, source publication, and selected-target builds. Internal Gitea
page and asset-delivery operations are implemented; facade and CLI orchestration
remain planned. The separate public `buildinfo` package provides lightweight
validation, source publication, selected-target builds, and tagged-source
delivery. The Gitea page and asset-delivery client is integrated through that
facade and the CLI. The separate public `buildinfo` package provides lightweight
runtime version access.
Each facade owns its public named types and documented contracts. Public