Run API-only recovery independently of consumer vendoring
This commit is contained in:
@@ -14,9 +14,106 @@ import (
|
||||
"testing"
|
||||
|
||||
"go.maximumdirect.net/releasekit/cmd/releasekit/internal/cli"
|
||||
"go.maximumdirect.net/releasekit/internal/gotool"
|
||||
"go.maximumdirect.net/releasekit/internal/publish"
|
||||
)
|
||||
|
||||
func TestVendoredAPIOnlyPublicationRecovery(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("fixture executes POSIX recovery commands")
|
||||
}
|
||||
repo, remote := newSimplePublishRepository(t, false)
|
||||
source := repositoryRoot(t)
|
||||
relative, err := filepath.Rel(repo, source)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeRepositoryFile(t, repo, "go.mod", "module example.com/cli-candidate\n\ngo 1.26.0\n\nrequire go.maximumdirect.net/releasekit v0.0.0\n\nreplace go.maximumdirect.net/releasekit => "+strconv.Quote(relative)+"\n")
|
||||
writeRepositoryFile(t, repo, "uses_releasekit.go", "package candidate\nimport _ \"go.maximumdirect.net/releasekit\"\n")
|
||||
sums, err := os.ReadFile(filepath.Join(source, "go.sum"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeRepositoryFile(t, repo, "go.sum", string(sums))
|
||||
goBinary := filepath.Join(runtime.GOROOT(), "bin", "go")
|
||||
for _, args := range [][]string{{"mod", "tidy"}, {"mod", "vendor"}} {
|
||||
command := exec.Command(goBinary, args...)
|
||||
command.Dir = repo
|
||||
if out, err := command.CombinedOutput(); err != nil {
|
||||
t.Fatalf("prepare vendored API: %v: %s", err, out)
|
||||
}
|
||||
}
|
||||
cliGitRun(t, repo, "add", ".")
|
||||
cliGitRun(t, repo, "commit", "-m", "Vendor API dependency")
|
||||
cliGitRun(t, repo, "push", "origin", "main")
|
||||
before := cliGitOutput(t, repo, "rev-parse", "HEAD^{tree}")
|
||||
if err := os.WriteFile(filepath.Join(remote, "hooks", "pre-receive"), []byte("#!/bin/sh\nexit 1\n"), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var out, diagnostics bytes.Buffer
|
||||
if status := run(t.Context(), []string{"publish", "--repo", repo, "v1.2.3"}, &out, &diagnostics); status != 1 {
|
||||
t.Fatalf("publication status=%d: %s", status, &diagnostics)
|
||||
}
|
||||
command := outputLineValue(diagnostics.String(), "recovery command: ")
|
||||
if command == "" {
|
||||
t.Fatalf("no handoff: %s", &diagnostics)
|
||||
}
|
||||
recovery := exec.Command("sh", "-c", command)
|
||||
recovery.Dir = t.TempDir()
|
||||
recovered, err := recovery.CombinedOutput()
|
||||
var exitError *exec.ExitError
|
||||
if !errors.As(err, &exitError) || exitError.ExitCode() != 1 || !strings.Contains(string(recovered), "module=example.com/cli-candidate tag=v1.2.3 state=not_published") {
|
||||
t.Fatalf("vendored recovery: %v: %s", err, recovered)
|
||||
}
|
||||
if status := cliGitOutput(t, repo, "status", "--porcelain"); status != "" {
|
||||
t.Fatalf("handoff changed consumer files: %s", status)
|
||||
}
|
||||
if after := cliGitOutput(t, repo, "write-tree"); after != before {
|
||||
t.Fatalf("handoff changed consumer index: %s != %s", after, before)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecoveryToolPreservesVersionedReplacement(t *testing.T) {
|
||||
proxy := writeReleaseKitModuleProxy(t)
|
||||
environment := make(map[string]string)
|
||||
useSyntheticModuleProxy(t, environment, "file://"+filepath.ToSlash(proxy))
|
||||
for key, value := range environment {
|
||||
t.Setenv(key, value)
|
||||
}
|
||||
module := t.TempDir()
|
||||
data := "module example.com/recovery-consumer\n\ngo 1.26.0\n\nrequire go.maximumdirect.net/releasekit v0.2.197\n\nreplace go.maximumdirect.net/releasekit v0.2.197 => go.maximumdirect.net/releasekit v0.2.198\n"
|
||||
if err := os.WriteFile(filepath.Join(module, "go.mod"), []byte(data), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
args, err := gotool.RecoveryTool(t.Context(), module, t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
command := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
|
||||
command.Dir = t.TempDir()
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil || !strings.Contains(string(output), "tool-version=v0.2.198 helper=tool-only dependency") {
|
||||
t.Fatalf("versioned recovery selection: %v: %s", err, output)
|
||||
}
|
||||
after, err := os.ReadFile(filepath.Join(module, "go.mod"))
|
||||
if err != nil || string(after) != data {
|
||||
t.Fatalf("consumer metadata changed: %q, %v", after, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecoveryToolSupportsReleaseKitSourceModule(t *testing.T) {
|
||||
args, err := gotool.RecoveryTool(t.Context(), repositoryRoot(t), t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
command := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), append(args, "version")...)
|
||||
command.Dir = t.TempDir()
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil || !strings.HasPrefix(string(output), "releasekit ") {
|
||||
t.Fatalf("source module recovery entry point: %v: %s", err, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestColdGoToolRecoverySurvivesLauncherExit(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("fixture observes the cold executable through /proc")
|
||||
|
||||
Reference in New Issue
Block a user