Separate Go discovery configuration from diagnostics
This commit is contained in:
@@ -20,6 +20,10 @@ and native cgo/C-tool configuration into its settings. This captures values
|
|||||||
supplied by either the process environment or the persistent Go environment
|
supplied by either the process environment or the persistent Go environment
|
||||||
file.
|
file.
|
||||||
|
|
||||||
|
Configuration discovery parses JSON from stdout. Stderr is captured separately
|
||||||
|
and included in command-failure diagnostics, so a successful query can emit
|
||||||
|
warnings while supplying valid configuration.
|
||||||
|
|
||||||
## Command environments
|
## Command environments
|
||||||
|
|
||||||
Every Go command receives `GOENV=off`, so removed persistent values cannot
|
Every Go command receives `GOENV=off`, so removed persistent values cannot
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Date: 2026-10-06.
|
Date: 2026-10-06.
|
||||||
Reviewed source: `55333b0`.
|
Reviewed source: `55333b0`.
|
||||||
Status: Two findings require remediation.
|
Status: R1 resolved; R2 requires remediation.
|
||||||
|
|
||||||
## Scope and assessment
|
## Scope and assessment
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ repairs within those decisions.
|
|||||||
|
|
||||||
## R1 — Medium: Go discovery treats successful diagnostics as invalid configuration
|
## R1 — Medium: Go discovery treats successful diagnostics as invalid configuration
|
||||||
|
|
||||||
Status: Open.
|
Status: Resolved.
|
||||||
Category: Correctness and an accidental environment prerequisite.
|
Category: Correctness and an accidental environment prerequisite.
|
||||||
Introduced by: `0809312`.
|
Introduced by: `0809312`.
|
||||||
|
|
||||||
@@ -67,6 +67,13 @@ the settings. A failing command retains useful stderr and its cause. Existing
|
|||||||
ambient/persistent flag, host-target, cache, and architecture-tuning regressions
|
ambient/persistent flag, host-target, cache, and architecture-tuning regressions
|
||||||
continue to pass. These checks add no warning-free configuration requirement.
|
continue to pass. These checks add no warning-free configuration requirement.
|
||||||
|
|
||||||
|
**Resolution (2026-10-07):** Discovery captures stdout and stderr separately,
|
||||||
|
parses configuration from stdout, and preserves diagnostic output and subprocess
|
||||||
|
causes on failure. A subprocess fixture proves successful JSON discovery accepts
|
||||||
|
stderr diagnostics and preserves host/cache settings; another verifies failure
|
||||||
|
diagnostics and exit-error identity. The success regression failed before the
|
||||||
|
fix. Go-environment, candidate-validation, and build regression checks pass.
|
||||||
|
|
||||||
## R2 — Medium: Wrapper regression testing repeats the project suite inside itself
|
## R2 — Medium: Wrapper regression testing repeats the project suite inside itself
|
||||||
|
|
||||||
Status: Open.
|
Status: Open.
|
||||||
|
|||||||
@@ -187,18 +187,18 @@ func discoveryEnvironment() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func discover(ctx context.Context, directory string, environment map[string]string, args ...string) ([]byte, error) {
|
func discover(ctx context.Context, directory string, environment map[string]string, args ...string) ([]byte, error) {
|
||||||
captured := &combinedWriter{}
|
var configuration, diagnostics bytes.Buffer
|
||||||
err := process.Run(ctx, process.Invocation{
|
err := process.Run(ctx, process.Invocation{
|
||||||
Args: args,
|
Args: args,
|
||||||
Dir: directory,
|
Dir: directory,
|
||||||
Env: environment,
|
Env: environment,
|
||||||
Stdout: captured,
|
Stdout: &configuration,
|
||||||
Stderr: captured,
|
Stderr: &diagnostics,
|
||||||
})
|
})
|
||||||
contents := captured.Bytes()
|
contents := configuration.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if len(contents) != 0 {
|
if output := strings.TrimSpace(configuration.String() + diagnostics.String()); output != "" {
|
||||||
return contents, fmt.Errorf("%s: %w: %s", strings.Join(args, " "), err, strings.TrimSpace(string(contents)))
|
return contents, fmt.Errorf("%s: %w: %s", strings.Join(args, " "), err, output)
|
||||||
}
|
}
|
||||||
return contents, fmt.Errorf("%s: %w", strings.Join(args, " "), err)
|
return contents, fmt.Errorf("%s: %w", strings.Join(args, " "), err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,18 @@ func runGoPreparationFixture() int {
|
|||||||
return 11
|
return 11
|
||||||
}
|
}
|
||||||
switch os.Getenv("RELEASEKIT_GO_FIXTURE_MODE") {
|
switch os.Getenv("RELEASEKIT_GO_FIXTURE_MODE") {
|
||||||
|
case "discovery":
|
||||||
|
settings := make(map[string]string)
|
||||||
|
for _, key := range os.Args[3:] {
|
||||||
|
settings[key] = os.Getenv(key)
|
||||||
|
}
|
||||||
|
settings["GOHOSTOS"] = runtime.GOOS
|
||||||
|
settings["GOHOSTARCH"] = runtime.GOARCH
|
||||||
|
fmt.Fprintln(os.Stderr, "fixture discovery diagnostic")
|
||||||
|
if err := json.NewEncoder(os.Stdout).Encode(settings); err != nil {
|
||||||
|
return 12
|
||||||
|
}
|
||||||
|
return 0
|
||||||
case "fail":
|
case "fail":
|
||||||
fmt.Fprintln(os.Stderr, "fixture dependency failure")
|
fmt.Fprintln(os.Stderr, "fixture dependency failure")
|
||||||
return 23
|
return 23
|
||||||
@@ -59,6 +71,30 @@ func runGoPreparationFixture() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDiscoveryAcceptsDiagnosticsWithValidConfiguration(t *testing.T) {
|
||||||
|
repository, _ := installGoPreparationFixture(t)
|
||||||
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "discovery")
|
||||||
|
cache := filepath.Join(t.TempDir(), "cache")
|
||||||
|
t.Setenv("GOCACHE", cache)
|
||||||
|
tool, err := New(context.Background(), repository)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("New() rejected successful discovery: %v", err)
|
||||||
|
}
|
||||||
|
if tool.HostTarget() != (Target{OS: runtime.GOOS, Arch: runtime.GOARCH}) || tool.settings["GOCACHE"] != cache {
|
||||||
|
t.Fatalf("discovered host=%v cache=%q", tool.HostTarget(), tool.settings["GOCACHE"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDiscoveryPreservesFailureDiagnosticsAndCause(t *testing.T) {
|
||||||
|
repository, _ := installGoPreparationFixture(t)
|
||||||
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "fail")
|
||||||
|
_, err := New(context.Background(), repository)
|
||||||
|
var exitError *exec.ExitError
|
||||||
|
if !errors.As(err, &exitError) || exitError.ExitCode() != 23 || !strings.Contains(err.Error(), "fixture dependency failure") {
|
||||||
|
t.Fatalf("New() error = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mustGetwd() string {
|
func mustGetwd() string {
|
||||||
directory, err := os.Getwd()
|
directory, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user