Share one placement per repository and commit for pins on pull heads; say a pin is on no pull request head and what go said (issue 1148)
This commit is contained in:
@@ -107,7 +107,7 @@ func (m *Module) resolvePins(ctx context.Context, root, dir, failure string) (bo
|
||||
if !strings.Contains(failure, p.short) || strings.Contains(done, "replace "+p.module+" =>") {
|
||||
continue
|
||||
}
|
||||
where, err := m.placePin(ctx, root, p)
|
||||
where, err := m.placePin(ctx, root, p, failure)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func (m *Module) resolvePins(ctx context.Context, root, dir, failure string) (bo
|
||||
|
||||
// placePin finds the commit of a pin among the pull request heads of the forge, places the repository at it beside
|
||||
// the workspace (the way a fetch places a sibling) and answers the directory of the module in it.
|
||||
func (m *Module) placePin(ctx context.Context, root string, p pin) (string, error) {
|
||||
func (m *Module) placePin(ctx context.Context, root string, p pin, failure string) (string, error) {
|
||||
repository := "novox/" + p.repo
|
||||
r := m.Run(ctx, []string{"GIT_TERMINAL_PROMPT=0"}, "git", "-c", "credential.helper=", "ls-remote", m.remote(repository), "refs/pull/*/head")
|
||||
if r.Status != 0 || r.Err != "" {
|
||||
@@ -135,12 +135,18 @@ func (m *Module) placePin(ctx context.Context, root string, p pin) (string, erro
|
||||
}
|
||||
}
|
||||
if commit == "" {
|
||||
return "", fmt.Errorf("the pin of %s at commit %s is on no branch, tag or pull request head of %s on the forge", p.module, p.short, repository)
|
||||
return "", fmt.Errorf("the pin of %s at commit %s is on no pull request head of %s on the forge; go said: %s", p.module, p.short, repository, causeLine(failure))
|
||||
}
|
||||
if _, err := m.placeSiblings(ctx, filepath.Join(root, "pinned"), []siblingArg{{repository: repository, commit: commit, ref: ref}}); err != nil {
|
||||
// One placement per repository and commit, shared by every go.mod directory of the tree that pins it.
|
||||
at := filepath.Join(root, "pinned", p.repo+"@"+commit)
|
||||
where := filepath.Join(at, "beside", p.repo, filepath.FromSlash(p.sub))
|
||||
if _, err := os.Stat(filepath.Join(at, "beside", p.repo)); err == nil {
|
||||
return where, nil
|
||||
}
|
||||
if _, err := m.placeSiblings(ctx, at, []siblingArg{{repository: repository, commit: commit, ref: ref}}); err != nil {
|
||||
return "", fmt.Errorf("the pin of %s at commit %s: %w", p.module, p.short, err)
|
||||
}
|
||||
return filepath.Join(root, "pinned", "beside", p.repo, filepath.FromSlash(p.sub)), nil
|
||||
return where, nil
|
||||
}
|
||||
|
||||
// replaceInModfile adds `replace module => where` to the temporary modfile of dir, made from the directory's go.mod and
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@@ -19,7 +20,12 @@ import (
|
||||
// commit) and a Go member pinning that head by a pseudo-version, when build_go_fetch then build_go_build run on the
|
||||
// member, then both pass, the build with GOPROXY=off.
|
||||
func TestRealFetchAndBuildOfAMemberPinningAPullHead(t *testing.T) {
|
||||
needTools(t, "the pin", "go", "git")
|
||||
// Not skipped when a tool is missing: a pass of the check must mean this test ran (the check prints no test log).
|
||||
for _, tool := range []string{"go", "git"} {
|
||||
if _, err := exec.LookPath(tool); err != nil {
|
||||
t.Fatalf("no %s where this check runs: the pin on a pull request's head cannot be proven", tool)
|
||||
}
|
||||
}
|
||||
f := newForge(t)
|
||||
work, fork := f.repo("novox/dep", map[string]string{"README": "dep\n"})
|
||||
head := f.commit("novox/dep", work, fork, map[string]string{
|
||||
|
||||
@@ -42,8 +42,12 @@ func newPinHarness(t *testing.T, gomod string, vendor bool, pulls string) (*pinH
|
||||
for i, a := range args {
|
||||
if a == "-C" {
|
||||
os.MkdirAll(args[i+1], 0o755)
|
||||
os.WriteFile(filepath.Join(args[i+1], "go.mod"), []byte(gomod), 0o644)
|
||||
os.WriteFile(filepath.Join(args[i+1], "go.sum"), []byte("sum\n"), 0o644)
|
||||
for _, g := range strings.Fields(f.gomods) {
|
||||
d := filepath.Join(args[i+1], filepath.Dir(g))
|
||||
os.MkdirAll(d, 0o755)
|
||||
os.WriteFile(filepath.Join(d, "go.mod"), []byte(gomod), 0o644)
|
||||
os.WriteFile(filepath.Join(d, "go.sum"), []byte("sum\n"), 0o644)
|
||||
}
|
||||
if vendor {
|
||||
os.MkdirAll(filepath.Join(args[i+1], "vendor"), 0o755)
|
||||
os.WriteFile(filepath.Join(args[i+1], "vendor", "modules.txt"), nil, 0o644)
|
||||
@@ -95,7 +99,7 @@ func TestAPinOnAPullHeadIsPlacedBesideAndHandedToGoByAModfile(t *testing.T) {
|
||||
if st.State != delivery.StepPassed {
|
||||
t.Fatalf("the step ended %s: %s", st.State, st.Reason)
|
||||
}
|
||||
placed := filepath.Join(h.m.Work, res.Workspace, "pinned", "beside", "mesh-sdk")
|
||||
placed := filepath.Join(h.m.Work, res.Workspace, "pinned", "mesh-sdk@"+commitSHA, "beside", "mesh-sdk")
|
||||
if !h.ran("-C " + placed + " checkout -q --detach " + commitSHA) {
|
||||
t.Errorf("mesh-sdk was not placed at %s at the commit:\n%s", placed, strings.Join(h.f.lines(), "\n"))
|
||||
}
|
||||
@@ -159,7 +163,8 @@ func TestAPinOnNoRefFailsNamingTheModuleAndTheCommit(t *testing.T) {
|
||||
if st.State != delivery.StepFailed {
|
||||
t.Fatalf("the step ended %s, want failed", st.State)
|
||||
}
|
||||
if !strings.Contains(st.Reason, "git.novox.be/novox/mesh-sdk/go") || !strings.Contains(st.Reason, pinShort) {
|
||||
if !strings.Contains(st.Reason, "no pull request head") || !strings.Contains(st.Reason, "unknown revision") ||
|
||||
!strings.Contains(st.Reason, "git.novox.be/novox/mesh-sdk/go") || !strings.Contains(st.Reason, pinShort) {
|
||||
t.Errorf("the reason does not name the module and the commit: %q", st.Reason)
|
||||
}
|
||||
if !h.ran("ls-remote") {
|
||||
@@ -178,3 +183,64 @@ func TestAVendoringDirectoryResolvesNothing(t *testing.T) {
|
||||
t.Errorf("a vendoring directory was resolved:\n%s", strings.Join(h.f.lines(), "\n"))
|
||||
}
|
||||
}
|
||||
|
||||
// 1148/AC1 (a repository with several go.mod directories, as mesh-catalog has): two directories pinning the same pull
|
||||
// head share one placement and both are handed a modfile; the fetch does not fail placing it twice.
|
||||
func TestTwoDirectoriesPinningOneHeadShareOnePlacement(t *testing.T) {
|
||||
h, states := newPinHarness(t, pinnedGoMod, false, pullList)
|
||||
h.f.gomods = "go.mod\nsub/go.mod\n"
|
||||
res, st := h.fetch(states)
|
||||
if st.State != delivery.StepPassed {
|
||||
t.Fatalf("the step ended %s: %s", st.State, st.Reason)
|
||||
}
|
||||
checkouts := 0
|
||||
for _, c := range h.cmds {
|
||||
if strings.Contains(c.line, "pinned") && strings.Contains(c.line, " checkout ") {
|
||||
checkouts++
|
||||
}
|
||||
}
|
||||
if checkouts != 1 {
|
||||
t.Errorf("the repository was placed %d times, want once:\n%s", checkouts, strings.Join(h.f.lines(), "\n"))
|
||||
}
|
||||
for _, d := range []string{"tree", "tree/sub"} {
|
||||
if _, ok := h.m.pinModfile(filepath.Join(h.m.Work, res.Workspace, d)); !ok {
|
||||
t.Errorf("%s was not handed a modfile", d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1148/AC1: two directories pinning two different commits of one repository get two placements, each its own.
|
||||
func TestTwoCommitsOfOneRepositoryGetTwoPlacements(t *testing.T) {
|
||||
other := "fedcba9876543210fedcba9876543210fedcba98"
|
||||
h, states := newPinHarness(t, pinnedGoMod, false, commitSHA+"\trefs/pull/7/head\n"+other+"\trefs/pull/8/head\n")
|
||||
h.f.gomods = "go.mod\nsub/go.mod\n"
|
||||
base := h.m.Run
|
||||
h.m.Run = func(ctx context.Context, env []string, name string, args ...string) forgekey.Ran {
|
||||
if name == "git" && strings.Contains(strings.Join(args, " "), "pinned/mesh-sdk@"+other+"/") && strings.Contains(strings.Join(args, " "), " rev-parse HEAD") {
|
||||
return forgekey.Ran{Stdout: other + "\n"}
|
||||
}
|
||||
// the second directory pins the other commit
|
||||
if name == "git" && strings.Contains(strings.Join(args, " "), " checkout ") && !strings.Contains(strings.Join(args, " "), "pinned") {
|
||||
r := base(ctx, env, name, args...)
|
||||
for i, a := range args {
|
||||
if a == "-C" {
|
||||
os.WriteFile(filepath.Join(args[i+1], "sub", "go.mod"), []byte(strings.ReplaceAll(pinnedGoMod, pinShort, other[:12])), 0o644)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
if name == "go" && strings.Contains(strings.Join(args, " "), "/sub mod download") && !strings.Contains(strings.Join(env, " "), "-modfile=") {
|
||||
return forgekey.Ran{Status: 1, Stderr: "go: git.novox.be/novox/mesh-sdk/go@v0.1.15-0.20261022120000-" + other[:12] + ": invalid version: unknown revision " + other[:12] + "\n"}
|
||||
}
|
||||
return base(ctx, env, name, args...)
|
||||
}
|
||||
_, st := h.fetch(states)
|
||||
if st.State != delivery.StepPassed {
|
||||
t.Fatalf("the step ended %s: %s", st.State, st.Reason)
|
||||
}
|
||||
for _, c := range []string{commitSHA, other} {
|
||||
if !h.ran("pinned/mesh-sdk@" + c) {
|
||||
t.Errorf("no placement of mesh-sdk at %s", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user