Preserve replacement selectors during recovery

This commit is contained in:
2026-11-04 01:25:34 +00:00
parent ec67496569
commit b5c6638538
4 changed files with 57 additions and 14 deletions

View File

@@ -15,6 +15,8 @@ import (
"testing"
"time"
"golang.org/x/mod/modfile"
"go.maximumdirect.net/releasekit/cmd/releasekit/internal/cli"
"go.maximumdirect.net/releasekit/internal/gotool"
"go.maximumdirect.net/releasekit/internal/publish"
@@ -159,16 +161,25 @@ func TestColdGoToolRecoverySurvivesLauncherExit(t *testing.T) {
if err := os.Symlink(source, selectedSource); err != nil {
t.Fatal(err)
}
if !registered {
relative, err := filepath.Rel(repo, selectedSource)
const toolModule = "go.maximumdirect.net/releasekit"
const toolVersion = "v0.0.0"
module := "module example.com/cli-candidate\n\ngo 1.26.0\n\nrequire " + toolModule + " " + toolVersion + "\n"
var wildcardSource string
if registered {
module += "\nreplace " + toolModule + " => " + strconv.Quote(selectedSource) + "\n"
module += "\ntool " + toolModule + "/cmd/releasekit\n"
} else {
wildcardSource = t.TempDir()
writeRepositoryFile(t, wildcardSource, "go.mod", "module "+toolModule+"\n\ngo 1.26.0\n")
wildcard, err := filepath.Rel(repo, wildcardSource)
if err != nil {
t.Fatal(err)
}
selectedSource = relative
}
module := "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(selectedSource) + "\n"
if registered {
module += "\ntool go.maximumdirect.net/releasekit/cmd/releasekit\n"
specific, err := filepath.Rel(repo, selectedSource)
if err != nil {
t.Fatal(err)
}
module += "\nreplace (\n" + toolModule + " => " + strconv.Quote(wildcard) + "\n" + toolModule + " " + toolVersion + " => " + strconv.Quote(specific) + "\n)\n"
}
writeRepositoryFile(t, repo, "go.mod", module)
sums, err := os.ReadFile(filepath.Join(source, "go.sum"))
@@ -251,8 +262,34 @@ func TestColdGoToolRecoverySurvivesLauncherExit(t *testing.T) {
if !strings.Contains(command, "go ") || strings.Contains(command, "/exe/releasekit") {
t.Fatalf("unstable handoff: %s", command)
}
if !registered && !strings.Contains(command, "publication-recovery") {
t.Fatalf("API-only handoff lacks durable metadata: %s", command)
if !registered {
store := filepath.Join(repo, ".git", "releasekit", "publication-recovery")
entries, err := os.ReadDir(store)
if err != nil || len(entries) != 1 {
t.Fatalf("API-only recovery modules = %v, %v", entries, err)
}
dir := filepath.Join(store, entries[0].Name())
if !strings.Contains(command, shellQuote(dir)) {
t.Fatalf("API-only handoff lacks durable metadata: %s", command)
}
path := filepath.Join(dir, "go.mod")
data, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
prepared, err := modfile.Parse(path, data, nil)
if err != nil {
t.Fatal(err)
}
paths := map[string]string{}
for _, replacement := range prepared.Replace {
if replacement.Old.Path == toolModule {
paths[replacement.Old.Version] = replacement.New.Path
}
}
if len(paths) != 2 || paths[""] != wildcardSource || paths[toolVersion] != selectedSource {
t.Fatalf("durable recovery lost replacement selection: %v", paths)
}
}
// Execute from another directory after the original driver and the
// API-only launcher's temporary files are gone.