Files
releasekit/preparation_graph_test.go

165 lines
5.9 KiB
Go
Raw Normal View History

package releasekit_test
import (
"archive/zip"
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"testing"
releasekit "go.maximumdirect.net/releasekit"
)
func TestPrepareBuildDependenciesSelectedModuleGraphs(t *testing.T) {
repo := t.TempDir()
nested := filepath.Join(repo, "nested")
child := filepath.Join(nested, "child")
if err := os.MkdirAll(child, 0755); err != nil {
t.Fatal(err)
}
write := func(path, value string) {
t.Helper()
if err := os.WriteFile(path, []byte(value), 0644); err != nil {
t.Fatal(err)
}
}
write(filepath.Join(repo, "go.mod"), "module example.invalid/root\n\ngo 1.25.0\n\nrequire example.invalid/rootdep v1.0.0\n")
write(filepath.Join(nested, "go.mod"), "module example.invalid/nested\n\ngo 1.25.0\n\nrequire example.invalid/nesteddep v1.0.0\n")
alt := filepath.Join(repo, "alternate.mod")
write(alt, "module example.invalid/alternate\n\ngo 1.25.0\n")
buildGit(t, repo, "init", "-b", "main")
buildGit(t, repo, "config", "user.name", "Test")
buildGit(t, repo, "config", "user.email", "test@example.invalid")
buildGit(t, repo, "add", ".")
buildGit(t, repo, "commit", "-m", "fixture")
proxy := t.TempDir()
for _, dep := range []string{"rootdep", "nesteddep"} {
writePreparationProxy(t, proxy, "example.invalid/"+dep)
}
t.Setenv("GOPROXY", "file://"+filepath.ToSlash(proxy))
t.Setenv("GOSUMDB", "off")
t.Setenv("GOPRIVATE", "")
t.Setenv("GONOPROXY", "none")
t.Setenv("GONOSUMDB", "*")
t.Setenv("GOTOOLCHAIN", "local")
t.Setenv("GOWORK", "off")
realGo, err := exec.LookPath("go")
if err != nil {
t.Fatal(err)
}
for _, tc := range []struct {
name, module, dep, modulePath string
persistent bool
}{
{"inherited root", "", "rootdep", "example.invalid/root", false},
{"persistent nested", "nested", "nesteddep", "example.invalid/nested", true},
} {
t.Run(tc.name, func(t *testing.T) {
cache := filepath.Join(t.TempDir(), "cache")
t.Setenv("GOMODCACHE", cache)
envFile := filepath.Join(t.TempDir(), "goenv")
flags := "-modfile=" + alt + " -modcacherw"
if tc.persistent {
write(envFile, "GOFLAGS="+flags+"\n")
t.Setenv("GOENV", envFile)
t.Setenv("GOFLAGS", "")
if err := os.Unsetenv("GOFLAGS"); err != nil {
t.Fatal(err)
}
} else {
t.Setenv("GOENV", "off")
t.Setenv("GOFLAGS", flags)
}
// Without the explicit override, the alternate file has no dependencies.
negativeCache := filepath.Join(t.TempDir(), "negative")
command := exec.Command(realGo, "mod", "download")
command.Dir = repo
command.Env = append(os.Environ(), "GOMODCACHE="+negativeCache)
if out, err := command.CombinedOutput(); err != nil {
t.Fatalf("negative control: %v: %s", err, out)
}
if _, err := os.Stat(filepath.Join(negativeCache, "cache", "download", "example.invalid", tc.dep)); !os.IsNotExist(err) {
t.Fatalf("alternate graph unexpectedly downloaded %s: %v", tc.dep, err)
}
if err := releasekit.PrepareBuildDependencies(context.Background(), releasekit.DependencyPreparationRequest{RepositoryDir: child, ModuleDir: tc.module}); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(cache, "cache", "download", "example.invalid", tc.dep, "@v", "v1.0.0.zip")); err != nil {
t.Fatalf("selected dependency missing: %v", err)
}
other := "rootdep"
if tc.dep == other {
other = "nesteddep"
}
if _, err := os.Stat(filepath.Join(cache, "cache", "download", "example.invalid", other)); !os.IsNotExist(err) {
t.Fatalf("unexpected other graph: %v", err)
}
info, err := os.Stat(filepath.Join(cache, "example.invalid", tc.dep+"@v1.0.0"))
if err != nil || info.Mode().Perm()&0200 == 0 {
t.Fatalf("-modcacherw did not take effect: %v, %v", info, err)
}
result, err := releasekit.Build(context.Background(), releasekit.BuildRequest{RepositoryDir: child, ModuleDir: tc.module, Version: "v1.2.3"})
expected := repo
if tc.module != "" {
expected = nested
}
if err != nil || result.RepositoryDir != repo || result.ModuleDir != expected || result.ModulePath != tc.modulePath {
t.Fatalf("build identity = %#v, error = %v", result, err)
}
})
}
// Standalone package subdirectories retain Go's upward module discovery.
standalone := t.TempDir()
pkg := filepath.Join(standalone, "pkg")
if err := os.Mkdir(pkg, 0755); err != nil {
t.Fatal(err)
}
write(filepath.Join(standalone, "go.mod"), "module example.invalid/standalone\n\ngo 1.25.0\n\nrequire example.invalid/rootdep v1.0.0\n")
t.Setenv("GOENV", "off")
t.Setenv("GOFLAGS", "-modfile="+alt+" -modcacherw")
cache := filepath.Join(t.TempDir(), "cache")
t.Setenv("GOMODCACHE", cache)
if err := releasekit.PrepareBuildDependencies(context.Background(), releasekit.DependencyPreparationRequest{RepositoryDir: pkg}); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(cache, "cache", "download", "example.invalid", "rootdep", "@v", "v1.0.0.zip")); err != nil {
t.Fatal(err)
}
}
func writePreparationProxy(t *testing.T, proxy, module string) {
t.Helper()
dir := filepath.Join(proxy, filepath.FromSlash(module), "@v")
if err := os.MkdirAll(dir, 0755); err != nil {
t.Fatal(err)
}
mod := "module " + module + "\n\ngo 1.25.0\n"
for name, contents := range map[string]string{"v1.0.0.mod": mod, "v1.0.0.info": `{"Version":"v1.0.0","Time":"2026-01-01T00:00:00Z"}`, "list": "v1.0.0\n"} {
if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil {
t.Fatal(err)
}
}
file, err := os.Create(filepath.Join(dir, "v1.0.0.zip"))
if err != nil {
t.Fatal(err)
}
z := zip.NewWriter(file)
for name, contents := range map[string]string{"go.mod": mod, "dep.go": "package dep\n"} {
w, err := z.Create(fmt.Sprintf("%s@v1.0.0/%s", module, name))
if err != nil {
t.Fatal(err)
}
if _, err := w.Write([]byte(contents)); err != nil {
t.Fatal(err)
}
}
if err := z.Close(); err != nil {
t.Fatal(err)
}
if err := file.Close(); err != nil {
t.Fatal(err)
}
}