188 lines
11 KiB
Markdown
188 lines
11 KiB
Markdown
# Implementation plan: host-native ReleaseKit launchers
|
|
|
|
Follow the stages in order as one sprint. The
|
|
[feature roadmap](host-native-launchers.md) defines the intended behavior and
|
|
scope. The focused checks below describe regression coverage; intermediate
|
|
stages need no separate review, release, or passing build. Run the assembled
|
|
checks in Stage 6.
|
|
|
|
## Stage 1: Normalize the local multi-module launcher
|
|
|
|
**Completed.**
|
|
|
|
1. In [the multi-module launcher](../../examples/multi-module/release.sh), after
|
|
entering the selected module and exporting its existing `GOWORK=off` and
|
|
`GOTOOLCHAIN=local` settings, insert the following before the first Go
|
|
bootstrap command. Reuse this shell recipe in the subsequent stages:
|
|
|
|
```sh
|
|
releasekit_host_os=$(go env GOHOSTOS) || exit $?
|
|
releasekit_host_arch=$(go env GOHOSTARCH) || exit $?
|
|
export GOOS="$releasekit_host_os" GOARCH="$releasekit_host_arch"
|
|
```
|
|
|
|
Keep the checked assignments separate from `export` so a failed Go query
|
|
stops the launcher. Keep host selection inside the existing launcher scope;
|
|
preserve selected module metadata, dependency preparation, publication
|
|
arguments, traps, and the child status. Application targets still come from
|
|
release profiles.
|
|
|
|
2. Extend [the existing launcher tests](../../cmd/releasekit/multi_module_example_test.go).
|
|
In `TestMultiModuleLauncherUsesSelectedModuleAndProfile`, let the Go shim
|
|
answer the two host queries and assert the exported target at
|
|
`go list -deps` in the selected module. In
|
|
`TestMultiModuleLauncherRunsToolFromSelectedDependency`, supply a foreign
|
|
target to the launcher and retain real Go tool preparation and execution.
|
|
Keep the checks for the nested module's version, forwarded profile and
|
|
arguments, statuses 0 through 3, unchanged source, and bootstrap cleanup.
|
|
For these fixtures, choose `windows` unless the host OS is `windows`
|
|
(then `linux`), and `arm64` unless the host architecture is `arm64` (then
|
|
`amd64`). This makes both variables differ from the host pair. Keep
|
|
synthetic versions in a test-owned `GOMODCACHE`.
|
|
|
|
## Stage 2: Normalize consumer Woodpecker templates
|
|
|
|
**Completed.**
|
|
|
|
1. Apply the Stage 1 recipe in the
|
|
[single-module](../../examples/woodpecker/tag-delivery.yml) and
|
|
[multi-module](../../examples/multi-module/woodpecker.yml) tag delivery
|
|
commands, under the existing Go settings and in the selected module. Insert
|
|
it after tag verification and checkout, before the first Go bootstrap
|
|
command. Write the new shell variable references as
|
|
`$${releasekit_host_os}` and `$${releasekit_host_arch}` so Woodpecker
|
|
passes them through. Keep the verified commit, selected tool, profile
|
|
mapping, credentials, alternate module and sum files, cleanup, and
|
|
`ci-deliver --prepared` invocation.
|
|
|
|
2. Update the existing
|
|
[single-module](../../cmd/releasekit/woodpecker_test.go) and
|
|
[multi-module](../../cmd/releasekit/multi_module_woodpecker_test.go) workflow
|
|
harnesses. Teach the controlled Go shim to answer host queries before
|
|
enforcing its alternate module file checks. In both Go shims, log the
|
|
target at `go list -deps`. Feed a foreign target to
|
|
`TestWoodpeckerTagDeliveryTemplate`,
|
|
`TestWoodpeckerTagDeliveryUsesTaggedModuleVersion`,
|
|
and `TestMultiModuleWoodpeckerDelivery` and check that dependency inspection
|
|
uses the host pair. Retain real execution where the fixture already uses it,
|
|
and keep the existing checks that a rejected tag or commit reaches no Go
|
|
command.
|
|
|
|
## Stage 3: Normalize source-built launchers
|
|
|
|
**Completed.**
|
|
|
|
1. Apply the same recipe in the [maintainer launcher](../../scripts/release)
|
|
before building and executing ReleaseKit. Prefix the two queries with
|
|
`GOTOOLCHAIN=local` to match its existing build. Preserve usage checking,
|
|
output location, build settings, and the final `exec`.
|
|
2. Apply the recipe in the
|
|
[source delivery template](../../examples/woodpecker/releasekit-source-delivery.yml)
|
|
after tag verification and checkout, under its existing Go settings and
|
|
before the source build. Use the Woodpecker escaping from Stage 2. Keep
|
|
its temporary build output, dependency preparation through the existing
|
|
build, and prepared delivery arguments.
|
|
Exercise `TestWoodpeckerSourceDeliveryTemplateSelfBootstraps` with a foreign
|
|
target; log and assert the host pair at the real `go build`, retain actual
|
|
execution, and keep the checkout, cleanup, and dependency preparation
|
|
assertions.
|
|
3. Update the manual delivery retry in the [maintainer runbook](../release.md).
|
|
After fetching and checking out the tagged version, run host selection,
|
|
dependency download, build, and delivery inside a subshell so the caller's
|
|
target environment stays intact. Query with `GOTOOLCHAIN=local` as above;
|
|
make the sequence stop on failure inside the subshell. Preserve the
|
|
dependency download before the offline build, the build-only proxy and sum
|
|
settings, the output path, and the older-tag credential example.
|
|
|
|
## Stage 4: Normalize module-based recovery preparation
|
|
|
|
1. In [the Go recovery implementation](../../internal/gotool/recovery.go),
|
|
keep the existing registered-tool, API-only, and no-dependency selections.
|
|
Have `RecoveryTool` return `(*RecoveryInvocation, error)` within the
|
|
internal package. Give the descriptor `Directory string` and
|
|
`Args []string` fields. A nil result still selects the native executable fallback.
|
|
Set the directory to the original module for a registered tool or the
|
|
durable bootstrap root for an API-only consumer. Put `tool -modfile=`
|
|
and the existing full command package path in `Args`; the caller supplies
|
|
the working directory. Preserve the selected version, local and versioned
|
|
replacements, private module and sum files, and their existing lifetime.
|
|
2. Immediately before the API-only branch runs `go list -deps`, query
|
|
`go env -json GOHOSTOS GOHOSTARCH` in its private root with its existing
|
|
`GOWORK=off` and `GOTOOLCHAIN=local` overrides. Reuse the internal
|
|
`discover` runner with the existing context. Decode both fields, treat
|
|
missing values as a preparation error, and add only `GOOS` and `GOARCH`
|
|
to the environment of the dependency command. Keep the target-independent
|
|
module-selection query and the registered-tool early return. Use the
|
|
existing preparation error and cleanup paths; leave candidate Go settings,
|
|
proxy policy, and fallback selection as they are.
|
|
3. Update the direct `RecoveryTool` callers in
|
|
[the handoff tests](../../cmd/releasekit/publication_handoff_test.go) to run
|
|
the descriptor's arguments in its directory. In
|
|
`TestRecoveryToolPreservesVersionedReplacement`, set a foreign target for
|
|
the preparation call, log the target of the real `go list -deps` through a
|
|
delegating shim, and verify the host pair there. Run the test's subsequent
|
|
direct tool invocation with the host pair and retain its version and
|
|
metadata assertions. Retain the source-module and vendored API-only cases.
|
|
Update the CLI caller in Stage 5.
|
|
|
|
## Stage 5: Normalize the printed recovery command when it runs
|
|
|
|
1. In `selectedPublicationRecoveryCommand` in
|
|
[the CLI](../../cmd/releasekit/main.go), render the descriptor as one
|
|
copyable POSIX shell command. Use this structure, with `<dir>`,
|
|
`<package>`, and `<record>` standing for shell-quoted operands:
|
|
|
|
```sh
|
|
(export GOWORK=off GOTOOLCHAIN=local && releasekit_host_os=$(go -C <dir> env GOHOSTOS) && releasekit_host_arch=$(go -C <dir> env GOHOSTARCH) && GOOS="$releasekit_host_os" GOARCH="$releasekit_host_arch" go -C <dir> tool '-modfile=' <package> reconcile --record <record>)
|
|
```
|
|
|
|
Build the common `go -C` prefix from the descriptor directory and render
|
|
its tool arguments using the existing diagnostic redaction and shell
|
|
quoting. Keep the explicit absolute record operand. Both host queries run
|
|
in the invocation directory with the same Go settings as the final command.
|
|
A failed query stops the command, and the subshell returns the final command
|
|
status when launched. Leave the native executable command, handoff timeout
|
|
and cancellation behavior, and existing fallback and diagnostic behavior
|
|
intact.
|
|
2. In `TestColdGoToolRecoverySurvivesLauncherExit`, execute the printed
|
|
command in a separate shell with a foreign target, after the original
|
|
launcher and its temporary files are gone. Exercise both registered and
|
|
API-only handoffs and retain status checks for 0 through 3. For the
|
|
alternate-record cases, replace the quoted original record operand inside
|
|
the command instead of appending flags after the closing subshell.
|
|
Retain the vendored API-only, native fallback, record-selection, and
|
|
redaction checks. Exercise the printed command itself; running the Go
|
|
descriptor directly would miss a regression in the shell recipe.
|
|
|
|
## Stage 6: Align consumer guidance and verify the sprint
|
|
|
|
1. In the [adoption guide](../consumers/adoption.md), make the minimal
|
|
launcher use the Stage 1 recipe followed by `exec go tool releasekit "$@"`.
|
|
Run it from the selected module, retaining that consumer's workspace and
|
|
toolchain settings. Move the registration smoke check to follow the launcher
|
|
example and invoke `version` through that launcher. In the
|
|
[multi-module README](../../examples/multi-module/README.md), apply the same
|
|
recipe to the direct `check` smoke commands: enter each selected module in
|
|
its own subshell, select the host there, then run the existing check with
|
|
its repository-root profile and version. Preserve the source-selected
|
|
fixture instructions and avoid turning the smoke check into publication.
|
|
2. Align the [consumer delivery guide](../consumers/delivery.md),
|
|
[CLI contract](../cli.md), and [internal Go tool guide](../internal/gotool.md)
|
|
with the maintained recipes and handoff behavior. Explain that consumers
|
|
update copied launchers and templates separately from upgrading the module
|
|
dependency. ReleaseKit tests generic bootstrap behavior; consumers can
|
|
focus their own wiring tests on selectors and profile mapping. Profile
|
|
build targets continue to select application binaries.
|
|
3. Run the focused launcher, workflow, and recovery fixtures from the preceding
|
|
stages with the existing local Git and module proxy fixtures. Run
|
|
`go test ./...` and `go run ./internal/apicheck` as documented in the
|
|
[development guide](../development.md#validation). Check shell syntax,
|
|
including Woodpecker command blocks after interpolation, local documentation
|
|
links, and `git diff --check`. Use the existing offline fixtures; no hosted
|
|
delivery, live publication, or external runner is needed.
|
|
4. Include the following entry in the next release note during release
|
|
preparation, when its version is selected: “Maintained launchers and
|
|
generated Go recovery commands now use the host target to prepare and run
|
|
ReleaseKit. Update copied launchers and CI templates to get the fix;
|
|
release profiles still select application build targets.”
|