Plan module-scoped release support

This commit is contained in:
2026-10-09 16:19:05 +00:00
parent 86c1da2cf5
commit f89bdf7edf

View File

@@ -0,0 +1,241 @@
# Roadmap: release individual Go modules
Status: planned feature; open recommendations await resolution.
## Purpose
Implement [ADR 0005](../adr/0005-module-release-scope.md) so a consumer can check
and publish one selected Go module in a shared repository through ReleaseKit's
API and CLI. CommandKit's core and optional integrations provide the initial
consumer case. Each invocation should require only module selection, product
settings, and a semantic version, with ReleaseKit owning the common mechanics.
This roadmap describes the target and the work from the current baseline. It
does not select a ReleaseKit release version or prescribe a staged implementation
plan. Recommendations under Open Decisions are proposals, not accepted contracts.
## Current baseline
The baseline is ReleaseKit v0.3.0 plus accepted ADR 0005; module selection is
not implemented.
- `ReleaseRequest` selects a repository, product, and version. `Candidate` and
`PublicationResult` expose the version without a distinct module or tag name.
- Candidate capture reads `docs/releases/<version>.md` from the captured commit.
Local and remote uniqueness checks, tag creation, push, and reconciliation use
the version as the Git tag.
- The shared validation path runs tests, selected vet, and package compilation
from the repository directory. Optional content checks inspect the committed
repository tree, including nested-module contents.
- Profiles support shared validation and additional commands. CLI product
checks run from the repository directory with candidate/version context.
- Artifact builds and delivery also use repository/version assumptions. The
consumer Woodpecker template selects `refs/tags/v*` and bootstraps ReleaseKit
from repository-root module files.
The existing candidate capture, declarative validation, exact-object publication,
and outcome reporting provide the foundation. Scope and identity need to be
carried through those paths together.
## Targeted end state
An invocation selects one module and one semantic version. Omitted selection
means the repository-root module. For example:
| Selected directory | Semantic version | Complete tag | Committed release note |
| --- | --- | --- | --- |
| Root | `v0.1.0` | `v0.1.0` | `docs/releases/v0.1.0.md` |
| `integrations/ckconfig` | `v0.2.0` | `integrations/ckconfig/v0.2.0` | `integrations/ckconfig/docs/releases/v0.2.0.md` |
| `integrations/ckprompt` | `v0.1.0` | `integrations/ckprompt/v0.1.0` | `integrations/ckprompt/docs/releases/v0.1.0.md` |
All mandatory and selected optional release checks use the selected module's
scope. Independently released nested modules are excluded from their parent's
validation inputs. Checks may read referenced material elsewhere in the
captured repository without adding that material's surrounding files to the
input set. The checkout remains the boundary for outside-checkout link checks.
Repository cleanliness, branch, candidate commit, remote endpoint, and publication
guards remain repository-wide. The complete selected tag governs uniqueness,
publication, and recovery. A successful source-tag push remains completion.
Dependency preparation and sibling release ordering remain consumer activities.
The feature covers individual releases. Batch publication, automatic release
selection, dependency-driven versioning, and arbitrary tag templates remain
outside this roadmap. Artifact and hosted-delivery integration is an open scope
decision below. This work adds no consumer-installation, proxy-availability, CI,
or hosted-delivery completion gate.
## Work needed
### 1. Establish a shared module and release identity
**Rationale:** One resolved identity prevents checks and publication from using
different interpretations of the selected module or tag.
**Target:** Distinct repository directory, module directory, semantic version,
and complete tag are available throughout candidate handling and public evidence.
**Work:** Add an optional repository-relative module selection to the public
request and profile, with root defaults. Resolve it against the captured
repository and committed module declaration. Derive tags using Go's standard
module conventions, including major-version directories: a `/v2` module stored
at `integrations/ckconfig/v2` uses `integrations/ckconfig/v2.0.0` for `v2.0.0`.
Carry the resolved identity through facade conversions, internal requests,
callbacks, results, and CLI diagnostics. Keep semantic-version validation
separate from full-tag handling. Exact field names belong in API design.
### 2. Apply one validation scope
**Rationale:** Consumers should select the release unit once and receive
consistent validation across enabled checks.
**Target:** Tests, vet, package compilation, formatting, distribution checks,
file-size checks, Markdown, and product-check context all correspond to the
selected module and its relevant release materials.
**Work:** Give the existing shared validation path both repository context and
module scope. Run Go commands in the module directory with the existing offline
and workspace-disabled environment. Select committed file inputs once under the
agreed boundary convention and apply that selection to each content check.
Retain repository access for resolving Markdown destinations and existing
committed-file references. A link to another module may be checked for existence
or its target heading without scanning that module's unrelated documents.
Update module-distribution inspection to examine the selected release's inputs.
For example, an unrelated sibling's filesystem replacement should not fail the
selected module's check. Determine relevant shared release materials through
existing conventions; shared files should not pull in an entire parent tree.
Keep the optional checks optional and retain their existing individual rules,
error identities, cancellation, and cause propagation apart from the intended
scope change. Resolve boundary identification and path conventions below before
finalizing these contracts.
### 3. Bind notes and publication to the resolved identity
**Rationale:** Different modules can use the same semantic version while
publishing distinct source identities and release notes.
**Target:** The selected module's committed note identifies its product and
semantic version. Publication and recovery address its complete tag.
**Work:** Resolve module-local note paths and retain existing title validation
and captured note bytes. Thread the complete tag through local guards, remote
guards, annotated-tag creation, exact-object push, and bounded reconciliation.
Include the module, version, and resolved tag in success and failure evidence
as available, alongside commit, endpoint, phase, state, and tag object. Preserve
the existing publication outcomes and repository checks. Root notes and tags
retain their ordinary forms.
### 4. Make API and CLI adoption small and coherent
**Rationale:** The shared release operation should replace consumer publication
logic with small per-module declarations.
**Target:** A shared launcher can select a profile and pass a semantic version;
API consumers express the equivalent operation. Additional checks receive
module context and repository context for explicit composition work.
**Work:** Map profile selection into the shared request, document relative-path
behavior, and provide module/tag context to configured commands. Retain existing
profile selection through `--config`; a separate CLI override for the module is
not needed to satisfy the initial request. Add a maintained multi-module example
showing root and integration profiles and a small shared launcher. Show dependency
preparation before offline validation and sequential sibling releases when a
dependency version must be published first. Keep product checks focused on
consumer assertions instead of repeating the standard suite.
### 5. Verify and document the complete behavior
**Rationale:** This changes release identity and validation boundaries, including
the behavior of root modules with nested modules.
**Target:** Representative public API and CLI workflows establish that the
selected module is validated and only its intended tag is published.
**Work:** Extend existing behavioral tests using local repositories and remotes.
Cover root defaults; nested-module failure while the root suite passes; equal
versions across modules; major-version directories; full-tag reuse; and failed
or unknown publication with the correct recovery identity. Exercise optional
checks with violations inside and outside the selected scope, parent selection
excluding independent nested modules, and cross-module Markdown references.
Verify that repository guards still observe changes outside the selected module
and that module selection does not repeat the standard suite. Reuse existing
failure tests where they already protect unchanged behavior.
Update GoDoc, CLI/configuration references, check/publication guides, adoption
examples, and recovery guidance together. Explain root-module scope changes in
the release note and migration guidance. Document semantic version versus full
tag in note titles and source/licensing links. ReleaseKit's own maintainer policy
continues to describe its root-module release; consumer guidance explains how
multi-module consumers adapt their policies. Run the normal offline suite and
public API checks for implementation changes; validate documentation links and
examples. Synthetic dependency fixtures use isolated module caches.
## Open Decisions
### 1. How should nested module boundaries be recognized?
**Recommendation:** Use committed nested `go.mod` locations as module boundaries
for ordinary source directories. This follows Go's module structure and avoids
a second registry of independently versioned products. Specify treatment of
vendored content and fixture modules before implementation: vendored material
remains part of the selected module's file-check inputs, while nested fixture
modules can be exercised through the parent's tests or product checks. A
repository-level workspace file outside a selected nested module's scope would
not fail that module's workspace-file check merely because it exists.
The tradeoff is that a nested fixture module can be excluded from generic file
checks even when it has no independent release. That distinction needs clear
documentation and representative tests.
**Alternative:** Declare independently released module directories explicitly
and exclude only those boundaries. This distinguishes products from fixtures
precisely and keeps fixture files in their parent's generic validation. It adds
a declaration consumers must maintain and coordinate with their module layout.
It is viable if real consumers need that distinction enough to justify the
configuration.
### 2. Which directory anchors relative paths and product commands?
**Recommendation:** Anchor module selection and profile lookup at the repository;
anchor module-owned validation settings, such as file-size exclusions, and
configured product-command execution at the selected module. Keep diagnostic
file paths repository-relative and expose both directories to product commands.
Markdown destinations remain relative to their source documents. This makes a
per-module profile self-contained while retaining unambiguous findings.
Existing root profiles retain their meaning. Nested-module launchers would use
the provided repository context when invoking shared scripts. Document these
rules together rather than adding a path-base switch to each check.
**Alternative:** Keep configuration paths and product-command execution
repository-relative, while shared check inputs remain module-scoped. This
preserves the current conventions and makes shared script invocation direct.
It requires module prefixes in otherwise module-specific settings and makes
moving or copying profiles more cumbersome. Both choices can implement the
accepted validation scope.
### 3. Should nested-module builds and hosted delivery ship with publication?
**Recommendation:** Deliver the requested source-only `Check` and `Publish`
capability first. Keep existing root build/delivery workflows working and document
the supported boundary. For that initial increment, report an unsupported
nested-module artifact-build request before validation or publication rather
than building the root product under the nested module's release identity.
This proposed limitation requires an explicit scope decision; it is not imposed
by ADR 0005. Package compilation remains part of module validation and is covered
by this roadmap.
This meets CommandKit's immediate need with a focused change, at the cost of
requiring follow-up work for consumers needing nested-module artifacts or hosted
pages. Review shared profile handling so unsupported delivery paths do not
silently interpret a nested module as the root product.
**Alternative:** Extend artifact builds and hosted delivery in the same release.
This gives every release operation the same module model immediately. It adds
work on build paths, semantic-version injection, receipts, tag verification,
note/source URLs, dependency preparation, and CI profile/tool selection. The
maintained tag filter and root-only bootstrap also need adaptation. This is a
viable cohesive release if those consumers are ready; it expands the sprint
beyond the source-only publication request. Delivery remains asynchronous under
either choice.