Run validation in the selected module
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/git"
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/gotool"
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/process"
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/releaseidentity"
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/validation"
|
||||
@@ -37,8 +38,9 @@ type Request struct {
|
||||
Version string
|
||||
Validation validation.Settings
|
||||
AdditionalChecks func(context.Context, Candidate) error
|
||||
AfterValidate func(context.Context, Candidate) error
|
||||
AfterValidate func(context.Context, Candidate, *gotool.Owner) error
|
||||
Output io.Writer
|
||||
ToolOwner *gotool.Owner
|
||||
}
|
||||
|
||||
func Check(ctx context.Context, request Request) (Candidate, error) {
|
||||
@@ -46,12 +48,18 @@ func Check(ctx context.Context, request Request) (Candidate, error) {
|
||||
if err != nil {
|
||||
return captured, err
|
||||
}
|
||||
request.ToolOwner = gotool.NewOwner(captured.ModuleDir)
|
||||
if err := Validate(ctx, request, captured); err != nil {
|
||||
return captured, err
|
||||
}
|
||||
if request.AfterValidate != nil {
|
||||
if err := request.AfterValidate(ctx, captured); err != nil {
|
||||
return captured, fmt.Errorf("after candidate validation: %w", err)
|
||||
callbackErr := request.AfterValidate(ctx, captured, request.ToolOwner)
|
||||
refreshErr := request.ToolOwner.Refresh(ctx)
|
||||
if callbackErr != nil {
|
||||
return captured, fmt.Errorf("after candidate validation: %w", callbackErr)
|
||||
}
|
||||
if refreshErr != nil {
|
||||
return captured, fmt.Errorf("refresh Go settings after candidate callback: %w", refreshErr)
|
||||
}
|
||||
}
|
||||
if err := Recheck(ctx, captured, ""); err != nil {
|
||||
@@ -120,18 +128,28 @@ func Capture(ctx context.Context, request Request) (Candidate, error) {
|
||||
// Validate runs the selected offline Go suite, followed by AdditionalChecks
|
||||
// when supplied, for the captured candidate.
|
||||
func Validate(ctx context.Context, request Request, captured Candidate) error {
|
||||
owner := request.ToolOwner
|
||||
if owner == nil {
|
||||
owner = gotool.NewOwner(captured.ModuleDir)
|
||||
}
|
||||
if err := validation.Run(ctx, validation.Request{
|
||||
RepositoryDir: captured.RepositoryDir,
|
||||
ModuleDir: captured.ModuleDir,
|
||||
Commit: captured.Commit,
|
||||
Output: request.Output,
|
||||
Settings: request.Validation,
|
||||
ToolOwner: owner,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("validate candidate %s: %w", captured.Commit, err)
|
||||
}
|
||||
if request.AdditionalChecks != nil {
|
||||
if err := request.AdditionalChecks(ctx, captured); err != nil {
|
||||
return fmt.Errorf("validate candidate %s: %w", captured.Commit, err)
|
||||
callbackErr := request.AdditionalChecks(ctx, captured)
|
||||
refreshErr := owner.Refresh(ctx)
|
||||
if callbackErr != nil {
|
||||
return fmt.Errorf("validate candidate %s: %w", captured.Commit, callbackErr)
|
||||
}
|
||||
if refreshErr != nil {
|
||||
return fmt.Errorf("refresh Go settings after additional checks: %w", refreshErr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -3,13 +3,17 @@ package candidate
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/gotool"
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/validation"
|
||||
)
|
||||
|
||||
@@ -159,7 +163,7 @@ func TestCheckStopsBeforeProductAndBuildCallbacksWhenGoFormatFails(t *testing.T)
|
||||
productCalls++
|
||||
return nil
|
||||
},
|
||||
AfterValidate: func(context.Context, Candidate) error {
|
||||
AfterValidate: func(context.Context, Candidate, *gotool.Owner) error {
|
||||
buildCalls++
|
||||
return nil
|
||||
},
|
||||
@@ -191,7 +195,7 @@ func TestCheckStopsBeforeProductAndBuildCallbacksWhenMarkdownBoundaryFails(t *te
|
||||
productCalls++
|
||||
return nil
|
||||
},
|
||||
AfterValidate: func(context.Context, Candidate) error {
|
||||
AfterValidate: func(context.Context, Candidate, *gotool.Owner) error {
|
||||
buildCalls++
|
||||
return nil
|
||||
},
|
||||
@@ -265,6 +269,125 @@ func TestCheckRunsDefaultOfflineGoValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckRefreshesGoSettingsAfterAdditionalChecks(t *testing.T) {
|
||||
repository := newRepository(t, "# Example Product v1.2.3\n\nRelease note.\n")
|
||||
t.Setenv("GOENV", "off")
|
||||
t.Setenv("GOMODCACHE", filepath.Join(t.TempDir(), "initial-module-cache"))
|
||||
selectedCache := filepath.Join(t.TempDir(), "callback-module-cache")
|
||||
var observed string
|
||||
_, err := Check(context.Background(), Request{
|
||||
RepositoryDir: repository,
|
||||
Product: "Example Product",
|
||||
Version: testVersion,
|
||||
AdditionalChecks: func(context.Context, Candidate) error {
|
||||
t.Setenv("GOMODCACHE", selectedCache)
|
||||
return nil
|
||||
},
|
||||
AfterValidate: func(ctx context.Context, captured Candidate, owner *gotool.Owner) error {
|
||||
tool, err := owner.Acquire(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
output, err := tool.Output(ctx, captured.ModuleDir, gotool.Native, gotool.Target{}, nil, "env", "GOMODCACHE")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
observed = strings.TrimSpace(string(output))
|
||||
return nil
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if observed != selectedCache {
|
||||
t.Fatalf("Go settings after additional checks = %q, want %q", observed, selectedCache)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckSharesGoDiscoveryWithAfterValidateCallback(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("the controlled Go command fixture uses a POSIX shell")
|
||||
}
|
||||
repository := newRepository(t, "# Example Product v1.2.3\n\nRelease note.\n")
|
||||
logPath := installCandidateGoShim(t)
|
||||
t.Setenv("GOENV", "off")
|
||||
_, err := Check(context.Background(), Request{
|
||||
RepositoryDir: repository,
|
||||
Product: "Example Product",
|
||||
Version: testVersion,
|
||||
AfterValidate: func(ctx context.Context, captured Candidate, owner *gotool.Owner) error {
|
||||
tool, err := owner.Acquire(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tool.Output(ctx, captured.ModuleDir, gotool.Native, gotool.Target{}, nil, "version")
|
||||
return err
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
contents, err := os.ReadFile(logPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
commands := strings.Split(strings.TrimSpace(string(contents)), "\n")
|
||||
var discoveries, suites, callbacks int
|
||||
for _, command := range commands {
|
||||
switch {
|
||||
case strings.HasPrefix(command, "env "):
|
||||
discoveries++
|
||||
case strings.HasPrefix(command, "test "):
|
||||
suites++
|
||||
case command == "version":
|
||||
callbacks++
|
||||
}
|
||||
}
|
||||
if discoveries != 2 || suites != 1 || callbacks != 1 {
|
||||
t.Fatalf("Go invocations = %q; discovery=%d suite=%d callback=%d, want 2, 1, 1", commands, discoveries, suites, callbacks)
|
||||
}
|
||||
}
|
||||
|
||||
func installCandidateGoShim(t *testing.T) string {
|
||||
t.Helper()
|
||||
directory := t.TempDir()
|
||||
logPath := filepath.Join(directory, "go-commands")
|
||||
settings := map[string]string{
|
||||
"GOHOSTOS": runtime.GOOS, "GOHOSTARCH": runtime.GOARCH, "GOENV": "off",
|
||||
"CC": "", "CXX": "", "CGO_CFLAGS": "", "CGO_CPPFLAGS": "", "CGO_CXXFLAGS": "",
|
||||
"CGO_ENABLED": "1", "CGO_LDFLAGS": "", "GOCACHE": "", "GOCACHEPROG": "",
|
||||
"GOMODCACHE": "", "GOPATH": "", "GOROOT": "", "GOTMPDIR": "", "PKG_CONFIG": "",
|
||||
}
|
||||
encoded, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
script := fmt.Sprintf(`#!/bin/sh
|
||||
set -eu
|
||||
printf '%%s\n' "$*" >> "$RELEASEKIT_GO_LOG"
|
||||
if [ "${1-}" = "env" ]; then
|
||||
printf '%%s\n' '%s'
|
||||
exit 0
|
||||
fi
|
||||
if [ "${1-}" = "version" ]; then
|
||||
echo 'go version fixture'
|
||||
exit 0
|
||||
fi
|
||||
exit 0
|
||||
`, encoded)
|
||||
shimPath := filepath.Join(directory, "go")
|
||||
if err := os.WriteFile(shimPath, []byte(script), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := directory
|
||||
if current := os.Getenv("PATH"); current != "" {
|
||||
path += string(os.PathListSeparator) + current
|
||||
}
|
||||
t.Setenv("PATH", path)
|
||||
t.Setenv("RELEASEKIT_GO_LOG", logPath)
|
||||
return logPath
|
||||
}
|
||||
|
||||
func TestDefaultValidationDoesNotInheritGOFLAGSRunFilter(t *testing.T) {
|
||||
repository := newRepository(t, "# Example Product v1.2.3\n\nRelease note.\n")
|
||||
writeTestFile(t, repository, "failure_test.go", "package candidate\nimport \"testing\"\nfunc TestExpectedFailure(t *testing.T) { t.Fatal(\"expected fixture failure\") }\n")
|
||||
|
||||
Reference in New Issue
Block a user