Invoke the registered ReleaseKit package explicitly

This commit is contained in:
2026-11-04 01:51:36 +00:00
parent f625674a68
commit bd1c714935
10 changed files with 43 additions and 29 deletions

View File

@@ -148,7 +148,11 @@ func TestMultiModuleLauncherRunsToolFromSelectedDependency(t *testing.T) {
repository := newCLIRepository(t)
copyExampleTree(t, example, repository)
writeRepositoryFile(t, repository, "go.mod", "module example.com/multi-module-consumer\n\ngo 1.25.0\n\nrequire go.maximumdirect.net/releasekit v0.2.197\n")
writeRepositoryFile(t, repository, "integrations/ckconfig/go.mod", "module example.com/multi-module-consumer/integrations/ckconfig\n\ngo 1.25.0\n\nrequire go.maximumdirect.net/releasekit v0.2.198\n")
const otherModule = "example.com/other-tool"
other := t.TempDir()
writeRepositoryFile(t, other, "go.mod", "module "+otherModule+"\n\ngo 1.25.0\n")
writeRepositoryFile(t, other, "cmd/releasekit/main.go", "package main\nfunc main() { println(\"unexpected tool ran\") }\n")
writeRepositoryFile(t, repository, "integrations/ckconfig/go.mod", "module example.com/multi-module-consumer/integrations/ckconfig\n\ngo 1.25.0\n\nrequire go.maximumdirect.net/releasekit v0.2.198\nrequire "+otherModule+" v0.0.0\n\nreplace "+otherModule+" => "+strconv.Quote(other)+"\n\ntool "+otherModule+"/cmd/releasekit\n")
cliGitRun(t, repository, "add", ".")
cliGitRun(t, repository, "commit", "-m", "prepare selected tool module")
@@ -200,6 +204,9 @@ func TestMultiModuleLauncherRunsToolFromSelectedDependency(t *testing.T) {
if strings.Contains(string(output), "tool-version=v0.2.197") {
t.Fatalf("launcher ran the root-selected ReleaseKit version: %s", output)
}
if strings.Contains(string(output), "unexpected tool ran") {
t.Fatalf("launcher ran the other tool with the same name: %s", output)
}
moduleAfter, err := os.ReadFile(filepath.Join(repository, "integrations", "ckconfig", "go.mod"))
if err != nil || !bytes.Equal(moduleAfter, moduleBefore) {
t.Fatalf("selected module go.mod changed: got %q want %q error=%v", moduleAfter, moduleBefore, err)

View File

@@ -669,7 +669,7 @@ func assertGoSelection(t *testing.T, repository, goLog string) {
if !strings.Contains(log, "GOWORK=off GOTOOLCHAIN=local") || !strings.Contains(log, list) || !strings.Contains(log, "-m "+module) {
t.Fatalf("Go module selection command is missing required settings: %q", log)
}
if !strings.Contains(log, tool) || !strings.Contains(log, " releasekit ci-deliver ") || strings.Contains(log, "@v0.2.0") {
if !strings.Contains(log, tool) || !strings.Contains(log, " "+module+"/cmd/releasekit ci-deliver ") || strings.Contains(log, "@v0.2.0") {
t.Fatalf("Go tool did not run the module-selected ReleaseKit: %q", log)
}
if strings.Index(log, list) > strings.Index(log, tool) {

View File

@@ -342,11 +342,12 @@ status 2. Final delivery uses the same statuses as `deliver`: 0 for complete,
state, including when cancellation prevents reconciliation.
The maintained module-based tag workflow verifies and checks out the event tag
before resolving the consumer module. It runs `go tool releasekit` for the version
already selected by that tagged `go.mod`, using temporary alternate module files
outside the source checkout. This tool bootstrap is separate from `ci-deliver`'s
application dependency preparation for binary profiles. ReleaseKit's own
source workflow self-bootstraps `./cmd/releasekit`; consumers without a declared
before resolving the consumer module. It invokes the ReleaseKit tool by its full
package path for the version already selected by that tagged `go.mod`, using
temporary alternate module files outside the source checkout. This tool bootstrap
is separate from `ci-deliver`'s application dependency preparation for binary
profiles. ReleaseKit's own source workflow self-bootstraps `./cmd/releasekit`;
consumers without a declared
ReleaseKit module dependency can use the separately installed-tool command.
See the [delivery guide](consumers/delivery.md#woodpecker-tag-workflows) for
compatible Go environments, retries, and preparation details.

View File

@@ -34,16 +34,17 @@ Go minimum. See the
### Select the Go host target
Run `go tool releasekit` from within the consumer module to use its selected
version. Go builds and caches the executable and preserves its exit status.
A launcher invoked from that module can forward commands directly:
Invoke the ReleaseKit tool by its full package path from within the consumer
module to use its selected version. Go builds and caches the executable and
preserves its exit status. The full path distinguishes tools with the same
short name. A launcher can forward commands directly:
```sh
#!/bin/sh
releasekit_host_os=$(go env GOHOSTOS) || exit $?
releasekit_host_arch=$(go env GOHOSTARCH) || exit $?
export GOOS="$releasekit_host_os" GOARCH="$releasekit_host_arch"
exec go tool releasekit "$@"
exec go tool go.maximumdirect.net/releasekit/cmd/releasekit "$@"
```
Save this launcher as `releasekit` and run `sh ./releasekit version` from the
@@ -114,9 +115,9 @@ Go module identity. The Go consumer minimum remains 1.26.0.
## CI adoption
The maintained [consumer tag-delivery workflow](delivery.md#woodpecker-tag-workflows)
supports both tool and ordinary package dependencies. It runs `go tool releasekit`
with temporary module metadata derived from the tagged consumer's module
selection, so the committed module files also govern CI delivery and retries.
supports both tool and ordinary package dependencies. It runs the ReleaseKit
tool by its full package path with temporary metadata derived from the tagged
module, so the committed module files also govern CI delivery and retries.
Registering the CLI as a tool is sufficient for
consumers that use ReleaseKit only for maintainer commands.

View File

@@ -296,9 +296,10 @@ directory outside the checkout. `go list -m` confirms that the module selects
ReleaseKit. The template selects the host Go target before preparing and running
the CLI. The template adds its CLI tool declaration to that temporary copy
and prepares tool dependencies with `go list -deps`. It then uses
`go tool -modfile=... releasekit` to build, cache, and run the selected tool with
`CI_WORKSPACE`, the resolved event commit, and `CI_COMMIT_TAG`. The tagged module
files stay unchanged, including for consumers with an ordinary package
`go tool -modfile=... go.maximumdirect.net/releasekit/cmd/releasekit` to build,
cache, and run the selected tool with `CI_WORKSPACE`, the resolved event commit,
and `CI_COMMIT_TAG`. The tagged module files stay unchanged, including for
consumers with an ordinary package
dependency. A cleanup trap removes the temporary metadata; Go manages the
cached executable. The command preserves the tool's exit status.

View File

@@ -235,6 +235,10 @@ once. No additional scaling issue was identified.
### Stages 1, 2, and 6: Invoke the exact registered Go tool
**Completed.** The launchers, templates, and consumer recipes use the full
package path. The real Go launcher regression verifies tool selection and
exit statuses with a second registered tool of the same short name.
**Evidence:** The [multi-module launcher](../../examples/multi-module/release.sh)
and both consumer Woodpecker templates
([single-module](../../examples/woodpecker/tag-delivery.yml),

View File

@@ -73,9 +73,9 @@ Then select a module and semantic version with the shared launcher:
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, adds the CLI tool declaration to that
temporary copy, and prepares its dependencies. It uses `go tool releasekit`
with the alternate module file to invoke `publish` with the repository profile
and `--expected-module` so the library can verify that the profile agrees with
temporary copy, and prepares its dependencies. It invokes the tool by its full
package path with the alternate module file to run `publish` with the repository
profile and `--expected-module` so the library can verify that the profile agrees with
the selected table row. Go builds and caches the executable and preserves its
exit status; the launcher removes the temporary metadata on exit. As with any
`publish` invocation, commit the selected module's release note and prepare its
@@ -89,9 +89,9 @@ 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 runs the ReleaseKit version selected there through
`go tool releasekit`. It then uses `ci-deliver --prepared` with the mapped profile
and expected physical module.
outside the checkout, and runs the selected ReleaseKit tool by its full package
path. It passes `ci-deliver --prepared`, the mapped profile, and the expected
physical module to the tool.
The `core-v2` profile demonstrates binary delivery; the other profiles are
page-only. Before enabling the workflow, configure each selected profile's
`delivery` object with `"forge": "gitea"`, its `base_url`, owner, and repository,
@@ -131,21 +131,21 @@ fixture and run the source-selected tool without publishing:
releasekit_host_os=$(go env GOHOSTOS) || exit $?
releasekit_host_arch=$(go env GOHOSTARCH) || exit $?
export GOOS="$releasekit_host_os" GOARCH="$releasekit_host_arch"
go tool releasekit check --config releasekit-root.json v1.2.3
go tool go.maximumdirect.net/releasekit/cmd/releasekit check --config releasekit-root.json v1.2.3
)
(
cd ./integrations/ckconfig || exit $?
releasekit_host_os=$(go env GOHOSTOS) || exit $?
releasekit_host_arch=$(go env GOHOSTARCH) || exit $?
export GOOS="$releasekit_host_os" GOARCH="$releasekit_host_arch"
go tool releasekit check --config releasekit-ckconfig.json v1.2.3
go tool go.maximumdirect.net/releasekit/cmd/releasekit check --config releasekit-ckconfig.json v1.2.3
)
(
cd ./integrations/core/v2 || exit $?
releasekit_host_os=$(go env GOHOSTOS) || exit $?
releasekit_host_arch=$(go env GOHOSTARCH) || exit $?
export GOOS="$releasekit_host_os" GOARCH="$releasekit_host_arch"
go tool releasekit check --config releasekit-core-v2.json v2.1.0
go tool go.maximumdirect.net/releasekit/cmd/releasekit check --config releasekit-core-v2.json v2.1.0
)
```

View File

@@ -42,7 +42,7 @@ releasekit_module=go.maximumdirect.net/releasekit
go list -mod=mod -modfile="$bootstrap_dir/releasekit.mod" -m "$releasekit_module"
go mod edit -modfile="$bootstrap_dir/releasekit.mod" -tool="$releasekit_module/cmd/releasekit"
go list -mod=mod -modfile="$bootstrap_dir/releasekit.mod" -deps "$releasekit_module/cmd/releasekit" > /dev/null
go tool -modfile="$bootstrap_dir/releasekit.mod" releasekit publish \
go tool -modfile="$bootstrap_dir/releasekit.mod" "$releasekit_module/cmd/releasekit" publish \
--repo "$repository_dir" \
--config "$profile_path" \
--expected-module "$module_dir" \

View File

@@ -58,7 +58,7 @@ steps:
go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -m "$${releasekit_module}"
go mod edit -modfile="$${bootstrap_dir}/releasekit.mod" -tool="$${releasekit_module}/cmd/releasekit"
go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -deps "$${releasekit_module}/cmd/releasekit" > /dev/null
go tool -modfile="$${bootstrap_dir}/releasekit.mod" releasekit ci-deliver \
go tool -modfile="$${bootstrap_dir}/releasekit.mod" "$${releasekit_module}/cmd/releasekit" ci-deliver \
--repo "$${CI_WORKSPACE}" \
--config "$${profile_path}" \
--expected-module "$${module_dir}" \

View File

@@ -48,7 +48,7 @@ steps:
go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -m "$${releasekit_module}"
go mod edit -modfile="$${bootstrap_dir}/releasekit.mod" -tool="$${releasekit_module}/cmd/releasekit"
go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -deps "$${releasekit_module}/cmd/releasekit" > /dev/null
go tool -modfile="$${bootstrap_dir}/releasekit.mod" releasekit ci-deliver \
go tool -modfile="$${bootstrap_dir}/releasekit.mod" "$${releasekit_module}/cmd/releasekit" ci-deliver \
--repo "$${CI_WORKSPACE}" \
--prepared \
--commit "$${expected_commit}" \