165 lines
5.9 KiB
Go
165 lines
5.9 KiB
Go
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)
|
|
}
|
|
}
|