Prepare the v0.9.0 release notes and retire completed roadmaps
This commit is contained in:
41
docs/releases/v0.9.0.md
Normal file
41
docs/releases/v0.9.0.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# ReleaseKit v0.9.0
|
||||
|
||||
ReleaseKit's maintained launchers and generated Go recovery commands now
|
||||
prepare and run the release tool for the Go host when inherited `GOOS` and
|
||||
`GOARCH` select another target. Release profiles still select the targets for
|
||||
application builds.
|
||||
|
||||
## Launcher, delivery, and recovery fixes
|
||||
|
||||
- Local launchers and Woodpecker templates select the host before preparing
|
||||
tool dependencies or compiling the CLI. Module-based launchers invoke
|
||||
ReleaseKit by its full Go package path, so another registered tool named
|
||||
`releasekit` does not make the invocation ambiguous.
|
||||
- Generated Go recovery commands select the host when run in a POSIX shell
|
||||
and find the Go executable through `PATH`. Recovery for API-only consumers
|
||||
preserves both wildcard and version-specific module replacements when
|
||||
relocating relative paths, fixing a panic after a failed publication.
|
||||
- The manual hosted-page retry stops if fetching or checking out the tag fails,
|
||||
or if local edits remain. It checks the tagged checkout before downloading
|
||||
dependencies or building the CLI.
|
||||
|
||||
## Compatibility and upgrade
|
||||
|
||||
The module path remains `go.maximumdirect.net/releasekit` and the Go consumer
|
||||
minimum remains 1.26.0. Public Go APIs, release profiles, and publication
|
||||
record formats are unchanged.
|
||||
|
||||
Update copied launchers and CI templates to get the host and tool selection
|
||||
fixes. Updating the module dependency alone does not update those files.
|
||||
Configured product checks inherit the launcher's host target; if a check
|
||||
needs an application target, set it explicitly in the check's `env` map
|
||||
or command.
|
||||
|
||||
See the [adoption guide](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/docs/consumers/adoption.md),
|
||||
[delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/docs/consumers/delivery.md),
|
||||
and [maintainer runbook](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/docs/release.md)
|
||||
for updated recipes.
|
||||
|
||||
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/COPYRIGHT) |
|
||||
[LICENSE](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/LICENSE) |
|
||||
[ATTRIBUTION](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/docs/oss/attribution.md)
|
||||
@@ -1,93 +0,0 @@
|
||||
# CommandKit feature request: host-safe consumer launchers
|
||||
|
||||
Status: proposed; not an accepted contract or implementation assignment.
|
||||
|
||||
## Consumer need
|
||||
|
||||
CommandKit selects ReleaseKit v0.8.0 as a Go tool and uses a small launcher to
|
||||
publish its core and two optional integration modules. Maintainers can inherit
|
||||
`GOOS` and `GOARCH` from application cross-build work. The release tool must run
|
||||
on the maintainer's host even when those variables name another target.
|
||||
|
||||
CommandKit currently handles this by querying `go env GOHOSTOS` and
|
||||
`go env GOHOSTARCH`, then using those values when building its native ReleaseKit
|
||||
executable. Its `TestReleaseLauncherDelegatesPublication` test supplies foreign
|
||||
target variables and checks native bootstrap behavior together with argument
|
||||
and exit-status forwarding. Consumer evidence is in CommandKit's
|
||||
`scripts/release` and `scripts/release_test.go` at local commit
|
||||
`a74fcb20041cbccde93f9b9a1e3b24cb8dd131e7`.
|
||||
|
||||
Please incorporate this behavior and regression coverage into ReleaseKit's
|
||||
maintained consumer launcher example so downstream projects can reuse the
|
||||
recipe and rely on upstream tests for its generic bootstrap mechanics.
|
||||
|
||||
## Observed failure
|
||||
|
||||
Reviewed ReleaseKit v0.8.0, commit
|
||||
`23203f235cc414c4ffe0fd3941030eb0c9f9943f`. The
|
||||
[multi-module launcher](../../examples/multi-module/release.sh) invokes
|
||||
`go tool` without normalizing the inherited target environment.
|
||||
|
||||
On Linux/amd64 with Go 1.26.8, from a prepared consumer module registering
|
||||
`go.maximumdirect.net/releasekit/cmd/releasekit` at v0.8.0:
|
||||
|
||||
```sh
|
||||
GOWORK=off GOTOOLCHAIN=local GOFLAGS=-mod=readonly \
|
||||
GOPROXY=off GONOPROXY=none GOSUMDB=off \
|
||||
GOOS=windows GOARCH=arm64 go tool releasekit version
|
||||
```
|
||||
|
||||
The command built a Windows executable and failed to launch it with an
|
||||
`exec format error`. Repeating the command with `GOOS=linux GOARCH=amd64`
|
||||
succeeded and printed `releasekit v0.8.0`. These observations establish the
|
||||
tool-execution failure; the complete upstream launcher was inspected rather
|
||||
than executed in this reproduction. No publication was attempted.
|
||||
|
||||
## Requested change
|
||||
|
||||
Update the maintained launcher to select the native host target when preparing
|
||||
and executing ReleaseKit, regardless of inherited application target variables.
|
||||
Resolve the host through the selected Go toolchain rather than hard-coding a
|
||||
platform. Scope this change to running the maintainer tool; preserve the
|
||||
application targets selected through existing release profiles.
|
||||
|
||||
Retain the launcher's existing module/version selection, profile routing,
|
||||
source-file preservation, workspace/toolchain settings, and child exit-status
|
||||
behavior. Document the host-target handling in the
|
||||
[consumer adoption guidance](../consumers/adoption.md) where appropriate.
|
||||
|
||||
Prefer a small change to the supported example and its tests. This request does
|
||||
not require a new validation option, public bootstrap API, or test-helper
|
||||
package. CommandKit's choice to select one tool version from its root module
|
||||
remains consumer-owned; this request does not change ReleaseKit's example policy
|
||||
of selecting the tool from the chosen module.
|
||||
|
||||
## Acceptance evidence
|
||||
|
||||
Extend the existing
|
||||
[multi-module launcher tests](../../cmd/releasekit/multi_module_example_test.go)
|
||||
with a controlled foreign-target environment. Demonstrate that:
|
||||
|
||||
1. The selected tool executes on the host despite foreign `GOOS` and `GOARCH`.
|
||||
2. The selected module's tool version and publication arguments still reach the
|
||||
child, and child statuses 0, 1, 2, and 3 are preserved.
|
||||
3. Source module files remain unchanged and existing bootstrap cleanup behavior
|
||||
is preserved.
|
||||
|
||||
Reuse existing coverage for unaffected behavior rather than adding a parallel
|
||||
suite. A host-run test can use a synthetic local tool and needs no real release
|
||||
or external service. Synthetic module downloads must use test-owned caches as
|
||||
described in [the developer guide](../development.md#testing-synthetic-modules).
|
||||
|
||||
## Ownership and downstream follow-up
|
||||
|
||||
CommandKit's review found no locally maintained candidate validator that needs
|
||||
to become a new ReleaseKit feature. Existing formatting, Markdown, and module
|
||||
distribution options already cover their respective reusable checks; selecting
|
||||
them as CommandKit release gates is a separate consumer decision.
|
||||
|
||||
ReleaseKit already owns publication-engine tests for annotated tags, exact
|
||||
remote objects, nested tag prefixes, and endpoint preflight. CommandKit can
|
||||
narrow its local publication exercise to its launcher and profile wiring
|
||||
without upstreaming a duplicate engine test suite. Its selectors, product names,
|
||||
publication endpoint, and release order remain local responsibilities.
|
||||
@@ -1,78 +0,0 @@
|
||||
# Roadmap: host-native consumer launchers
|
||||
|
||||
Status: implemented.
|
||||
|
||||
## Purpose
|
||||
|
||||
Make ReleaseKit's maintained launchers and generated recovery commands prepare
|
||||
and execute the release tool for the maintainer's host when inherited `GOOS`
|
||||
and `GOARCH` select a different application target. Centralize the recipe and
|
||||
regression coverage so consumers can retain small launchers and product-specific
|
||||
wiring tests.
|
||||
|
||||
This is a launcher correctness improvement. It requires no public bootstrap API,
|
||||
validation option, or test-helper package. This roadmap selects no release version.
|
||||
|
||||
## Baseline before implementation
|
||||
|
||||
The [CommandKit feature request](commandkit-feature-request.md) describes a
|
||||
prepared v0.8.0 tool invocation on Linux/amd64 with `GOOS=windows GOARCH=arm64`
|
||||
that built a Windows executable and failed with an exec format error.
|
||||
CommandKit's local launcher already selects the Go host target before
|
||||
building the release executable. The report's reproduction exercised tool
|
||||
execution without attempting publication.
|
||||
|
||||
The maintained [multi-module launcher](../../examples/multi-module/release.sh)
|
||||
already selected a module and profile, copied module metadata into temporary
|
||||
storage, prepared the selected ReleaseKit dependency, and invoked
|
||||
`go tool releasekit`. It set `GOWORK=off` and `GOTOOLCHAIN=local` while passing
|
||||
inherited `GOOS` and `GOARCH` to dependency inspection and tool execution.
|
||||
|
||||
The [adoption guide](../consumers/adoption.md) included a minimal `go tool`
|
||||
launcher. The [single-module CI template](../../examples/woodpecker/tag-delivery.yml)
|
||||
and [multi-module CI template](../../examples/multi-module/woodpecker.yml) also
|
||||
invoked the selected tool without explicit host-target normalization.
|
||||
|
||||
The [maintainer launcher](../../scripts/release),
|
||||
[source delivery template](../../examples/woodpecker/releasekit-source-delivery.yml),
|
||||
and [manual delivery retry](../release.md) built and executed the tool with the
|
||||
same inherited-target assumption. The CLI's [generated recovery command](../../cmd/releasekit/main.go)
|
||||
inherited the target from the shell where it ran, and [recovery dependency
|
||||
preparation](../../internal/gotool/recovery.go) also inherited the target.
|
||||
|
||||
Existing [launcher tests](../../cmd/releasekit/multi_module_example_test.go)
|
||||
exercised synthetic module selection, publication arguments, child statuses
|
||||
0 through 3, and preservation of source module metadata. Those fixtures provided
|
||||
the starting point for foreign-target regression coverage.
|
||||
|
||||
## Targeted end state
|
||||
|
||||
Maintained launchers and module-based recovery use `GOHOSTOS` and `GOHOSTARCH`
|
||||
from the selected Go toolchain as `GOOS` and `GOARCH` while preparing and running
|
||||
ReleaseKit. The tool executes on that host even when the caller was working with
|
||||
a foreign application target. Normalize before target-dependent dependency
|
||||
inspection as well as tool execution. Generated recovery commands select the
|
||||
host when run, using the Go toolchain that will execute the command.
|
||||
|
||||
Application targets continue to come from existing release profiles. The
|
||||
launcher's host selection preserves module-selected tool versions, profile and
|
||||
argument routing, source-file preservation, temporary-file cleanup, existing
|
||||
workspace/toolchain settings, and child exit statuses. Consumers retain their
|
||||
own selectors, products, endpoints, and release order.
|
||||
|
||||
The scope is inherited `GOOS` and `GOARCH` handling for the maintainer tool. It
|
||||
does not establish a hermetic environment, broaden hardware or platform support,
|
||||
or add release gates. Existing Go/toolchain failures remain ordinary bootstrap
|
||||
failures. No new fallback toolchain or download policy is introduced.
|
||||
|
||||
The [implementation plan](implementation.md) defines the work to reach this
|
||||
state.
|
||||
|
||||
## Completion evidence
|
||||
|
||||
Completion requires host selection before dependency inspection and successful
|
||||
host execution under a foreign target, including for generated recovery commands.
|
||||
Preserve selected tool identity and arguments, child-status forwarding, unchanged
|
||||
source metadata, and existing cleanup behavior. The maintained local and CI
|
||||
recipes and adoption guidance must use the same host-selection approach.
|
||||
Application build targets must retain their existing profile-driven behavior.
|
||||
@@ -1,193 +0,0 @@
|
||||
# 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
|
||||
|
||||
**Completed.** The CLI adapter and assembled handoff tests follow in the next stage.
|
||||
|
||||
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
|
||||
|
||||
**Completed.**
|
||||
|
||||
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
|
||||
|
||||
**Completed.**
|
||||
|
||||
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.”
|
||||
@@ -1,289 +0,0 @@
|
||||
# Host-native launcher review findings
|
||||
|
||||
Reviewed the implementation from `bf07bed` through `0269648` against the
|
||||
[feature roadmap](host-native-launchers.md) and
|
||||
[implementation plan](implementation.md).
|
||||
|
||||
The maintained launchers select the Go host before preparing and running the
|
||||
tool. API-only recovery prepares its private module on the host; printed Go
|
||||
handoffs discover the host again when run. The CLI retains the native fallback
|
||||
and saved-record selection. Application build targets still come from the
|
||||
profile, and the public Go facades and dependency boundaries are unchanged.
|
||||
|
||||
## Make the adoption smoke command runnable
|
||||
|
||||
**Completed.** The smoke command runs the saved launcher through `sh`; verified with a non-executable file and a foreign target.
|
||||
|
||||
**Evidence:** The [adoption guide](../consumers/adoption.md#cli-tool-dependency)
|
||||
tells readers to save the launcher as `releasekit` and run
|
||||
`./releasekit version`. A newly saved shell file ordinarily lacks its execute
|
||||
bit. In a disposable directory, the documented command failed with status 126
|
||||
and “Permission denied.” Invoking the same snippet through `sh` ran a
|
||||
module-registered fixture tool on Linux/amd64 with inherited
|
||||
`GOOS=windows GOARCH=arm64`.
|
||||
|
||||
**Fix:** Use `sh ./releasekit version` in the smoke instructions, or give an
|
||||
explicit `chmod +x ./releasekit` step before direct execution. Verify the
|
||||
published instructions from a newly created file under a foreign target.
|
||||
|
||||
## Limit the recovery guarantee to GOOS and GOARCH
|
||||
|
||||
**Completed.** The CLI reference names the two target variables and identifies the shell syntax.
|
||||
|
||||
**Evidence:** The [CLI contract](../cli.md) says Go handoffs select the host
|
||||
“independently of inherited cross-compilation settings.” The
|
||||
[command formatter](../../cmd/releasekit/main.go) overrides `GOOS` and
|
||||
`GOARCH` and retains other build settings. For example, building the actual CLI
|
||||
with the native target, `CGO_ENABLED=1`, and an unavailable C compiler named
|
||||
by `CC` still fails in `runtime/cgo`. This is consistent with the roadmap's
|
||||
scope, but the CLI wording implies broader independence.
|
||||
|
||||
**Fix:** Say that generated Go handoffs set `GOOS` and `GOARCH` from the
|
||||
selected Go toolchain at invocation time. Preserve the other inherited settings
|
||||
and the existing workspace and toolchain overrides. The documented handoff
|
||||
uses POSIX shell syntax; identify that syntax when telling operators where to
|
||||
paste the command.
|
||||
|
||||
## Exercise a profile target that differs from the launcher host
|
||||
|
||||
**Completed.** The binary delivery fixture selects a non-host Linux target and checks the uploaded ELF machine as well as the filename.
|
||||
|
||||
**Evidence:** The binary-delivery case in
|
||||
[`TestMultiModuleWoodpeckerDelivery`](../../cmd/releasekit/multi_module_woodpecker_test.go)
|
||||
supplies a foreign target to the workflow and checks the uploaded
|
||||
`core-v2.1.0-linux-amd64` asset. The profile itself selects `linux/amd64`.
|
||||
On the Linux/amd64 review host, the test cannot distinguish using the
|
||||
profile target from accidentally using the normalized launcher target. The
|
||||
current build code still applies the selected profile target explicitly.
|
||||
|
||||
**Fix:** In that fixture, select a supported profile target distinct from the
|
||||
host and assert the uploaded asset matches it. Where practical, inspect the
|
||||
uploaded executable header as well as the name, so the test catches a
|
||||
host-built payload with a profile-derived filename. Keep the existing local
|
||||
forge fixture and native version check; the cross-built asset need not run on
|
||||
the host.
|
||||
|
||||
## Reconcile the feature roadmap with the completed implementation
|
||||
|
||||
**Completed.** The feature roadmap records implementation and labels the pre-change baseline. The release-note entry remains in the implementation plan.
|
||||
|
||||
**Evidence:** The [feature roadmap](host-native-launchers.md) still declares
|
||||
“implementation pending” and describes the pre-change launchers as the current
|
||||
baseline. All six stages in the [implementation plan](implementation.md) are
|
||||
marked complete, and the maintained launchers and recovery code implement the
|
||||
host selection described there.
|
||||
|
||||
**Fix:** Mark the roadmap implemented and label the old baseline as historical,
|
||||
or retire the completed planning documents after review. Preserve the planned
|
||||
release-note entry for the next selected release version.
|
||||
|
||||
## Verification
|
||||
|
||||
`go test ./...`, `go run ./internal/apicheck`, and syntax checks for the
|
||||
maintained shell scripts passed. The Go suite exercised real tool preparation,
|
||||
Woodpecker command blocks with local fixtures, and later execution of printed
|
||||
recovery commands. Disposable smoke probes also verified the maintainer
|
||||
launcher forwards the child status and the manual retry preserves the calling
|
||||
shell's target variables. The review made no changes to production code or
|
||||
tests.
|
||||
|
||||
## Integration audit
|
||||
|
||||
The audit below examines how the new bootstrap paths interact with existing
|
||||
invocation recipes, product checks, and publication recovery.
|
||||
|
||||
### Use the external Go executable in printed recovery commands
|
||||
|
||||
**Completed.** All three Go invocations use external lookup through `PATH`. The handoff regression reproduces the shell-function failure before the fix and verifies reconciliation afterward.
|
||||
|
||||
**Evidence:** Before host normalization, the
|
||||
[command formatter](../../cmd/releasekit/main.go) emitted
|
||||
`env GOWORK=off GOTOOLCHAIN=local go ...`, which resolves Go through `PATH`.
|
||||
[Recovery preparation](../../internal/gotool/recovery.go) still executes an
|
||||
external Go command. The new printed command uses bare `go` for both host
|
||||
queries and the later tool invocation, so a function named `go` in the
|
||||
operator's shell can intercept it. In a local rejected-push fixture, the
|
||||
actual printed command reconciled the saved record in an ordinary shell.
|
||||
With `go() { GOOS=windows GOARCH=arm64 command go "$@"; }` defined, the same
|
||||
command failed with an exec format error. The function overrode the final
|
||||
assignments even though the host queries reported the correct host. In this
|
||||
case both paths exited with status 1, but only one produced a reconciliation
|
||||
result.
|
||||
|
||||
**Fix:** Restore external command lookup for the host queries and tool
|
||||
invocation, for example by using `env go -C ...` throughout the subshell.
|
||||
Keep selection through the operator's current `PATH`, including executable
|
||||
shims, and keep the exact record and exit status. Exercise a generated
|
||||
handoff from a POSIX shell that defines a cross-build Go function; assert
|
||||
the reconciliation result as well as the status.
|
||||
|
||||
### Explain how host normalization affects configured product checks
|
||||
|
||||
**Completed.** The adoption guide explains inherited host variables and points checks that need an application target to the existing environment overlay.
|
||||
|
||||
**Evidence:** The updated launchers export `GOOS` and `GOARCH` to the
|
||||
ReleaseKit process. Existing [configured checks](../config.md) inherit that
|
||||
process environment unless their `env` maps override it;
|
||||
[`RunChecks`](../../cmd/releasekit/internal/cli/config.go) adds the configured
|
||||
and ReleaseKit-owned values to the child. This differs from built-in
|
||||
application compilation, which chooses its target from the profile. A
|
||||
disposable consumer's check using shell defaults for an application target
|
||||
passed with the previous direct `go tool` invocation and no target
|
||||
variables, then failed through the updated launcher because it observed
|
||||
`linux/amd64`. Adding explicit `GOOS=windows` and `GOARCH=arm64` to that
|
||||
check's `env` restored its behavior.
|
||||
|
||||
**Fix:** In the launcher adoption guidance, explain that host variables
|
||||
reach configured child checks and that checks which need an application
|
||||
target should set it explicitly in their existing `env` map or command.
|
||||
Link to the configuration contract. Keep the current environment overlay
|
||||
semantics and the separate profile selection for built-in builds.
|
||||
|
||||
### Align direct source and standalone CI recipes with the launcher guidance
|
||||
|
||||
**Completed.** The source examples link to host selection, and the standalone install recipe scopes the same settings to `go install`. Both paths were verified under a foreign target.
|
||||
|
||||
**Evidence:** The [README quick start](../../README.md) and
|
||||
[CLI reference](../cli.md) still recommend bare `go run ./cmd/releasekit`
|
||||
for source invocation. The [consumer delivery guide](../consumers/delivery.md#woodpecker-tag-workflows)
|
||||
also recommends bare `go install ...@PIN` for consumers who install the
|
||||
delivery executable separately. These older recipes remain target-sensitive
|
||||
alongside the new host-native launchers. On Linux/amd64 with inherited
|
||||
`GOOS=windows GOARCH=arm64`, the README's actual `version` command failed
|
||||
with an exec format error. A versioned install from a disposable local
|
||||
module proxy failed under the same variables with `GOBIN` set; the native
|
||||
install succeeded and its binary ran.
|
||||
|
||||
**Fix:** Link these recipes to the host-selection instructions and make the
|
||||
native target requirement explicit at the source invocation and at the
|
||||
standalone installation step. Use the existing recipe where a copyable
|
||||
command is useful. Keep the selected version, install location, and
|
||||
`go run` exit-status caveat. An already installed native binary does not
|
||||
need a new bootstrap step.
|
||||
|
||||
## Algorithmic audit
|
||||
|
||||
The host normalization itself adds a fixed number of Go invocations per
|
||||
launch. The CLI renders a fixed argument list, so quoting and formatting take
|
||||
time and space linear in the lengths of the directory and record paths. Go
|
||||
dependency inspection and compilation retain their existing roles. The
|
||||
findings below concern a pre-existing algorithm on the audited recovery path
|
||||
and a new module-selection defect in the smoke recipe.
|
||||
|
||||
### Relocate recovery replacements in one pass without merging selectors
|
||||
|
||||
**Completed.** Recovery rewrites relative destinations in one pass. The CLI regression verifies both selectors, the selected tool, the rejected-push status, and later reconciliation.
|
||||
|
||||
**Evidence:** The API-only path in
|
||||
[`RecoveryTool`](../../internal/gotool/recovery.go) walks the parsed
|
||||
`go.mod` replacements. It calls `modfile.AddReplace` for each relative
|
||||
local replacement. In the pinned `golang.org/x/mod` implementation,
|
||||
each call scans the entire replacement slice. With `R` total directives
|
||||
and `L` relative local directives, relocation visits `O(R × L)` entries,
|
||||
and takes quadratic time when all or most entries require relocation.
|
||||
This loop predates host normalization and still runs before the new host
|
||||
query.
|
||||
|
||||
The same loop can panic on a valid module that declares both an unversioned
|
||||
and a version-specific replacement for the same dependency. When the
|
||||
unversioned directive appears first and uses a relative path, calling
|
||||
`AddReplace` with an empty old version treats both directives as matches
|
||||
and clears the version-specific entry. The outer loop then visits that
|
||||
cleared entry as if it were another relative replacement. In a disposable
|
||||
API-only consumer with both forms for ReleaseKit, Go accepted the module
|
||||
and validation passed. After a local hook rejected the tag push, ReleaseKit
|
||||
saved the publication record, then panicked in `modfile.addReplace`. It
|
||||
exited with status 2 instead of reporting the rejected push and a recovery
|
||||
handoff.
|
||||
|
||||
**Fix:** Rewrite each relative right-hand path on its existing parsed
|
||||
directive in one pass, preserving the exact left-hand path and version
|
||||
selector. For example, update the typed replacement and its corresponding
|
||||
syntax token before formatting. This takes `O(R)` directive visits plus
|
||||
the bytes processed for the paths and avoids selector merging. Keep the
|
||||
existing relocation policy, the separate synthetic replacement for the
|
||||
original module, and the private module lifetime. Add a recovery fixture
|
||||
with distinct local destinations for a wildcard and a version-specific
|
||||
replacement. Check that the handoff preserves both directives, selects the
|
||||
version-specific destination, and reports the original publication status.
|
||||
|
||||
### Anchor smoke-check module paths to the intended checkout
|
||||
|
||||
**Completed.** Both nested paths use `./`; verified the full smoke recipe with a conflicting `CDPATH`.
|
||||
|
||||
**Evidence:** The [multi-module smoke recipe](../../examples/multi-module/README.md)
|
||||
replaced `go -C integrations/...` with subshells that run
|
||||
`cd integrations/...` before host discovery. A shell with `CDPATH` set can
|
||||
resolve these relative names in another checkout. In a disposable probe
|
||||
with matching module paths under two directories, the published snippet
|
||||
sent both nested checks to the checkout named by `CDPATH` and returned
|
||||
success. If the other checkout has valid profiles and tools, the smoke
|
||||
result can appear valid for the wrong candidate.
|
||||
|
||||
**Fix:** Use `cd ./integrations/ckconfig` and `cd ./integrations/core/v2`,
|
||||
or clear `CDPATH` for those two directory changes. The number of lookups is
|
||||
already fixed; the change corrects which directory is selected. Verify the
|
||||
copyable recipe with a conflicting `CDPATH` entry.
|
||||
|
||||
## Follow-up review after remediation
|
||||
|
||||
Reviewed all six implementation stages at `9797f43`. The focused launcher,
|
||||
delivery, and recovery tests and the public API and dependency checks passed.
|
||||
The host discovery work remains bounded to a fixed number of calls per
|
||||
invocation, and recovery replacement relocation now visits each directive
|
||||
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),
|
||||
[multi-module](../../examples/multi-module/woodpecker.yml)) register the
|
||||
full ReleaseKit package path, but invoke the short name `releasekit`. The
|
||||
[adoption launcher](../consumers/adoption.md#select-the-go-host-target) and
|
||||
[multi-module smoke recipe](../../examples/multi-module/README.md) also use
|
||||
the short name. Go allows two different package paths with the same final
|
||||
component in the tool declarations. With a second local tool ending in
|
||||
`/cmd/releasekit`, the maintained launcher and both extracted CI command
|
||||
blocks prepared the intended module, then exited with an ambiguous-tool
|
||||
error. Changing only the invocation to the full package path ran the
|
||||
intended host-native tool in all three probes. Recovery already invokes
|
||||
the full path and is unaffected.
|
||||
|
||||
**Fix:** Invoke the same full package path used for registration in the
|
||||
maintained launchers, templates, and copyable consumer recipes. Preserve
|
||||
the selected module version, arguments, and exit status. Extend an
|
||||
existing launcher fixture with a second registered tool of the same short
|
||||
name and verify that only the intended tool runs.
|
||||
|
||||
### Stage 3: Build the manual retry tool only from a clean tagged checkout
|
||||
|
||||
**Completed.** The retry resolves and checks out the fetched tag and checks
|
||||
cleanliness before invoking Go. Local probes verified that fetch failure,
|
||||
checkout failure, and remaining edits stop before Go, and a clean retry
|
||||
builds and runs the tagged tool for the host.
|
||||
|
||||
**Evidence:** The [manual retry block](../release.md) runs `git fetch` and
|
||||
`git checkout --detach` before the subshell that enables `set -e`. A
|
||||
failed checkout can therefore be followed by dependency preparation, a
|
||||
build, and execution from the wrong source. A successful checkout can
|
||||
also carry local edits forward. Both cases were reproduced with the
|
||||
documented block in disposable Git repositories and a local bare remote:
|
||||
a checkout refused because of conflicting edits still ran a fixture
|
||||
built from the edited source, and checking out the already selected tag
|
||||
succeeded while retaining and executing a local edit. The fixture exited
|
||||
successfully in both cases. ReleaseKit's normal delivery guards check
|
||||
the tagged checkout after the executable has already been built and
|
||||
started; they do not protect this bootstrap.
|
||||
|
||||
**Fix:** Include the fetch and checkout in the fail-fast subshell. Resolve
|
||||
the literal tag to its commit and require a clean checkout before
|
||||
downloading dependencies or building the CLI, as the
|
||||
[source delivery template](../../examples/woodpecker/releasekit-source-delivery.yml)
|
||||
does. Preserve the scoped host target, dependency download before the
|
||||
offline build, and the existing retry arguments. Verify that checkout
|
||||
failure and carried-over edits both stop before the first Go command.
|
||||
Reference in New Issue
Block a user