Files
ReleaseKit/examples/multi-module

Multi-module release example

This example maps selectors and complete event tags to a physical Go module directory and a repository-root profile. The library derives the release tag from the selected module declaration and physical location; the table only selects the corresponding profile and checkout directory.

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.

Select the release tool

The module files are setup skeletons. Set RELEASEKIT_TOOL_VERSION to a released ReleaseKit version containing module-release support, then register that tool in each consumer module before running the launcher or workflow:

: "${RELEASEKIT_TOOL_VERSION:?Select a ReleaseKit release with module-release support}"
for module_dir in . integrations/ckconfig integrations/core/v2; do
  go -C "$module_dir" get -tool "gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@${RELEASEKIT_TOOL_VERSION}"
  go -C "$module_dir" mod tidy
done

Review and commit the generated tool, dependency, and checksum declarations. The adoption guide owns tool registration and coordinated tool/workflow upgrades. The v0.4.0 release note describes module-release support and migration from earlier versions.

Module mapping and publication

release-modules.tsv is literal tab-separated text with four columns:

  1. Local selector.
  2. Shell pattern matched against a complete event tag.
  3. Repository-relative physical module directory (. means the root module).
  4. Repository-relative profile path.

The checked-in patterns are v[01].*, integrations/ckconfig/v*, and integrations/core/v2.*. The helper passes pattern text to the shell's case matcher without eval. A tag must match exactly one row; missing and ambiguous matches are configuration errors. Module and profile paths may contain spaces. The core-v2 row places the Go module physically under integrations/core/v2 and declares a /v2 module path. ReleaseKit derives the versioned tag under integrations/core, while the table retains the full physical path.

Before running candidate checks offline, prepare each module's dependencies in its own directory:

go -C . mod download
go -C integrations/ckconfig mod download
go -C integrations/core/v2 mod download

Commit each generated go.sum with its module files. The binary delivery profile prepares application dependencies in the tagged module before building; the committed sums keep that prepared checkout clean for delivery verification.

Then select a module and semantic version with the shared launcher:

./release.sh root v1.2.3
./release.sh ckconfig v1.2.3
./release.sh core-v2 v2.1.0

The launcher copies the selected module's go.mod and go.sum to temporary alternate module files outside the checkout, resolves ReleaseKit from that module's local dependency selection, and builds the tool there. It invokes publish with the repository profile and --expected-module so the library can verify that the profile agrees with the selected table row. The temporary files and tool are removed on exit. As with any publish invocation, commit the selected module's release note and prepare its repository before publishing.

If an integration depends on a sibling release, publish the dependency first, then publish the integration with the version that consumes it. For example, publish the core release before an integration that requires that release. This declaration does not infer dependency order or rerun the standard suite.

The maintained Woodpecker example uses the same map and selector for root, ckconfig, and major-version tags. It verifies and detaches 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. 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.

Retries use the selected tag's module files and matching workflow. Tags whose tool predates this interface use their corresponding historical workflow.

Local source verification

For verification before a compatible release is published, copy this example into a disposable consumer checkout. Set RELEASEKIT_SOURCE to the absolute path of a prepared ReleaseKit checkout, then select its source in those fixture modules:

: "${RELEASEKIT_SOURCE:?Set the absolute ReleaseKit checkout path}"
for module_dir in . integrations/ckconfig integrations/core/v2; do
  go -C "$module_dir" mod edit \
    -require=gitea.maximumdirect.net/eric/ReleaseKit@v0.0.0 \
    -replace="gitea.maximumdirect.net/eric/ReleaseKit=$RELEASEKIT_SOURCE" \
    -tool=gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit
  GOTOOLCHAIN=local GOWORK=off go -C "$module_dir" mod tidy
done

Here v0.0.0 is a fixture placeholder resolved by the local replacement. Keep these declarations in the disposable checkout. Add representative product source and each selected product's module-local release note, then commit the fixture and run the source-selected tool without publishing:

go tool releasekit check --config releasekit-root.json v1.2.3
go -C integrations/ckconfig tool releasekit check --config releasekit-ckconfig.json v1.2.3
go -C integrations/core/v2 tool releasekit check --config releasekit-core-v2.json v2.1.0

These commands use the repository-root profile paths even when invoked from a child module. The core profile also verifies the native binary and injected version. Prepared dependencies allow this verification with GOPROXY=off and GOSUMDB=off.