diff --git a/README.md b/README.md index 15bdb2f..1b4aefb 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,13 @@ tagged-source delivery API, and the `version`, `check`, `publish`, `build`, maintainer procedure and prepared Woodpecker workflow for hosted note-page delivery are documented. ReleaseKit does not declare binary deliverables. +Release operations can select one Go module within a repository. The repository +root remains the default; a selected module's declared import path and physical +directory determine its complete Git tag and module-local release note. See the +[candidate check](docs/consumers/check.md), +[publication](docs/consumers/publish.md), and +[multi-module example](examples/multi-module/). + See the [consumer adoption guide](docs/consumers/adoption.md) to add ReleaseKit as a versioned Go tool or package dependency, and the [v0.1.0 release note](docs/releases/v0.1.0.md) for the initial baseline. diff --git a/check.go b/check.go index a46abf6..9a69d4a 100644 --- a/check.go +++ b/check.go @@ -26,7 +26,7 @@ type Candidate struct { ModulePath string Tag string Commit string - Version string + Version string // selected stable semantic version. } // ReleaseRequest contains the inputs used to validate and optionally build one @@ -37,8 +37,8 @@ type ReleaseRequest struct { // ModuleDir selects a repository-relative module directory; empty selects // the repository root. ModuleDir string - Product string - Version string + Product string + Version string // stable semantic version, independent of the derived Git tag. Remote string // ExpectedPushURL optionally requires Publish's resolved push URL to match // this string exactly before validation or tag creation. Check ignores this @@ -56,8 +56,10 @@ type ReleaseRequest struct { // preserves the current validation behavior. type ValidationSpec struct { // SharedFiles adds repository-relative committed files to optional file - // checks. Nil selects the optional defaults; an empty non-nil slice selects - // none. Explicit files are checked for presence even when file checks are off. + // checks. Nil selects the optional root COPYRIGHT, LICENSE, and + // docs/oss/attribution.md defaults; an empty non-nil slice selects none. + // Explicit files replace the defaults and must exist even when file checks + // are off. SharedFiles []string Go GoValidationSpec // GoFormat checks the formatting of committed regular Go source files. It diff --git a/delivery.go b/delivery.go index 551a17e..e69fa5c 100644 --- a/delivery.go +++ b/delivery.go @@ -51,7 +51,8 @@ type DeliveryRequest struct { ModuleDir string Product string Version string - // ExpectedTag optionally binds delivery to the full tag that triggered a CI event. + // ExpectedTag optionally requires the full CI event tag to match the + // selected module's derived tag before building or making hosted requests. ExpectedTag string Destination GiteaDestination // Build selects binaries to build in temporary storage outside the checkout. @@ -70,8 +71,8 @@ type DeliveryResult struct { RepositoryDir string ModuleDir string ModulePath string - Tag string - Version string + Tag string // complete derived Git tag. + Version string // selected stable semantic version. CandidateCommit string ReleaseURL string State DeliveryState diff --git a/docs/config.md b/docs/config.md index 5af98b7..a365ef2 100644 --- a/docs/config.md +++ b/docs/config.md @@ -9,7 +9,7 @@ The current profile fields are: | Field | Required | Behavior | | --- | --- | --- | | `product` | Yes | Product name used by release operations. | -| `module_dir` | No | Repository-relative physical Go module directory; omission selects `.` (the repository root). | +| `module_dir` | No | Repository-relative physical Go module directory with its own `go.mod`; omission selects `.` (the repository root). | | `remote` | No | Selected Git remote; defaults to `origin`. | | `expected_push_url` | No | Exact effective push URL required by `publish`; ignored by local `check`. | | `checks` | No | Ordered additional child commands, each with an argument vector and optional environment map. | @@ -17,6 +17,13 @@ The current profile fields are: | `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. | +`module_dir` names the selected module's physical location in the repository; +ReleaseKit reads its declared import path from that module's own `go.mod`. The +physical directory and declared path are distinct: a declared `/v2` module can +live either at `integrations/core` or `integrations/core/v2`, while both use the +same full release tag. Root-only profiles can omit `module_dir` and do not need +a module map. + Each check requires a nonempty `args` array whose first element names the executable. Arguments are passed directly to the child process; ReleaseKit does not parse a shell command string. Select a shell explicitly when a check needs @@ -30,10 +37,13 @@ target requires the package and binary name; each target is written as one The optional `validation` object selects shared checks implemented by ReleaseKit. `validation.shared_files` is a committed file list resolved from the repository -root. Omission or `null` uses the optional defaults for enabled file checks; -`[]` selects no shared files. Each explicit file must exist in the candidate, -even when no file checks are enabled. Paths are literal and have no glob -semantics. This field does not enable any checks. +root. Omission or `null` uses `COPYRIGHT`, `LICENSE`, and +`docs/oss/attribution.md` when present for enabled file checks; `[]` selects no +shared files. An explicit list replaces those defaults. Each explicit file must +exist in the candidate, even when no file checks are enabled. Paths are literal, +repository-relative files with no glob semantics and may select a file outside +the chosen module. ReleaseKit deduplicates them with module inputs by path. This +field does not enable any checks. `validation.go.race` enables the race detector for the single standard Go test suite. `validation.go.full_vet` runs a separate native `go vet` pass after that suite succeeds; ReleaseKit disables test-time vet for that suite to avoid @@ -191,8 +201,10 @@ credentials. An optional `--expected-module` checks a launcher's module selection against the profile. It runs `go mod download` only when the profile has selected build targets; source-only delivery does not need application dependencies. Default preparation may access the network and may update -`go.sum`. The command takes CI values as arguments, so profile settings remain -independent of Woodpecker environment variable names. See the +`go.sum`. For binary tagged delivery, prepare and commit that module's sums +before tagging so dependency preparation leaves the tagged checkout clean. The +command takes CI values as arguments, so profile settings remain independent of +Woodpecker environment variable names. See the [CLI contract](cli.md) for the invocation and exit statuses. This application dependency preparation is separate from bootstrapping the diff --git a/docs/consumers/adoption.md b/docs/consumers/adoption.md index 378c1ab..896f4df 100644 --- a/docs/consumers/adoption.md +++ b/docs/consumers/adoption.md @@ -20,10 +20,11 @@ declaration retains the dependency through `go mod tidy`. Commit the resulting `go.mod` and `go.sum` changes. To upgrade, repeat the command with the chosen version and review the module changes. -Go tool dependencies require Go 1.24 or later, together with a toolchain that -satisfies the selected ReleaseKit version and its dependencies. Tools share the -consumer's module graph: their requirements participate in dependency version -selection and can raise the consumer module's Go minimum. See the +The Go tool dependency feature requires Go 1.24 or later. The current ReleaseKit +module declares a Go 1.26.0 minimum, so use Go 1.26.0 or later for the current +release. Tool dependencies share the consumer's module graph: their requirements +participate in dependency version selection and can raise the consumer module's +Go minimum. See the [Go tool dependency reference](https://go.dev/ref/mod#go-mod-file-tool). Run `go tool releasekit` from within the consumer module to use its selected diff --git a/docs/consumers/check.md b/docs/consumers/check.md index 284c0a5..35032ef 100644 --- a/docs/consumers/check.md +++ b/docs/consumers/check.md @@ -21,6 +21,17 @@ if err != nil { fmt.Println(result.Version, result.Commit) ``` +Set `ReleaseRequest.ModuleDir` to select a nested module using a +repository-relative physical directory; omission or `.` selects the root +module. ReleaseKit reads that module's committed `go.mod` and returns its +physical `ModuleDir`, declared `ModulePath`, semantic `Version`, and complete +`Tag` in the candidate and result. A physical `/v2` directory is removed from +the tag prefix only when the declared module path also ends in `/v2`. For +example, both `integrations/core/v2` and `integrations/core` can declare +`example.com/project/integrations/core/v2` and use the tag +`integrations/core/v2.1.0`. The release note lives under the physical module at +`/docs/releases/.md`. + The repository must have a clean index and worktree on `main`, and the selected version must be stable `vMAJOR.MINOR.PATCH`. The committed `docs/releases/.md` note must have a first Markdown H1 containing the @@ -79,7 +90,19 @@ standard suite, selected vet/format/distribution checks, or Markdown navigation checks in `AdditionalChecks` or profile `checks`. Keep release-note rules and consumer-specific assertions—such as tests of maintained examples—in those product-owned checks. -ReleaseKit calls `AdditionalChecks` once after shared validation when supplied. +The `Candidate` supplies both `RepositoryDir` and `ModuleDir`, plus the declared +`ModulePath`, semantic `Version`, and full `Tag`; use its module directory for +module-local product checks. ReleaseKit calls `AdditionalChecks` once after +shared validation when supplied. + +`ValidationSpec.SharedFiles` adds committed, repository-relative files to +ReleaseKit's optional file checks without enabling any checks. A nil slice +selects the optional defaults `COPYRIGHT`, `LICENSE`, and +`docs/oss/attribution.md`, when present; a non-nil empty slice selects none. +Explicit files replace those defaults, must exist even when file checks are +disabled, and may be in another module. Combined inputs are deduplicated by +repository-relative path. + It does not download a different toolchain automatically. If race prerequisites are unavailable, the `go-test` check fails rather than being skipped; a selected full-vet failure is reported as `go-vet`. The suite uses the Go host target, diff --git a/docs/consumers/delivery.md b/docs/consumers/delivery.md index f57e308..0d59edb 100644 --- a/docs/consumers/delivery.md +++ b/docs/consumers/delivery.md @@ -27,7 +27,7 @@ or hosted content. ```go err := releasekit.PrepareTaggedCheckout(ctx, releasekit.TaggedCheckoutRequest{ RepositoryDir: repositoryDir, - Version: version, + Tag: "integrations/example/v1.2.3", ExpectedCommit: ciCommit, }) if err != nil { @@ -42,11 +42,18 @@ module with workspace discovery disabled and the available compatible local Go toolchain. The operation may use the network and updates the Go module cache while preserving the caller's proxy, private-module, credential, and cache settings. -If checksums are missing, Go may update `go.sum`; see the +If checksums are missing, Go may update `go.sum`. For binary CI delivery, prepare +and commit the selected module's `go.sum` before tagging: delivery verifies the +tagged source remains clean after dependency preparation. See the [Go Modules Reference](https://go.dev/ref/mod#go-mod-download). Cancellation and command errors are returned. Page-only profiles do not need dependency preparation. +Set `TaggedCheckoutRequest.VerifyOnly` when a bootstrap step already fetched and +detached the event tag. This mode checks the exact tag, expected commit, `HEAD`, +and clean worktree without fetching or changing the checkout. Both modes require +the full `Tag` and expected commit. + ## Command line Add a Gitea destination to the profile: @@ -199,10 +206,21 @@ without another fetch or checkout. It loads the tagged profile and downloads application dependencies only when build targets are selected; it builds and delivers those targets with the note page. Source-only profiles skip application dependency downloads and binary work. Dependency preparation for binaries may -use the network and may update an uncommitted checksum file in the checkout. A +use the network. Prepare and commit the selected module's `go.sum` before +tagging; an uncommitted change makes the later delivery source check fail. A retry still uses the same immutable tag and that tag's module settings, even after the default branch selects a newer ReleaseKit version. +The root-only [`tag-delivery.yml`](../../examples/woodpecker/tag-delivery.yml) +keeps the small default profile and root-module bootstrap. For consumers that +release several modules from one repository, copy the contents of the maintained +[multi-module example](../../examples/multi-module/) to the consumer repository +root and use its [`woodpecker.yml`](../../examples/multi-module/woodpecker.yml), +[`release-modules.tsv`](../../examples/multi-module/release-modules.tsv), and +shared selector. The event tag chooses one row from the tagged checkout; the +profile and physical module must agree, and ReleaseKit verifies the derived tag. +The example covers source-only integration pages and a binary core module. + If the application does not declare ReleaseKit as a module dependency, install the executable separately and invoke the same `ci-deliver` command. For ReleaseKit's own source workflow, the maintained diff --git a/docs/consumers/publish.md b/docs/consumers/publish.md index 25e7a4f..5b5ca9c 100644 --- a/docs/consumers/publish.md +++ b/docs/consumers/publish.md @@ -6,6 +6,7 @@ annotated source tag: ```go result, err := releasekit.Publish(ctx, releasekit.ReleaseRequest{ RepositoryDir: "/work/project", + ModuleDir: "integrations/example", Product: "Example", Version: "v1.2.3", ExpectedPushURL: "ssh://git.example/owner/example.git", @@ -19,9 +20,22 @@ result, err := releasekit.Publish(ctx, releasekit.ReleaseRequest{ if err != nil { return err } -fmt.Println(result.Version, result.CandidateCommit, result.TagObject) +fmt.Println(result.ModulePath, result.Version, result.Tag, result.CandidateCommit, result.TagObject) ``` +`ModuleDir` is a repository-relative physical module directory; omit it or use +`.` for a root-module release. ReleaseKit reads the selected module's committed +declaration and derives the complete Git tag from its declared module path and +physical location. `Version` remains the stable semantic version. The note is +`/docs/releases/.md`; an on-disk `/v2` directory is part of +the note path but is removed from the tag prefix only when the module path ends +in `/v2`. `PublicationResult` returns the absolute `ModuleDir`, declared +`ModulePath`, complete `Tag`, and existing commit and tag-object evidence. + +The optional `ValidationSpec.SharedFiles` selects additional committed files +for enabled file checks. Its nil and empty-slice behavior is described in the +[candidate check guide](check.md#local-candidate-check). + Publication captures a clean candidate on `main`, validates its committed release note, and checks the selected remote before running candidate checks. Set `ExpectedPushURL` to require the effective push destination to match an diff --git a/docs/integrations/gitea.md b/docs/integrations/gitea.md index 1908542..06202c2 100644 --- a/docs/integrations/gitea.md +++ b/docs/integrations/gitea.md @@ -13,10 +13,19 @@ the `Authorization: token …` request header and is not included in errors or results. The base URL must use HTTP or HTTPS and cannot contain URL credentials, a query, or a fragment. -The selected module derives a complete tag from its semantic version and -physical repository-relative directory. For example, version `v1.2.3` in -`integrations/ckconfig` uses `integrations/ckconfig/v1.2.3`; a root module uses -`v1.2.3`. The client first reads +The selected module derives a complete tag from its semantic version, declared +module path, and physical repository-relative directory. For example, version +`v1.2.3` in `integrations/ckconfig` uses +`integrations/ckconfig/v1.2.3`; a root module uses `v1.2.3`. A `/v2` module +stored at `integrations/core/v2` uses `integrations/core/v2.1.0`; the same +declared module stored at `integrations/core` derives the same tag. ReleaseKit +removes a final physical `/v2` directory from the tag prefix only when the +module declaration has that `/v2` suffix. A module-local note stays at +`/docs/releases/.md`, including a physical `/v2` directory. +Shared license files remain at the repository root. Use the complete derived +tag as the immutable source ref in note links, with paths rooted at the +repository; license footer links target the root `COPYRIGHT`, `LICENSE`, and +`docs/oss/attribution.md` files. The client first reads `/api/v1/repos/{owner}/{repo}/tags/{tag}` and requires the hosted tag's commit SHA to equal the captured source commit. It then reads `/api/v1/repos/{owner}/{repo}/releases/tags/{tag}`. A matching existing page diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 916a941..178053e 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -25,7 +25,7 @@ Go declarations and GoDoc remain the owners of exact exported contracts. ## Module and dependencies The module is `gitea.maximumdirect.net/eric/ReleaseKit`, with Go language -version `1.25.0`. `go.mod` requires `golang.org/x/mod` and Goldmark for internal +version `1.26.0`. `go.mod` requires `golang.org/x/mod` and Goldmark for internal validation; public facades do not expose either dependency. `go list ./...` reports these implemented packages: @@ -46,6 +46,7 @@ reports these implemented packages: | `internal/tempdir` | Disposable system temporary storage outside source worktrees. | | `internal/process` | Cancellable child-process execution, including owned stdin/stdout pipes for serialized exchanges, with per-command environment overlays and removals. | | `internal/preparation` | Coordination for expected-commit tag checkout and Go module dependency preparation. | +| `internal/releaseidentity` | Shared module selection, declaration reading, and semantic-version-to-tag derivation for committed and working-tree operations. | | `internal/validation` | Shared Go validation with optional race, full-vet, and static package-compilation target selections, formatting, workspace-file and filesystem-replacement checks, per-blob size limits, and selected Markdown destination and fragment checking; `internal/candidate` retains capture, callback sequencing, and local-state rechecks. | | `internal/publish` | Publication guards, one validation run, annotated tag creation, push, and recovery state. | | `internal/runtimeinfo` | Injected version selection and cached fallback metadata lookup for the runtime facade. | @@ -90,8 +91,9 @@ not a separate release matrix: | Cross-builds, version smoke checks, module paths, empty target sets, and partial outputs | `releasekit.Build`, `internal/build`, `internal/artifact`, `internal/tempdir`, `buildinfo` | `TestBuildCreatesSelectedTargetsAndInjectsVersion`, `TestBuildUsesNestedWorkingTreeModuleAndModuleRelativeOutput`, `TestBuildResolvesDirtyWorkingTreeDeclaration`, `TestBuildWithNoTargetsDoesNotInvokeCompiler`, `TestBuildReturnsPartialArtifactsAfterTargetFailure`, `TestNormalizeSettingsKeepsBuildInputsAndNormalizesTargets`, `TestOutsideFallsBackWhenTemporaryDirectoryIsInsideWorktree` | | Page-only and managed or prebuilt binary delivery | `releasekit.Deliver`, `internal/delivery`, `internal/gitea`, CLI | `TestDeliverPageOnlySkipsBuildAndHostedAssets`, `TestDeliverUsesCommittedModuleIdentityForSeparatePages`, `TestDeliverRejectsPrebuiltArtifactsForAnotherModuleBeforeHostedRequests`, `TestDeliverManagedBuildUploadsArtifactsAndCleansTemporaryOutput`, `TestDeliverBinaryConsumerWithBuildinfoAndSelectedTargets`, `TestDeliverPrebuiltArtifactsRemainCallerOwned`, `TestDeliverRejectsSameSizePrebuiltTamperingBeforeHostedWrites`, `TestDeliverManagedBuildFailureCleansTemporaryOutputBeforeHostedWrites`, `TestDeliverManagedBuildCancellationCleansTemporaryOutput`, `TestDeliverBuildsTaggedArtifactsAndReusesAssets`, `TestDeliverRejectsTamperedAssetsAndStaleReceiptBeforeRemoteWrites`, `TestEnsureReleaseEscapesSlashContainingTag` | | Tagged checkout and build dependency preparation | `releasekit.PrepareTaggedCheckout`, `releasekit.PrepareBuildDependencies`, `internal/preparation`, `internal/git`, `internal/gotool` | `TestPrepareTaggedCheckoutFetchesExpectedCommitAndDetaches`, `TestPrepareTaggedCheckoutRejectsWrongCommitBeforeCheckout`, `TestPrepareTaggedCheckoutReportsLocalCheckoutConflict`, `TestPrepareTaggedCheckoutReportsConflictingLocalTag`, `TestPrepareBuildDependenciesUsesSelectedModuleDirectory`, `TestPrepareBuildDependenciesPreservesPreparationEnvironment`, `TestPrepareBuildDependenciesPropagatesCommandFailure`, `TestPrepareBuildDependenciesPropagatesCancellation` | +| Shared module identity and tag derivation | `internal/releaseidentity`, `internal/candidate`, `internal/build`, `internal/delivery` | `TestDeriveUsesModuleDeclarationAndPhysicalLayout`, `TestCommittedAndWorkingTreeDeclarationsUseTheirOwnSources`, `TestSelectedNestedModuleDoesNotRequireRootDeclaration`, `TestBuildResolvesDirtyWorkingTreeDeclaration`, `TestDeliverUsesCommittedModuleIdentityForSeparatePages` | | Page, manifest, asset comparison, and additive retry outcomes | `internal/gitea` | `TestEnsureReleaseCreatesMissingPageFromCommittedNote`, `TestInspectAssetsDetectsSameNameAndSizeWithDifferentBytes`, `TestUploadMissingPartialFailureThenRerunOnlyMissingAssets` | -| CLI profiles and prepared Woodpecker sequences | `cmd/releasekit`, `cmd/releasekit/internal/cli`, `examples/woodpecker/` | `TestLoadSettingsRejectsInvalidProfiles`, `TestWoodpeckerTagDeliveryTemplate`, `TestWoodpeckerTagDeliveryUsesTaggedModuleVersion`, `TestWoodpeckerSourceDeliveryTemplateSelfBootstraps`, `TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout` | +| CLI profiles and prepared Woodpecker sequences | `cmd/releasekit`, `cmd/releasekit/internal/cli`, `examples/woodpecker/`, `examples/multi-module/` | `TestLoadSettingsRejectsInvalidProfiles`, `TestWoodpeckerTagDeliveryTemplate`, `TestWoodpeckerTagDeliveryUsesTaggedModuleVersion`, `TestWoodpeckerSourceDeliveryTemplateSelfBootstraps`, `TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout`, `TestMultiModuleSelectorMapsSelectorsAndTags`, `TestMultiModuleLauncherUsesSelectedModuleAndProfile`, `TestMultiModuleWoodpeckerDelivery` | Run the complete suite with `go test ./...`. The public API and import boundary check is `go run ./internal/apicheck`. Local HTTP and Git fixtures exercise diff --git a/docs/internal/validation.md b/docs/internal/validation.md index 4bb3ff0..f6a5af5 100644 --- a/docs/internal/validation.md +++ b/docs/internal/validation.md @@ -27,6 +27,19 @@ on parse or inspection errors. It runs before product checks and build callbacks `Request.ReadCandidateTree` lets selected file checks request candidate contents; the Go-only path does not enumerate the tree. +## Selected validation inputs + +`CandidateTree` keeps the full committed repository lookup separate from the +ordered file input set. The selected module's committed regular-file inputs +exclude independently released nested modules, while vendored contents stay +in scope. Explicit shared-file selections are normalized from repository-root +paths, added as individual files, and deduplicated with module inputs by path. +File-size exclusions are normalized from the selected module directory. Link +resolution can still inspect a committed destination outside the selected input +set without adding that destination's content to the checks. The public +selection, nil/empty behavior, and profile path bases belong to the +[configuration reference](../config.md) and the root facade's GoDoc. + The workspace-file check uses that same candidate inventory and reports blob entries named go.work or go.work.sum, including nested paths and symlink blobs. It does not read workspace contents or depend on the workspace selected for Go diff --git a/docs/release.md b/docs/release.md index 2862240..22d375a 100644 --- a/docs/release.md +++ b/docs/release.md @@ -28,16 +28,12 @@ The maintained [source-delivery image](../examples/woodpecker/releasekit-source- and [consumer template image](../examples/woodpecker/tag-delivery.yml) follow the chosen build toolchain; update them together when that selection changes. -The current consumer minimum is declared in [go.mod](../go.mod). When preparing -a release that raises it to Go 1.26, the normal declaration is: - -```sh -go mod edit -go=1.26.0 -``` - -Retain any higher patch minimum required by dependencies or a specific fix. -Make module changes before committing the candidate. A release preserving the -existing minimum keeps its current declaration. Minimum increases must fit the +The current consumer minimum is Go 1.26.0, declared in [go.mod](../go.mod). +Keep it for a release unless release preparation deliberately selects a newer +series under the [Go support policy](policy/release.md#consumer-minimum-and-release-toolchain). +When increasing it, update `go.mod` to the first stable version of the selected +series, or to a higher patch when a dependency or specific fix requires one. +Make module changes before committing the candidate. Minimum increases must fit the [compatibility policy](policy/release.md#versioning-and-compatibility); before v1.0.0, an increase belongs in a minor release. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 542ea43..fccbe68 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # Implementation plan: individual Go module releases -Status: ready for implementation. +Status: complete; all 15 stages implemented and locally verified. ## Objective and authority @@ -756,6 +756,17 @@ evidence describe the complete implemented feature. record the full-suite and compiled API check results, and confirm that the implemented examples and canonical documentation agree with the current API. +**Completed:** Updated facade GoDoc, consumer and CLI/configuration guidance, +Gitea and internal ownership documents, recovery guidance, and maintained +examples for module selection, full tags, path bases, shared files, preparation, +and receipt ownership. Added pending next-release notes with migration guidance +and corrected the current Go minimum facts. Audited acceptance coverage against +the stage-owned tests and reviewed ReleaseKit's root release procedure against +the adopted release policy; no new release gates were added. Verified +`go test ./...`, `go run ./internal/apicheck`, local links and heading fragments +in 13 changed Markdown documents, multi-module shell/config/module syntax, and +`git diff --check`. + ### Acceptance coverage audit | Requirement | Primary stage/evidence owner | diff --git a/docs/roadmap/next-release-notes.md b/docs/roadmap/next-release-notes.md new file mode 100644 index 0000000..5d5ef8a --- /dev/null +++ b/docs/roadmap/next-release-notes.md @@ -0,0 +1,100 @@ +# Pending notes for the next release + +Status: pending release preparation. This feature does not select a release +version or move this draft to `docs/releases/.md`. + +## Release individual Go modules + +ReleaseKit operations can now select one Go module within a Git repository. +Omitted module selection retains the repository-root default. A selected module +is identified by both its repository-relative physical directory and its own +declared module path. ReleaseKit derives a semantic version's complete Git tag +from that identity, including Go's `/v2` major-version convention. For example, +`v2.1.0` for a module declared as `example.com/project/integrations/core/v2` +uses `integrations/core/v2.1.0`, whether the module is physically stored at +`integrations/core` or `integrations/core/v2`. Its release note stays at the +physical module's `docs/releases/v2.1.0.md` path. + +The public `Check`, `Publish`, `Build`, and `Deliver` requests add `ModuleDir`; +results expose the resolved module directory, declared module path, and complete +tag alongside existing commit and outcome evidence. `Version` remains the +stable semantic version used in note titles, binary version output, and asset +names. Git publication and hosted delivery use the complete tag. Product +commands receive both repository and module paths, and candidate callbacks +receive the module identity. + +`ValidationSpec.SharedFiles` and profile `validation.shared_files` allow a +repository-relative list of committed shared files to join optional file +checks. Omission or `null` selects the available root `COPYRIGHT`, `LICENSE`, +and `docs/oss/attribution.md` defaults; an explicit list replaces those +defaults, and `[]` selects none. Explicit files must exist even when file +checks are disabled. This selection does not enable a check. + +Profiles add `module_dir` for physical module selection. The CLI's `ci-deliver` +now takes a full Git `TAG`; its final path component supplies the semantic +version. The optional `--prepared` mode verifies an already prepared checkout +without fetching or checking it out again. `--expected-module` binds a mapped +launcher selection to the selected profile. The public tagged-checkout request +renames `Version` to `Tag` and adds `VerifyOnly`; dependency preparation now +takes a `DependencyPreparationRequest` with repository and module directories. +`DeliveryRequest.ExpectedTag` binds delivery to the exact CI event tag before +building artifacts or contacting Gitea. + +The private `.releasekit-build.json` receipt now requires schema version 1 and +binds artifacts to the module directory, declared module path, semantic +version, complete tag, source commit, normalized build settings, and artifact +declarations. Older and unversioned receipts are rejected; rebuild with the +updated `build` command before using `deliver --assets DIR`. + +The maintained [multi-module example](../../examples/multi-module/) shares a +four-column `release-modules.tsv` and POSIX selector between its local launcher +and mapped Woodpecker workflow. The workflow verifies and detaches the triggering +tag before reading the mapping, profile, module files, or ReleaseKit version. +Retries therefore use the original tagged source after the default branch +changes. Root-only consumers can keep the ordinary profile and the simpler +[root tag workflow](../../examples/woodpecker/tag-delivery.yml) without a map. + +## Consumer migration + +Update callers, profiles, receipts, and CI declarations together for this +clean interface cutover; compatibility shims and legacy receipt readers are +not provided. + +- Set `ModuleDir` in Go requests or `module_dir` in profiles for a nested + module. The selected directory must contain its own `go.mod`; module paths + and release tags are read from that declaration, not inferred from a folder + name. Keep `Version` as a semantic version in ordinary commands and API calls. +- Update reads of result identity to use `ModuleDir`, `ModulePath`, and `Tag` + where needed. Product commands can use `RELEASEKIT_REPOSITORY_DIR` and + `RELEASEKIT_MODULE_DIR` to distinguish repository-level work from + module-local checks. +- Replace `TaggedCheckoutRequest.Version` with the complete `Tag`. Set + `VerifyOnly` when a bootstrap step already verified and detached the event + checkout. Change `PrepareBuildDependencies` calls to pass a + `DependencyPreparationRequest`. +- Add `module_dir` and, when needed, `validation.shared_files` to profiles. + Recheck profile-relative and repository-relative paths. Prepare and commit + each binary module's `go.sum` before tagging so dependency preparation leaves + the tagged source clean for delivery verification. +- Change `ci-deliver VERSION` invocations to pass the full event `TAG` and + required `--commit OID`. Maintained bootstraps should use `--prepared` after + verifying the tag and commit. A mapped launcher should pass + `--expected-module DIR`; the profile remains the source of selection. +- Regenerate existing build receipts with the new `build` command before + prebuilt delivery. Do not edit old receipts into the new format. +- Root-module validation now excludes independently released nested modules + from module-scoped file checks. Run a nested module's checks from that module + when it is the release unit. Nested module fixtures remain available to the + parent module's product tests. + +ReleaseKit's current consumer minimum remains Go 1.26.0. Root-module releases +retain their existing note path, unprefixed tags, profile defaults, and small +root-only workflow. A successful push of the intended source tag remains the +source-release completion point; hosted page and asset delivery remains +asynchronous and may be retried from the same immutable tag. No live-service, +deployment, or consumer-rollout gate is introduced. + +For current behavior, see the [API and consumer guides](../consumers/), +[CLI contract](../cli.md), [configuration reference](../config.md), +[Gitea integration](../integrations/gitea.md), and +[ReleaseKit release procedure](../release.md). diff --git a/examples/multi-module/README.md b/examples/multi-module/README.md index 630e473..7faa747 100644 --- a/examples/multi-module/README.md +++ b/examples/multi-module/README.md @@ -9,6 +9,9 @@ Copy the contents of this directory into a consumer repository root, keeping the listed module directories and profile paths at those locations, then run the launcher from that checkout. +The sample modules declare Go 1.26.0, matching the current ReleaseKit consumer +minimum. + `release-modules.tsv` is literal tab-separated text with four columns: 1. Local selector. @@ -64,4 +67,7 @@ the literal event tag before selecting the module, copies that module's metadata outside the checkout, and builds the ReleaseKit version selected there. It then uses `ci-deliver --prepared` with the mapped profile and expected physical module. The `core-v2` profile demonstrates binary delivery; the other profiles are -page-only. +page-only. Before enabling the workflow, configure each selected profile's +`delivery` destination and add the Woodpecker repository secret +`releasekit_gitea_token`; the workflow exposes it as +`RELEASEKIT_GITEA_TOKEN` only in the delivery step. diff --git a/examples/multi-module/go.mod b/examples/multi-module/go.mod index f813a10..9e38f83 100644 --- a/examples/multi-module/go.mod +++ b/examples/multi-module/go.mod @@ -1,5 +1,5 @@ module example.com/multi-module-consumer -go 1.25.0 +go 1.26.0 require gitea.maximumdirect.net/eric/ReleaseKit v0.2.197 diff --git a/examples/multi-module/integrations/ckconfig/go.mod b/examples/multi-module/integrations/ckconfig/go.mod index 893740e..f7ca7a6 100644 --- a/examples/multi-module/integrations/ckconfig/go.mod +++ b/examples/multi-module/integrations/ckconfig/go.mod @@ -1,5 +1,5 @@ module example.com/multi-module-consumer/integrations/ckconfig -go 1.25.0 +go 1.26.0 require gitea.maximumdirect.net/eric/ReleaseKit v0.2.197 diff --git a/examples/multi-module/integrations/core/v2/go.mod b/examples/multi-module/integrations/core/v2/go.mod index 8518abb..f1bf440 100644 --- a/examples/multi-module/integrations/core/v2/go.mod +++ b/examples/multi-module/integrations/core/v2/go.mod @@ -1,5 +1,5 @@ module example.com/multi-module-consumer/integrations/core/v2 -go 1.25.0 +go 1.26.0 require gitea.maximumdirect.net/eric/ReleaseKit v0.2.197