Retire completed roadmaps and preserve adoption work
This commit is contained in:
@@ -1,997 +0,0 @@
|
||||
# ReleaseKit staged implementation plan
|
||||
|
||||
Status: Complete. Stages 1–18 are complete.
|
||||
|
||||
Date: 2026-10-05
|
||||
|
||||
## Purpose and baseline
|
||||
|
||||
This plan gives a Luna coding agent bounded implementation assignments, in
|
||||
execution order, for the target state in the [feature roadmap](releasekit.md).
|
||||
The roadmap owns product intent and selected release conventions. This document
|
||||
owns implementation steps, dependencies, acceptance evidence, and progress.
|
||||
|
||||
The baseline is ReleaseKit commit `6c2695f`. It contains documentation, adopted
|
||||
policies, licensing notices, and [ADR 0001](../adr/0001-public-facade.md). It has
|
||||
no Go module, packages, executable, tests, or publication automation. The
|
||||
worktree was clean when this plan was prepared. The available tools were Go
|
||||
1.26.8 on linux/amd64 and Git 2.53.0; these observations are not minimum support
|
||||
requirements.
|
||||
|
||||
The six sibling checkouts provide design evidence; this implementation sequence
|
||||
changes ReleaseKit only. Consumer migrations and measurement of deleted consumer
|
||||
infrastructure belong to later adoption work. Consult code through the knowledge
|
||||
graph, indexing a repository when necessary. Documents, scripts, and CI
|
||||
configuration may be read directly under the discovery instructions.
|
||||
|
||||
## Scope and completion
|
||||
|
||||
Deliver the complete initial library, executable, configuration, shared build
|
||||
and delivery mechanics, Woodpecker examples, and ReleaseKit's own prepared
|
||||
release wiring. Hosted Gitea release pages are part of the selected standard
|
||||
for every project, including source-only projects. Source-only delivery uses
|
||||
the committed release note and zero binary assets; it needs no binary build or
|
||||
checksum manifest.
|
||||
|
||||
Proceed through all stages using the local checkout and controlled fixtures.
|
||||
No stage depends on an intermediate release, published tool/runtime pin,
|
||||
consumer pilot, external service action, or human review. Ordinary automated
|
||||
development checks accompany implementation under the testing policy.
|
||||
|
||||
After the complete initial implementation, the maintainer will review the
|
||||
architecture, address discovered issues, and then choose the broader testing
|
||||
plan and next steps. Consumer adoption, live integration testing, secret
|
||||
provisioning, CI activation, and actual publication are outside this sequence.
|
||||
|
||||
## Execution instructions
|
||||
|
||||
- Implement stages in integer order. Each stage is one assignment; finish its
|
||||
acceptance checks and local commit before starting the next stage. Record
|
||||
completed work and evidence here. Read the stage's dependencies and relevant
|
||||
decisions before editing.
|
||||
- Start with the [developer guide](../development.md) and applicable policies.
|
||||
Architecture, testing, documentation, and release policies apply to the core
|
||||
implementation. Read the OSS policy when incorporating third-party material.
|
||||
- Follow the [architecture policy](../policy/architecture.md) and ADR 0001.
|
||||
Add exported declarations as their behavior is implemented, with GoDoc.
|
||||
Implement the selected contract with proportionate internal collaborators.
|
||||
- The design choices below specify this draft's recommended implementation.
|
||||
Apply the selected scope and decisions throughout the sequence. Later
|
||||
agent-authored code or tests provide evidence of implementation, rather than
|
||||
independent authority to strengthen the contract.
|
||||
- For each stage, run focused behavioral checks for its changed risks and the
|
||||
established offline default suite. Reuse unchanged evidence where appropriate.
|
||||
Stage acceptance checks are development checks; they add no publication gates
|
||||
beyond the release policy and a repository's selected candidate checks.
|
||||
- Use temporary repositories, local bare remotes, test programs, and local HTTP
|
||||
servers. Keep fixtures independent of the six consumer checkouts and real
|
||||
services. Temporary fixture module replacements may connect test programs to
|
||||
this checkout; keep them outside committed production module configuration.
|
||||
- Update canonical documentation with each implemented responsibility. Create
|
||||
consumer, CLI, configuration, integration, and internal documents when they
|
||||
have substantive content. Keep future behavior and stage progress here.
|
||||
- Keep the implementation self-contained. Build the tool from this checkout;
|
||||
temporary fixture modules may use local replacements. Integration templates
|
||||
accept an operator-selected immutable tool pin for later deployment, without
|
||||
requiring one to complete this plan or claiming that a release already exists.
|
||||
- Complete stages with local implementation commits and controlled checks.
|
||||
Prepare runnable automation and deployment instructions without activating
|
||||
live workflows. Distinguish implemented integration from verified live use.
|
||||
Finish the whole sequence before the maintainer's architecture review; add no
|
||||
intermediate approval or external-action checkpoint.
|
||||
|
||||
## Implementation decisions
|
||||
|
||||
### Module, runtime access, and public ownership
|
||||
|
||||
Use one module, `gitea.maximumdirect.net/eric/ReleaseKit`, preserving the case
|
||||
advertised by the forge's Go import metadata. Set the initial Go language
|
||||
baseline to `go 1.25.0`, matching the oldest consumer module line. Use APIs
|
||||
available on that baseline. Actual execution uses a prepared local toolchain
|
||||
capable of building the consumer; Narratio already needs Go 1.26. There is no
|
||||
mandatory multi-toolchain release matrix.
|
||||
|
||||
The supported packages are the root `releasekit` facade and `buildinfo`. Put
|
||||
the executable at `cmd/releasekit`. Start with standard-library implementations
|
||||
and the installed Git and Go executables. Introduce internal packages as their
|
||||
responsibilities land: runtime information, process execution, release engine,
|
||||
Git operations, builds, Gitea transport, and CLI adaptation. Put command-owned
|
||||
parsing and file-format helpers under `cmd/releasekit/internal/cli`; keep facade
|
||||
calls in the `cmd/releasekit` controller. Those helpers return their own settings
|
||||
for explicit conversion by the controller and import neither public facade.
|
||||
The executable therefore consumes the supported APIs while library internal
|
||||
packages retain inward dependencies. There are no public transport clients or
|
||||
assembly APIs.
|
||||
|
||||
The initial runtime API is `buildinfo.Version() string`. It returns an injected
|
||||
release identifier when supplied; otherwise it uses the running executable's
|
||||
main-module version when present and different from `(devel)`, then `dev` when
|
||||
that metadata is unavailable. This supports source installs as well as explicit
|
||||
release builds. It describes the application version, not the ReleaseKit
|
||||
dependency version. [Go build information](https://pkg.go.dev/runtime/debug#ReadBuildInfo)
|
||||
documents the main-module metadata available to implement this fallback.
|
||||
|
||||
Keep the injected string private in the internal runtime implementation. Keep
|
||||
the linker symbol identifier in a small internal contract used by the builder.
|
||||
The builder and runtime implementation change together. Consumers call the
|
||||
accessor; their configuration supplies no linker symbol. The runtime import
|
||||
graph uses the standard library and small runtime implementation, independent
|
||||
of orchestration. A tool/runtime version mismatch must be exposed by the native
|
||||
version smoke check; do not introduce an exact dependency-version equality gate.
|
||||
|
||||
### Orchestration API
|
||||
|
||||
Implement these root operations as the corresponding stages land:
|
||||
|
||||
| Operation | Request and result responsibilities |
|
||||
| --- | --- |
|
||||
| `Check(ctx, ReleaseRequest)` | Capture and validate a local committed candidate; return its commit and version. This diagnostic operation does not query publication services, create a tag, or claim remote readiness. |
|
||||
| `Publish(ctx, ReleaseRequest)` | Validate once, check authoritative state, create and publish the selected annotated tag, and return publication state and retained recovery facts. |
|
||||
| `Build(ctx, BuildRequest)` | Build the selected targets with the requested version, verify a native version invocation, and return source identity and generated artifacts. |
|
||||
| `Deliver(ctx, DeliveryRequest)` | Verify tagged source and supplied artifact identity, create or find a hosted release, compare content, and add missing assets with explicit partial or uncertain outcomes. |
|
||||
|
||||
Each operation returns a facade-owned result and an error. Requests carry the
|
||||
repository directory explicitly. `ReleaseRequest` also carries the display
|
||||
product name, version, selected remote, optional validation callback, optional
|
||||
build specification, and optional output writer. The remote defaults to
|
||||
`origin`; publication uses `main`. The callback receives a facade-owned
|
||||
`Candidate` containing directory, captured commit, and selected version. A nil
|
||||
callback selects the default Go test invocation. A supplied callback replaces
|
||||
that invocation with the repository's complete selected validation; it is
|
||||
called once. The CLI adapts configured commands into this callback.
|
||||
|
||||
A build specification carries main package, binary name, and targets. Each
|
||||
facade-owned `Target` contains Go OS and architecture strings. A build request
|
||||
adds version and output directory. A delivery request identifies version,
|
||||
product, repository directory, Gitea destination, and optional build result.
|
||||
The Gitea destination carries base URL, owner, repository name, and caller-supplied
|
||||
token. Library code obtains no credentials from ambient configuration. Before
|
||||
the first remote write, an inspection failure reports that this invocation has
|
||||
not attempted mutation. Reserve uncertain-mutation classification and exit 3
|
||||
for writes whose authoritative outcome remains unresolved.
|
||||
|
||||
Publication results identify version, candidate commit, captured endpoint,
|
||||
phase, and tag object when created. Use distinct states for `not_attempted`,
|
||||
`not_published`, `published`, `conflict`, and `unknown`. These describe this
|
||||
invocation; a pre-existing remote release is not described as unpublished.
|
||||
Delivery results identify release URL and the matching, uploaded, pending, and
|
||||
uncertain assets, with `not_attempted`, `complete`, `partial`, `conflict`, or
|
||||
`unknown` state. Ordinary errors preserve useful causes through wrapping.
|
||||
Document exactly when nonzero results accompany errors. Add only the named
|
||||
types needed to represent these responsibilities; field spelling and internal
|
||||
package layout can follow idiomatic Go without changing the decisions here.
|
||||
|
||||
### CLI and configuration
|
||||
|
||||
Use standard-library flag parsing and JSON configuration. The default profile
|
||||
is `<repository>/releasekit.json`; `--config` selects another file. Configuration
|
||||
paths are resolved from the selected repository, whose default is the current
|
||||
directory. A profile supplies product identity, remote, candidate commands,
|
||||
optional build specification, and optional Gitea delivery declaration. The
|
||||
command supplies the version rather than persisting it in the profile.
|
||||
|
||||
This composite profile shows the implemented fields together; working
|
||||
[source-only](../../examples/releasekit.json) and
|
||||
[binary-producing](../../examples/releasekit-binary.json) profiles are maintained
|
||||
under `examples/`:
|
||||
|
||||
```json
|
||||
{
|
||||
"product": "Scriptorium",
|
||||
"remote": "origin",
|
||||
"checks": [{"args": ["sh", "scripts/check-release-candidate.sh"]}],
|
||||
"build": {
|
||||
"main_package": "./cmd/scriptorium",
|
||||
"binary_name": "scriptorium",
|
||||
"targets": ["linux/amd64", "linux/arm64"]
|
||||
},
|
||||
"delivery": {
|
||||
"base_url": "https://gitea.maximumdirect.net",
|
||||
"owner": "eric",
|
||||
"repository": "scriptorium",
|
||||
"token_env": "GITEA_RELEASE_TOKEN"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Command entries also accept an `env` map. Run argument vectors directly, without
|
||||
implicit shell parsing. A repository that needs shell syntax selects `sh` or
|
||||
`bash` explicitly. Run commands in the captured repository directory and supply
|
||||
`RELEASEKIT_VERSION` and `RELEASEKIT_CANDIDATE` for candidate-specific checks.
|
||||
Those captured values take precedence over conflicting command environment
|
||||
entries. Inherit the remaining environment and overlay explicitly owned values
|
||||
without mutating the caller process.
|
||||
|
||||
An absent or empty check list selects `go test -count=1 ./...`; a nonempty list
|
||||
is the repository's complete validation sequence. Decode profile fields
|
||||
strictly so unsupported build or delivery settings cannot silently disappear
|
||||
from the selected checks. Validate required values for the operation being run;
|
||||
source-only checks and publication need neither a main package nor credentials.
|
||||
Hosted page delivery requires a destination and token for source-only profiles
|
||||
as well as binary-producing profiles.
|
||||
The CLI loads the token named by `delivery.token_env`, defaulting to
|
||||
`RELEASEKIT_GITEA_TOKEN`, only for delivery. Build receipt identity covers resolved
|
||||
build inputs; delivery credentials, destination, and unrelated check settings
|
||||
are excluded from that identity.
|
||||
|
||||
The eventual command forms are:
|
||||
|
||||
```text
|
||||
releasekit version
|
||||
releasekit check [--repo DIR] [--config FILE] VERSION
|
||||
releasekit publish [--repo DIR] [--config FILE] VERSION
|
||||
releasekit build [--repo DIR] [--config FILE] [--output DIR] VERSION
|
||||
releasekit deliver [--repo DIR] [--config FILE] [--assets DIR] VERSION
|
||||
```
|
||||
|
||||
Flags precede the positional version. `version` prints `releasekit <version>`.
|
||||
Use exit 0 for completed success, 1 for a known failure or conflict, 2 for usage
|
||||
or invalid configuration, and 3 for an uncertain remote mutation. Library
|
||||
outcomes retain more detail. Send validation progress and diagnostics to stderr;
|
||||
stdout presents the command's final result. Signals cancel the operation through
|
||||
its context. There is no interactive confirmation loop.
|
||||
|
||||
### Candidate checks and Git publication
|
||||
|
||||
Parse stable versions using the roadmap's exact syntax. Validate decimal
|
||||
components as strings without introducing a machine-integer size limit. Read
|
||||
the release note from the captured commit at `docs/releases/<version>.md`. Its
|
||||
first line must be a Markdown H1 containing the configured product name and
|
||||
exact version as complete title elements. Preserve the note content for the annotated tag.
|
||||
The shared tool imposes no additional note section inventory.
|
||||
|
||||
`Check` checks a clean worktree and index on `main`, captures HEAD, checks the
|
||||
committed note and unused local version, runs validation and selected builds,
|
||||
and rechecks local mutable state. `Publish` adds authoritative endpoint and
|
||||
remote branch/tag checks before validation and immediately before publication.
|
||||
Cleanliness includes untracked files; ordinary Git ignore rules still apply.
|
||||
Snapshot resolved request values and CLI profile content for the invocation so
|
||||
configuration is not reloaded into different checks midway through the run.
|
||||
Source changes remain subject to the ordinary candidate rechecks. The Go API
|
||||
accepts caller-supplied values without requiring a particular profile file.
|
||||
|
||||
Resolve the selected remote's effective push destination using Git's own remote
|
||||
configuration semantics. A missing destination or more than one distinct
|
||||
effective publication destination is an actionable configuration error because
|
||||
this operation needs one authoritative endpoint. A separate fetch URL is
|
||||
supported. Inspect the publication endpoint,
|
||||
rather than assuming the selected remote's normal fetch URL is authoritative.
|
||||
|
||||
Use a transient, command-scoped named remote with explicit read and push URLs
|
||||
and mirror mode disabled. Verify that both effective URLs equal the captured
|
||||
publication destination after Git URL rewriting. Reuse that scoped remote for
|
||||
queries and push; persist no new remote configuration. Retain normal Git
|
||||
credential and transport settings, carrying remote-specific transport settings
|
||||
into the scoped remote as needed. If rewriting prevents establishing this
|
||||
equality, report the unresolved destination before mutation.
|
||||
Recheck the original remote resolution before pushing. Test ordinary
|
||||
`insteadOf`, `pushInsteadOf`, and explicit push-URL cases using local remotes.
|
||||
[Git's remote documentation](https://git-scm.com/docs/git-remote) describes the
|
||||
effective URL lookup on which this relies.
|
||||
|
||||
Use exact ref names in remote queries. Require authoritative `main` to equal
|
||||
the captured candidate and the selected tag to be absent. Create the annotated
|
||||
tag from the committed note with signing disabled for this invocation, inspect
|
||||
its object type and peeled commit, then freeze its object ID. Push
|
||||
`<tag-object-id>:refs/tags/<version>` with automatic following of tags and mirror
|
||||
defaults disabled. Publish no branch updates, unrelated tags, or force updates.
|
||||
|
||||
A successful push returns immediately as published. After a failed or ambiguous
|
||||
push, make one authoritative tag query: an exact object match confirms success;
|
||||
absence confirms not published at observation; a different object is conflict;
|
||||
an unavailable or uninterpretable answer is unknown. Retain the local tag in
|
||||
all failed or uncertain cases. Caller cancellation after push starts also needs
|
||||
this bounded reconciliation attempt using a separate finite recovery context.
|
||||
Use a 30-second recovery deadline as an operational default, not a guarantee
|
||||
that the endpoint will respond. Cancellation before push does not initiate it.
|
||||
|
||||
The last remote branch check is an observation before the tag push. This design
|
||||
provides no transaction locking remote `main` against concurrent writers. Do not
|
||||
add branch pushes or assert stronger concurrency guarantees in tests.
|
||||
|
||||
### Go execution, builds, and assets
|
||||
|
||||
For ReleaseKit-owned candidate Go commands and builds, use prepared dependencies
|
||||
and a local toolchain. Set child environment values `GOWORK=off`, `GOPROXY=off`,
|
||||
`GONOPROXY=none`, `GOSUMDB=off`, and `GOTOOLCHAIN=local`. Set module mode to
|
||||
readonly, preserving a repository's deliberately selected testing flags.
|
||||
ReleaseKit-owned builds replace ambient `GOFLAGS` with `-mod=readonly` and use
|
||||
their explicit build arguments; custom validation commands retain their
|
||||
deliberately configured flags.
|
||||
Preparation of caches and tools occurs separately. These settings do not
|
||||
sandbox arbitrary repository callbacks or establish a general network firewall.
|
||||
|
||||
Build with `CGO_ENABLED=0`, `-mod=readonly`, `-trimpath`, `-buildvcs=false`, and
|
||||
linker flags `-s -w` plus the shared version injection. This selects the pure-Go
|
||||
build convention already used by the current asset builders. Additional cgo
|
||||
toolchains remain outside this implementation. The injected string must use a
|
||||
linker-supported initializer. [Go's linker documentation](https://pkg.go.dev/cmd/link)
|
||||
defines the `-X` mechanism.
|
||||
|
||||
Initially verify linux/amd64, linux/arm64, and darwin/arm64. Represent targets
|
||||
as values rather than a closed enum; other explicit Go OS/architecture pairs
|
||||
can be passed to the prepared compiler and may fail according to its support.
|
||||
This establishes no native-execution promise for other platforms.
|
||||
|
||||
Asset names are `<binary-name>-<version>-<goos>-<goarch>`, with `.exe` when the
|
||||
requested Go OS needs it. Binary names and target components must be nonempty
|
||||
filename components without path separators, backslashes, CR, or LF, so names
|
||||
stay in the output directory and have unambiguous manifest entries. Normalize
|
||||
repeated target pairs to one target, retaining their first position. Distinguish
|
||||
the display product name used by notes from this binary name. Preserve selected
|
||||
target order for progress; generate manifests in filename order.
|
||||
|
||||
For nonempty targets, invoke the built application with `version` and require
|
||||
`<binary-name> <version>` plus a final newline. Reuse a target artifact when it
|
||||
matches `GOHOSTOS/GOHOSTARCH`; otherwise build a temporary native executable
|
||||
with the same flags and injection. Determine the host independently of ambient
|
||||
`GOOS/GOARCH`. Native smoke binaries are temporary and are not extra assets.
|
||||
An empty target set performs no Go build or version invocation. Source-only
|
||||
projects may retain an explicitly selected application check; no binary check
|
||||
is silently imposed on them.
|
||||
|
||||
Candidate build checks use a temporary output directory outside the worktree
|
||||
and discard it. Artifact builds record the commit, version, main package,
|
||||
targets, compiler identity, and generated filename/hash pairs. Return these
|
||||
facts in `BuildResult`. The CLI persists them in an internal local receipt,
|
||||
`.releasekit-build.json`, alongside the generated files after a successful
|
||||
complete build and smoke check. A partial build returns progress without a
|
||||
receipt authorizing delivery. This receipt is for tool coordination, with no
|
||||
public format or attestation promise. It contains no credentials and is not a
|
||||
hosted asset. Build output defaults to `dist`; create
|
||||
the directory as needed, regenerate owned local filenames, and preserve
|
||||
unrelated files. Report generated files on partial local failure and clean up
|
||||
only tool-owned temporary paths.
|
||||
|
||||
Delivery uses a clean checkout whose HEAD equals the selected local tag's peeled
|
||||
commit; detached HEAD is valid. Read the note from that commit and snapshot the
|
||||
selected settings. Repository-local tracked profiles come from that source;
|
||||
explicit caller-supplied settings are identified in the build result. Verify
|
||||
the hosted repository already has the same tag targeting that commit before
|
||||
creating a release. Existing lightweight historical tags may be inspected and
|
||||
delivered; new publication follows the annotated-tag standard. Do not require
|
||||
current remote `main` to remain at an old release commit during delivery retries.
|
||||
|
||||
The CLI's `deliver --assets DIR` consumes a verified build receipt and checks
|
||||
file hashes, selected filenames, and source/build-input identity before remote
|
||||
mutation. When no directory is supplied, build into a temporary directory from
|
||||
the tagged checkout and then deliver. With zero targets, hosted delivery creates
|
||||
the required note page without a binary manifest or build receipt. An absent
|
||||
build specification is equivalent to zero targets for source-only delivery.
|
||||
Neither mode reruns the candidate test suite or changes source-publication status.
|
||||
|
||||
### Hosted delivery and Woodpecker
|
||||
|
||||
Use a small internal standard-library Gitea REST client. On 2026-10-05 the host's
|
||||
[version endpoint](https://gitea.maximumdirect.net/api/v1/version) reported Gitea
|
||||
1.25.4; its [served API schema](https://gitea.maximumdirect.net/swagger.v1.json)
|
||||
confirmed release-by-tag lookup, JSON release creation, asset listing, and
|
||||
multipart attachment upload. Implement the operations described here against
|
||||
local fixtures and record them in the integration guide. Verification against
|
||||
the deployed host belongs to later live testing and is not needed to complete
|
||||
this sequence. This observation is not an all-version Gitea compatibility promise.
|
||||
|
||||
Read the tag through `/api/v1/repos/{owner}/{repo}/tags/{tag}` and verify its
|
||||
`commit.sha`. Use the repository API prefix for each following operation. Find
|
||||
the release through `/releases/tags/{tag}`. Create it through
|
||||
`POST /releases` with the existing tag, captured commit, title from the note's
|
||||
H1, complete committed note as body, and stable, non-draft settings. A found
|
||||
release must match the note body and tag and be stable/non-draft; retain its
|
||||
existing title, including a historical title chosen by other tooling. A content
|
||||
conflict is reported; its body, title, assets, and tag are not edited. Existing
|
||||
historical pages remain intact.
|
||||
|
||||
List attachments through `/releases/{id}/assets`. Identify expected filenames
|
||||
and stream their downloads to compare SHA-256 content; size and name alone do
|
||||
not prove a match. Use multipart field `attachment` and the filename query
|
||||
parameter for missing uploads. The client obtains no automatic tag-creation
|
||||
responsibility. Keep authorization on the configured service origin when
|
||||
following attachment URLs or redirects; never include token values in receipts
|
||||
or diagnostics.
|
||||
|
||||
For nonempty binary sets, generate `SHA256SUMS` with lowercase hashes, two spaces,
|
||||
filenames, and LF-terminated lines, sorted by filename. It describes the complete
|
||||
declared binary set and excludes itself and the private receipt. An existing
|
||||
manifest must match that expected content. Fill missing assets covered by that
|
||||
manifest only with matching bytes. A manifest describing a different or smaller
|
||||
set cannot be replaced to extend that version. Leave unrelated attachments
|
||||
untouched.
|
||||
|
||||
Inspect all known declared asset and manifest conflicts before uploading.
|
||||
Upload missing binaries in filename order, then a missing manifest. HTTP writes
|
||||
are separate operations. After an ambiguous creation or upload, re-read the
|
||||
affected resource once; classify matching content as completed, conflict as
|
||||
conflict, and inaccessible or still-indeterminate content as unknown. Handle
|
||||
concurrent creation by finding and verifying the created resource. Do not
|
||||
blindly retry writes or delete attachments. Record partial progress so an
|
||||
operator can rerun against the same tag and retained assets.
|
||||
|
||||
Woodpecker uses tag-triggered repository-local YAML with a pinned Go image
|
||||
and an explicit tool preparation step. Provide source-only and binary-producing
|
||||
examples. Consumer templates accept an operator-selected immutable ReleaseKit
|
||||
source pin for deployment; template preparation and local execution use the
|
||||
implementation checkout and require no published pin. Prepare consumer module
|
||||
caches separately, then run builds and delivery with offline Go execution.
|
||||
This honors ReleaseKit's source-only distribution; a dedicated ReleaseKit
|
||||
container image would require a separate deliverable decision. Use a Go image
|
||||
that satisfies the repository's module requirements.
|
||||
|
||||
ReleaseKit's own prepared workflow builds `cmd/releasekit` from its tagged
|
||||
checkout using the local toolchain and delivers its hosted note page. It needs
|
||||
no previously released executable and produces no distributed binary assets.
|
||||
Prepare this workflow locally; activation belongs to the later next-step plan.
|
||||
|
||||
Use `CI_COMMIT_TAG` and `CI_COMMIT_SHA` to bind the workflow to tagged source,
|
||||
with an explicit tag fetch when the checkout omits local tag refs. For binary
|
||||
profiles, the build step writes to ignored `dist` and the delivery step shares
|
||||
the workspace. Source-only workflows call delivery directly without an artifact
|
||||
build step. Supply the Gitea token only to delivery from a Woodpecker secret.
|
||||
Document operator substitution of image digests and source pins for eventual
|
||||
consumer deployment. Pipeline preparation may access dependency services;
|
||||
candidate validation and builds use the prepared caches. CI does not call
|
||||
`publish`, push refs, or gate source completion. The supported retry is a rerun
|
||||
from the same tagged source with content comparison; reproducible bytes across
|
||||
arbitrary toolchains or elapsed time are not promised.
|
||||
|
||||
## Stage 1: Establish the Go module and development baseline
|
||||
|
||||
Status: Complete. Depends on the baseline only.
|
||||
|
||||
1. Add the module with the selected path and language baseline. Add root package
|
||||
documentation for the orchestration facade and establish ordinary Go layout.
|
||||
2. Keep committed module state independent of sibling checkouts and workspaces.
|
||||
Start without external runtime dependencies or a generic plugin framework.
|
||||
3. Add the working offline developer test command and initial implemented-package
|
||||
inventory. Update README to its actual implemented boundary.
|
||||
|
||||
Acceptance: module loading and `go test ./...` work with the prepared local
|
||||
toolchain and network disabled. Review module identity and licensing notices.
|
||||
Do not invent tests merely to assert that an empty package exists.
|
||||
|
||||
Completion evidence: added the Go 1.25.0 module and documented root facade,
|
||||
updated the README and developer guide to describe the implemented boundary and
|
||||
offline test command, and confirmed module loading and `go test ./...` with
|
||||
network access disabled. The module has no external dependencies; existing
|
||||
LGPL licensing and attribution notices remain consistent.
|
||||
|
||||
## Stage 2: Implement the runtime version facade
|
||||
|
||||
Status: Complete. Depends on Stage 1.
|
||||
|
||||
1. Implement `buildinfo.Version` and its internal injected-string and main-module
|
||||
fallback logic. Keep runtime state private and the public accessor small.
|
||||
2. Add the internal injection-symbol contract without importing orchestration
|
||||
into the runtime path. Test injected precedence and missing/development
|
||||
metadata through stable internal seams and a small executable fixture.
|
||||
3. Add `cmd/releasekit` with a working `version` command using this accessor.
|
||||
Record its implemented command contract and the runtime consumer guidance.
|
||||
|
||||
Acceptance: a source-built fixture reports `dev`; a fixture linked with a stable
|
||||
version reports that version. Fallback metadata uses the executable main module.
|
||||
CLI version output is correct and no runtime orchestration initialization occurs.
|
||||
|
||||
Completion evidence: implemented `buildinfo.Version`, its private injected
|
||||
string and main-module fallback, and the internal linker-symbol contract. Unit
|
||||
tests cover injection precedence and missing, development, and stable main
|
||||
module metadata. Built and ran a separate consumer executable from source and
|
||||
with an injected stable version using network-disabled Go commands; both
|
||||
reported the selected value. CLI tests cover its version line, and the CLI's
|
||||
dependency closure contains no orchestration package. Added runtime consumer
|
||||
guidance and documented the command contract.
|
||||
|
||||
## Stage 3: Protect public contracts and dependency direction
|
||||
|
||||
Status: Complete. Depends on Stage 2.
|
||||
|
||||
1. Add a compiled-export boundary checker for both facades using `go list` export
|
||||
data and `go/types`. Inspect exported signatures, fields, callbacks, aliases,
|
||||
generic constraints, and pointer/value method sets recursively.
|
||||
2. Assert facade ownership of public named types. Permit deliberately selected
|
||||
standard-library contracts. Protect the private-state forwarding approach
|
||||
against leaked internal types and promoted implementation methods.
|
||||
3. Add import-direction checks: internal production packages use internal
|
||||
contracts; the runtime facade's dependency closure excludes orchestration,
|
||||
process, build, Gitea, and CLI implementation.
|
||||
4. Use small negative fixtures proving that the checker catches a leaked type
|
||||
and promoted internal method, and accepts a private implementation field.
|
||||
|
||||
Acceptance: actual exports pass and meaningful negative fixtures fail. Tests
|
||||
inspect contracts and imports, with no fixed inventory of future internal
|
||||
package names. Extend these checks as subsequent exports land.
|
||||
|
||||
Completion evidence: added `internal/apicheck`, which loads compiled exports
|
||||
from `go list -deps -export` and inspects signatures, fields, aliases, generic
|
||||
constraints, and pointer and value method sets through `go/types`. The checks
|
||||
pass for both public facades and enforce internal import direction and the
|
||||
runtime dependency boundary. Negative fixtures detect leaked types, aliases,
|
||||
callbacks, generic constraints, and promoted implementation methods; a private
|
||||
implementation field and selected standard-library contracts pass. Added the
|
||||
checker command and internal package inventory to the canonical developer docs.
|
||||
|
||||
## Stage 4: Implement profile loading and command adaptation
|
||||
|
||||
Status: Complete. Depends on Stage 3.
|
||||
|
||||
1. Implement JSON product, remote, and command settings under an internal CLI
|
||||
adapter. Add strict field decoding, directory resolution, required-value
|
||||
diagnostics, direct argument execution, and per-child environment overlays.
|
||||
2. Implement an internal cancellable process runner with directory, argument,
|
||||
environment, stdout, stderr, and exit-error support. Use `os/exec` directly;
|
||||
expose no public runner abstraction solely for test assembly.
|
||||
3. Add CLI parsing infrastructure and selected usage/exit behavior. Advertise
|
||||
commands only when their following stages implement them.
|
||||
4. Add small profile examples and `docs/config.md` for implemented fields.
|
||||
|
||||
Acceptance: paths and arguments containing spaces remain separate arguments;
|
||||
selected environment values reach the child without changing process globals;
|
||||
missing executables, invalid configuration, and cancellation report useful
|
||||
errors. Tests use controlled local child commands and temporary directories.
|
||||
|
||||
Completion evidence: added strict profile decoding, repository-relative and
|
||||
absolute profile resolution, required product and command diagnostics, and
|
||||
direct check argument adaptation. Added a cancellable `os/exec` runner with
|
||||
working directory, inherited environment plus child-only overlays, stdout,
|
||||
stderr, and preserved exit errors. Tests cover spaced paths and arguments,
|
||||
environment isolation, missing executables, exit failures, cancellation, and
|
||||
invalid profiles. Added a profile example and canonical CLI, configuration, and
|
||||
internal package documentation.
|
||||
|
||||
## Stage 5: Capture and validate one local candidate
|
||||
|
||||
Status: Complete. Depends on Stage 4.
|
||||
|
||||
1. Implement stable-version syntax, clean `main` and index/worktree inspection,
|
||||
captured HEAD, profile snapshot/note loading, title identity, and unused local
|
||||
tag checks. Preserve immutable candidate facts in internal values.
|
||||
2. Implement default offline Go validation and callback adaptation. Bind the
|
||||
callback to the captured candidate; pass captured version/commit to CLI
|
||||
commands. Call the complete validation callback once, stopping on failure.
|
||||
3. Recheck branch, HEAD, and cleanliness after validation. Retain the captured
|
||||
settings throughout the operation. Implement the public `Check` operation
|
||||
and local diagnostic `check` command.
|
||||
4. Document that local check success provides local candidate evidence and makes
|
||||
no authoritative remote availability claim.
|
||||
|
||||
Acceptance: temporary repositories cover invalid versions, missing or mismatched
|
||||
committed notes, dirty tracked/untracked state, existing local tags, detached
|
||||
HEAD, callback failure, and a callback changing HEAD or the worktree. Count a
|
||||
successful callback once. No test needs a publication service, and `Check`
|
||||
creates no tag or remote ref.
|
||||
|
||||
Evidence: `internal/candidate` validates stable versions and committed note
|
||||
identity, captures a clean `main` commit, runs either the offline default or the
|
||||
configured callback once, and rechecks local mutable state. The public
|
||||
`releasekit.Check` API and `releasekit check` command provide the local
|
||||
diagnostic. Temporary Git repositories cover the acceptance cases; offline
|
||||
`go test -count=1 ./...` and `go run ./internal/apicheck` pass.
|
||||
|
||||
## Stage 6: Resolve and inspect the authoritative endpoint
|
||||
|
||||
Status: Complete. Depends on Stage 5.
|
||||
|
||||
1. Implement effective push-URL capture, command-scoped remote configuration,
|
||||
matching read/write resolution, and endpoint rechecks described above.
|
||||
2. Implement exact remote main/tag queries with distinct present, absent,
|
||||
conflicting, and unreadable results. Query failures never establish absence.
|
||||
3. Compose the pre-validation and pre-publication remote guards around captured
|
||||
local state. Require main equality, rather than ancestor-only publication.
|
||||
|
||||
Acceptance: local remotes cover a separate fetch endpoint, explicit push URL,
|
||||
ordinary URL rewrites, multiple push destinations, missing main, conflicting
|
||||
tags, main ahead/behind the candidate, endpoint changes, and remote failure.
|
||||
Queries leave local tags, persistent remote configuration, and remote refs intact.
|
||||
|
||||
Evidence: `internal/git` captures effective push destinations through Git,
|
||||
rejects multiple distinct destinations, verifies scoped URL rewriting, and
|
||||
queries exact main and version-tag refs. A candidate check requires main to
|
||||
equal the captured commit and the version tag to be absent. Local bare remote
|
||||
tests cover separate fetch/push URLs, both rewrite modes, missing main, an
|
||||
existing tag, main ahead and behind, endpoint changes, unreadable remote state,
|
||||
and unchanged persistent config and refs.
|
||||
|
||||
## Stage 7: Create and push the exact annotated tag
|
||||
|
||||
Status: Complete. Depends on Stage 6.
|
||||
|
||||
1. Implement public publication request/result values and explicit conversion
|
||||
into the engine. Validate once between the complete preflight guards.
|
||||
2. Create an annotated tag from captured note bytes, inspect type and peeled
|
||||
commit, capture its object ID, and push only that object to the selected ref.
|
||||
3. Recheck mutable local state and endpoint before the push, including the local
|
||||
tag still identifying the captured object. A changed local tag prevents this
|
||||
invocation from proceeding; cleanup remains deliberate recovery.
|
||||
4. On successful push, return published state without another remote read-back.
|
||||
On push error, retain the tag and return unknown until Stage 8 adds resolution.
|
||||
|
||||
Acceptance: a local bare remote receives the expected tag object and commit;
|
||||
its main and unrelated refs do not change. Follow-tags and mirror configuration
|
||||
cannot expand publication. Note content, tag identity, and one-validation
|
||||
behavior are checked through the public facade. Restrict stage trials to test
|
||||
remotes while failure handling is incomplete.
|
||||
|
||||
Evidence: the public `releasekit.Publish` API captures the committed note,
|
||||
validates once between exact remote guards, creates an unsigned annotated tag,
|
||||
rechecks local and remote state, and pushes only the captured tag object. Bare
|
||||
remote tests verify the note bytes, peeled commit, tag object, unchanged branch
|
||||
and unrelated refs, disabled follow-tags and mirror expansion, validation count,
|
||||
remote conflicts, and retained local tags after push error; Stage 8 adds outcome
|
||||
classification through remote reconciliation.
|
||||
|
||||
## Stage 8: Resolve rejected and ambiguous publication
|
||||
|
||||
Status: Complete. Depends on Stage 7.
|
||||
|
||||
1. Add the one-query reconciliation path and public error/result classification.
|
||||
Preserve the original push cause when resolution does not confirm success.
|
||||
2. Give post-push cancellation a separate bounded recovery context. Retain local
|
||||
tag/object facts when the read fails or recovery is cancelled/times out.
|
||||
3. Add real rejected-push tests using bare-remote hooks. Simulate lost
|
||||
acknowledgments at the subprocess boundary after a real successful push.
|
||||
Separate known absence, conflicting object, and unavailable-query cases.
|
||||
4. Cover a remote branch change during validation and local tag mutation before
|
||||
push. Keep concurrency promises at the observed guard boundaries.
|
||||
|
||||
Acceptance: exact remote object match succeeds despite a reported push error;
|
||||
missing, conflicting, and unavailable remote tags have distinct outcomes. Failed
|
||||
pushes issue one reconciliation query, successful pushes issue none, and no
|
||||
recovery force-update or automatic tag deletion occurs.
|
||||
|
||||
Evidence: failed tag pushes receive one bounded exact-tag query. Matching object
|
||||
identity returns published; absence returns not_published with the original push
|
||||
error; a different object returns conflict; query failure returns unknown while
|
||||
preserving the push cause. Tests cover rejection by a bare remote's receive
|
||||
hook, an installed conflicting tag, unavailable reconciliation, and a lost
|
||||
acknowledgment after the bare remote accepted the tag while the caller context
|
||||
was canceled. Query counts confirm one recovery read after errors and none after
|
||||
a successful push.
|
||||
Tests also verify that a remote branch change during validation and a changed
|
||||
local tag before push prevent publication.
|
||||
|
||||
## Stage 9: Expose publication and document ReleaseKit bootstrap
|
||||
|
||||
Status: Complete. Depends on Stage 8.
|
||||
|
||||
1. Wire the complete public publisher into `releasekit publish`, with selected
|
||||
progress output, final result, exit classification, and signal cancellation.
|
||||
2. Add ReleaseKit's source-only profile and one short maintainer entry script.
|
||||
The profile selects the offline default suite; no inherited race, lint,
|
||||
documentation, image, or platform gates are added.
|
||||
3. Create `docs/release.md` now that publication works. Name authoritative
|
||||
`origin` at the ReleaseKit forge URL and `main`; document preparation,
|
||||
successful-push completion, exact-object recovery, local tag retention, and
|
||||
deliberate cleanup of proven unpublished tags.
|
||||
4. Document first-release execution from the captured candidate source using
|
||||
the local Go toolchain, before a released ReleaseKit executable exists.
|
||||
Include immutable release-note licensing footer construction and dependency
|
||||
preparation separate from validation.
|
||||
5. Update current development documentation and the policy-adoption roadmap's
|
||||
bootstrap status to the implemented boundary. Preserve pending deliverables.
|
||||
|
||||
Acceptance: an end-to-end CLI fixture publishes to a local remote through a
|
||||
committed profile and returns the expected exit/output behavior. Runbook commands
|
||||
are exercised using a temporary repository configured like ReleaseKit. This
|
||||
stage prepares self-publication and does not publish a real ReleaseKit release.
|
||||
|
||||
Evidence: `publish` runs the public publisher with the CLI signal context,
|
||||
selected progress output, final commit and tag-object output, and separate exit
|
||||
status for unresolved outcomes. A temporary committed profile runs the offline
|
||||
test command and publishes to a local bare remote. ReleaseKit's root profile,
|
||||
entry script, CLI and configuration guides, development guide, and maintainer
|
||||
runbook describe source-only publication and exact-object recovery. The
|
||||
runbook's dependency preparation is separate from offline validation. No real
|
||||
ReleaseKit release was published.
|
||||
|
||||
## Stage 10: Build selected targets with shared version injection
|
||||
|
||||
Status: Complete. Depends on Stage 9.
|
||||
|
||||
1. Implement public build values and internal build execution using the fixed
|
||||
flags, version symbol, filename convention, and prepared Go environment.
|
||||
2. Build explicit OS/architecture pairs and verify the application `version`
|
||||
invocation using a host artifact or temporary native build. Preserve
|
||||
caller-owned output files and report partial generated output on failure.
|
||||
3. Return source identity, artifact paths, filenames, targets, hashes, and
|
||||
compiler identity. Keep byte reproducibility and cross-platform execution
|
||||
promises outside the result contract.
|
||||
4. Add a temporary consumer module importing only `buildinfo` and exposing the
|
||||
canonical version command. Its local replacement is fixture-only.
|
||||
|
||||
Acceptance: the fixture compiles for the three initial targets and a native
|
||||
execution reports the injected version. An ambient cross-target environment
|
||||
does not select the smoke host. Empty targets perform no build or smoke test;
|
||||
missing main packages, build failures, incorrect version output, unsafe binary
|
||||
names, and cancellation fail with useful partial results.
|
||||
|
||||
Evidence: `releasekit.Build` and `internal/build` compile Linux amd64, Linux
|
||||
arm64, and macOS arm64 artifacts using the shared linker symbol and prepared
|
||||
local Go environment. The consumer fixture imports `buildinfo` and reports the
|
||||
injected version through its `version` invocation. Results retain the observed
|
||||
source commit, compiler identity, normalized targets, absolute paths, filenames,
|
||||
and SHA-256 digests. Tests cover host selection despite ambient cross-target
|
||||
variables, empty target sets, existing output preservation, partial target
|
||||
failure, missing packages, incorrect version output, unsafe names, and
|
||||
cancellation with completed artifacts retained. No byte-reproducibility or
|
||||
cross-platform execution guarantee is added.
|
||||
|
||||
## Stage 11: Integrate candidate builds and artifact command
|
||||
|
||||
Status: Complete. Depends on Stage 10.
|
||||
|
||||
1. Add build profile fields, CLI `build`, and the private artifact receipt.
|
||||
Bind receipts to source/build-input identity and generated hashes. Validate
|
||||
data on reload; leave the receipt outside the public API and hosted asset list.
|
||||
2. Integrate selected builds into `Check` and `Publish` after the single candidate
|
||||
callback. Use disposable output outside the worktree for candidate builds.
|
||||
Recheck mutable state after the entire validation/build sequence.
|
||||
3. Add ignored `dist` output and source-only and binary-producing examples.
|
||||
Document the API, profile target selection, version invocation, and build
|
||||
output ownership.
|
||||
4. Refresh facade and runtime dependency checks with the new values.
|
||||
|
||||
Acceptance: source-only publication invokes no builder; selected build failure
|
||||
prevents tag creation; selected builds inject the exact candidate version;
|
||||
callback validation runs once. CLI artifacts and receipts agree on filenames,
|
||||
hashes, commit, and resolved build settings. Generated validation output does
|
||||
not dirty the candidate. Continue directly to hosted delivery implementation;
|
||||
no publication or consumer pilot is needed to complete this stage.
|
||||
|
||||
## Stage 12: Find and create Gitea release pages
|
||||
|
||||
Status: Complete. Depends on Stage 11.
|
||||
|
||||
1. Implement the small internal REST transport using the served API operations,
|
||||
explicit destination/token inputs, context cancellation, and structured
|
||||
failure mapping. Use standard HTTP and JSON packages.
|
||||
2. Verify the hosted tag targets the captured source commit. Find a release by
|
||||
tag, create a missing stable release from the committed note, and verify
|
||||
existing note body/tag and stable, non-draft state before accepting it.
|
||||
Preserve the existing title.
|
||||
3. Handle create conflicts and lost acknowledgments by one lookup and content
|
||||
comparison. Never edit the existing page to make it match.
|
||||
4. Add `docs/integrations/gitea.md` describing implemented API interactions,
|
||||
credential supply, source binding, and failure semantics.
|
||||
|
||||
Acceptance: `httptest.Server` covers found, missing, created, conflicting,
|
||||
unauthorized, malformed, cancelled, and ambiguous-create results. A missing or
|
||||
wrong hosted tag prevents page creation. Existing historical titles are retained
|
||||
when the body, tag, and release state match. Fixture assertions cover actual
|
||||
request paths, payloads, and authentication without using real credentials.
|
||||
|
||||
## Stage 13: Inspect asset and manifest content
|
||||
|
||||
Status: Complete. Depends on Stage 12.
|
||||
|
||||
1. Generate the expected binary manifest from the declared build result. Add
|
||||
attachment discovery and streaming hash comparison of existing assets.
|
||||
2. Compare existing `SHA256SUMS` with the complete declared manifest. Identify
|
||||
matching, missing, conflicting, and unverifiable content separately.
|
||||
3. Inspect all declared conflicts before any upload and preserve unrelated
|
||||
attachments. Keep download authorization confined to the configured origin.
|
||||
|
||||
Acceptance: equal name/size with different bytes is conflict; matching content
|
||||
is accepted; a full matching manifest can cover missing binaries; a subset or
|
||||
different manifest is conflict; unreadable content is not treated as missing.
|
||||
Source-only delivery generates no binary manifest. No write endpoint is used
|
||||
by inspection tests.
|
||||
|
||||
## Stage 14: Upload missing assets and report partial delivery
|
||||
|
||||
Status: Complete. Depends on Stage 13.
|
||||
|
||||
1. Add multipart uploads for missing binaries in filename order, followed by a
|
||||
missing manifest. Record completed work and pending asset identities.
|
||||
2. Resolve ambiguous uploads by one resource read and content comparison.
|
||||
Handle concurrent matching uploads without creating replacement content;
|
||||
detect duplicate/conflicting attachment names as conflicts.
|
||||
3. Implement rerun behavior that accepts existing matching files, adds missing
|
||||
ones, and stops on conflicts. Preserve every existing page and attachment.
|
||||
4. Add tests where the first binary succeeds, a later write fails, and a second
|
||||
invocation completes only the missing assets; also cover a lost manifest
|
||||
acknowledgment and failure of the reconciliation read.
|
||||
|
||||
Acceptance: partial and unknown outcomes retain exact completed/pending facts;
|
||||
retries do not overwrite or delete content; no blind repeat POST is made after
|
||||
an ambiguous acknowledgment. Published manifest constraints hold across reruns.
|
||||
|
||||
## Stage 15: Expose tagged-source delivery through the facade and CLI
|
||||
|
||||
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
|
||||
as specified.
|
||||
2. Add delivery profile fields, environment-name token loading in the CLI, and
|
||||
`deliver` with an optional verified assets directory. With no directory,
|
||||
build declared tagged-source artifacts in temporary storage before uploading.
|
||||
An absent build specification or empty target set selects page-only delivery:
|
||||
skip the builder, native smoke, receipt requirement, and manifest generation.
|
||||
3. Accept detached tagged checkouts and historical tags without requiring old
|
||||
remote main equality. Verify receipt identity/hashes before supplied assets
|
||||
are used. Keep the library credential input explicit.
|
||||
4. Add current consumer/CLI guidance for source status, delivery status,
|
||||
retained assets, and retry commands. Extend public boundary checks.
|
||||
|
||||
Acceptance: facade/CLI fixtures cover both page-only delivery and binary delivery
|
||||
from tagged source to a local server, with content-aware reruns. Page-only
|
||||
delivery preserves the complete note, needs no main package or receipt, and
|
||||
performs no Go build or asset upload. Wrong commit, stale build settings or
|
||||
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: Complete. Depends on Stage 15.
|
||||
|
||||
1. Add maintained source-only and binary-producing tag-pipeline templates.
|
||||
Parameterize the Go image and immutable ReleaseKit source pin for eventual
|
||||
deployment, with explicit installation/cache preparation and a delivery
|
||||
secret. Document required template inputs rather than inventing a published
|
||||
pin. Create no new ReleaseKit image-distribution requirement.
|
||||
2. Bind tag and commit variables to the checkout, fetch the selected tag when
|
||||
necessary, share generated assets between steps, and keep output ignored.
|
||||
3. Document preparation versus offline execution, asynchronous status, and
|
||||
rerunning the same immutable tag. The source-only template delivers the note
|
||||
page directly; the binary template first builds its declared assets. Neither
|
||||
workflow executes the publisher.
|
||||
4. Exercise both command sequences locally with a tool built from this checkout,
|
||||
fixture repositories, and a local server. Substitute the local executable for
|
||||
the templates' installation step during development checks. Check YAML using
|
||||
locally available tooling or static inspection; no live runner or new
|
||||
external validator is needed to complete the stage.
|
||||
|
||||
Acceptance: the maintained commands reach common delivery for both profile types
|
||||
and common builds for declared binary targets, with the selected version and
|
||||
commit. Secrets enter only the delivery step. Agent-performed static YAML checks
|
||||
and local command evidence are recorded accurately. No published tool pin,
|
||||
container pull, configured secret, or live runner is a stage prerequisite.
|
||||
CI success is not a source release gate. The
|
||||
[Woodpecker environment reference](https://woodpecker-ci.org/docs/usage/environment)
|
||||
owns the runner-provided tag and commit variables.
|
||||
|
||||
Evidence: maintained source-only and binary tag workflows are in
|
||||
`examples/woodpecker/`. Both parameterize the Go image and immutable ReleaseKit
|
||||
commit through their matrix entries, verify the fetched tag against the runner
|
||||
commit, and keep shared output under the locally ignored `.releasekit/`
|
||||
directory. Only the delivery step maps the configured Woodpecker secret to the
|
||||
CLI token variable. The source-only workflow delivers the note page; the binary
|
||||
workflow prepares module caches, builds declared targets offline, and passes
|
||||
the build receipt and assets into delivery. The delivery guide covers template
|
||||
inputs, source publication versus delivery status, and retries against the same
|
||||
tag. A test builds the CLI from this checkout and exercises both workflows'
|
||||
delivery command sequences against fixture repositories and a local HTTP
|
||||
server; it substitutes the built executable for the installation command. Both
|
||||
YAML files parse with locally available PyYAML 6.0.3, and static checks confirm
|
||||
their tag filters, step layout, and delivery-only secret mapping. `go test ./...`,
|
||||
`go run ./internal/apicheck`, and the Markdown whitespace check pass. No live
|
||||
Woodpecker runner, image pull, secret, or hosted delivery service was used.
|
||||
|
||||
## Stage 17: Prepare ReleaseKit's own hosted-page delivery
|
||||
|
||||
Status: Complete. Depends on Stage 16.
|
||||
|
||||
1. Extend ReleaseKit's source-only profile with its Gitea destination and token
|
||||
environment name. Keep the build target set empty and retain its selected
|
||||
offline candidate suite. No distributed executable or binary manifest is
|
||||
introduced.
|
||||
2. Prepare a repository-specific Woodpecker workflow under the maintained
|
||||
examples, using the tagged checkout to build the local release tool and call
|
||||
page-only delivery. Keep it outside active CI discovery during this sequence.
|
||||
Document where to place it for later activation and how to supply its secret.
|
||||
3. Update the release policy's deliverable declaration and `docs/release.md`
|
||||
together to identify the hosted note page, automation responsibility, and
|
||||
page-delivery retry command. Source completion remains the exact tag push.
|
||||
4. Exercise the prepared command sequence against a temporary tagged repository
|
||||
and local HTTP server. Retain the note's complete body, including licensing
|
||||
footer, on the hosted page.
|
||||
|
||||
Acceptance: ReleaseKit's source-only example creates a hosted page and accepts
|
||||
an identical rerun without building consumer binaries, generating a manifest,
|
||||
requiring a receipt, or consulting a previously released tool. Delivery failure
|
||||
leaves source status unchanged. Workflow preparation requires no real tag,
|
||||
credentials, remote push, CI activation, or maintainer checkpoint.
|
||||
|
||||
Evidence: ReleaseKit's root profile identifies its Gitea destination and
|
||||
`RELEASEKIT_GITEA_TOKEN`, preserves the offline default test suite, and declares
|
||||
no build targets. The repository-specific Woodpecker example remains under
|
||||
`examples/` and builds the CLI from the fetched, commit-checked tag before
|
||||
page-only delivery; the release procedure documents later activation and secret
|
||||
configuration, source-tag completion, and same-tag retry. A local integration
|
||||
test clones and tags a temporary copy of the repository, builds the CLI from
|
||||
that tag, and exercises delivery against a local HTTP server. It verifies a
|
||||
hosted-tag failure leaves the source tag intact, then checks page creation and
|
||||
an identical rerun without assets; the complete note body, including its three
|
||||
license links, is preserved. No real tag, push, credential, or hosted service
|
||||
was used.
|
||||
|
||||
## Stage 18: Complete the initial implementation and handoff documentation
|
||||
|
||||
Status: Complete. Depends on Stage 17.
|
||||
|
||||
1. Map each initial capability in the feature roadmap to its implemented owner
|
||||
and existing behavioral evidence. Record the concrete package and dependency
|
||||
inventory, both supported facades, and their implemented responsibilities in
|
||||
the canonical internal and consumer documentation.
|
||||
2. Finish current API, CLI, configuration, integration, example, development,
|
||||
and release documentation. Check links and consistency with actual behavior;
|
||||
keep licensing and attribution accurate for incorporated material.
|
||||
3. Run the established offline default suite and relevant existing boundary
|
||||
checks for the assembled implementation. Resolve implementation defects
|
||||
within this scope without adding a new permanent release matrix or live
|
||||
testing requirement.
|
||||
4. Record the completed initial implementation and evidence in this plan.
|
||||
Identify prepared integrations whose live operation remains unverified and
|
||||
hand off the implementation for the maintainer's subsequent architecture
|
||||
review. Keep consumer migrations and their anticipated code savings marked
|
||||
as future adoption work.
|
||||
|
||||
Acceptance: the initial library and executable provide check, publication,
|
||||
build, runtime version access, page-only and binary delivery, partial/uncertain
|
||||
recovery, and prepared Woodpecker integration. The documentation describes the
|
||||
implemented boundary accurately. Completion depends on local implementation
|
||||
and development evidence; architectural review, a broader testing plan,
|
||||
consumer migrations, and release/deployment decisions follow this sequence.
|
||||
|
||||
Evidence and handoff: `docs/internal/overview.md` records both public Go
|
||||
facades, all 14 implemented Go packages, the absence of third-party module
|
||||
dependencies, capability ownership, and representative behavioral tests. The
|
||||
README and canonical CLI, configuration, consumer, integration, development,
|
||||
and release documents describe the implemented behavior; the policy and product
|
||||
roadmaps no longer present completed facade, delivery, or workflow work as
|
||||
pending. `go test ./...`, `go run ./internal/apicheck`, local Markdown link and
|
||||
fragment checks, and prose whitespace checks pass. All three maintained
|
||||
Woodpecker examples parse with local PyYAML 6.0.3, with the token mapped only in
|
||||
each delivery step. Local Git and HTTP fixtures exercise source-only delivery,
|
||||
binary delivery, publication recovery, and the ReleaseKit tagged-source workflow.
|
||||
|
||||
The Woodpecker workflows remain prepared, not activated. No live runner,
|
||||
configured deployment secret, immutable deployment pin, hosted Gitea delivery,
|
||||
or ReleaseKit source release was used or verified. Consumer migrations and
|
||||
measurement of removed consumer infrastructure remain future adoption work.
|
||||
The implementation is ready for the maintainer's subsequent architecture
|
||||
review; broader testing and release or deployment decisions remain outside this
|
||||
completed implementation sequence.
|
||||
|
||||
## Coverage of the feature roadmap
|
||||
|
||||
| Initial target responsibility | Implementing stages |
|
||||
| --- | --- |
|
||||
| Two public facades and small runtime dependencies | 1–3, extended in 10–11 and 15 |
|
||||
| Stable version and committed note identity | 5 |
|
||||
| Candidate capture, one validation, mutable guards | 5–8, 11 |
|
||||
| Authoritative endpoint and remote ref state | 6–8 |
|
||||
| Annotated object publication and failure recovery | 7–9 |
|
||||
| ReleaseKit source-only bootstrap/runbook | 9, 17 |
|
||||
| Shared version injection and selected cross-builds | 2, 10–11 |
|
||||
| Native smoke, empty target sets, consistent names | 10–11 |
|
||||
| Hosted page/note creation, including source-only projects | 12, 15, 17 |
|
||||
| Full checksums, comparison, partial/additive retries | 13–15 |
|
||||
| Prepared Woodpecker workflows for both delivery profiles | 16–17 |
|
||||
| Complete initial implementation and canonical documentation | 18 |
|
||||
|
||||
Consumer infrastructure reduction and convergence on the shared standard remain
|
||||
feature-roadmap adoption goals. Their migration sequence, real-world testing,
|
||||
and measured savings will be determined after the initial architecture review.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None block this initial implementation sequence. The maintainer has selected
|
||||
hosted pages for source-only projects and deferred pilots, releases, consumer
|
||||
adoption, and broader testing decisions until after implementation and the
|
||||
subsequent architecture review. Actual release pins and deployment credentials
|
||||
are inputs to later adoption; no stage requires them.
|
||||
Reference in New Issue
Block a user