# 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: ```sh : "${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](../../docs/consumers/adoption.md) owns tool registration and coordinated tool/workflow upgrades. The [v0.4.0 release note](../../docs/releases/v0.4.0.md) 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: ```sh 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: ```sh ./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](woodpecker.yml) 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: ```sh : "${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: ```sh 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`.