mesh-build-go: bring the mirror to the trunk commit so the merge preview deepens from it, and place the siblings side by side (issue 1921, try speed S6)
This commit is contained in:
@@ -184,6 +184,12 @@ func (m *Module) fetchPhases(ctx context.Context, req buildstep.FetchRequest, id
|
||||
}
|
||||
remote := m.remote(repository)
|
||||
opts := m.fetchOptions(ctx, repository, commit, ref)
|
||||
mergeOpts := m.FetchOptions
|
||||
if base != "" {
|
||||
// The mirror is brought to the trunk commit too, so the merge preview deepens the tree from it and asks the forge
|
||||
// for no history the mirror holds (issue 1921, try speed S6).
|
||||
mergeOpts = m.fetchOptions(ctx, repository, base, "")
|
||||
}
|
||||
clock.lap(&took.Mirror)
|
||||
if err := buildstep.FetchCommit(ctx, m.Run, tree, remote, commit, ref, opts...); err != nil {
|
||||
return FetchResult{}, err
|
||||
@@ -191,7 +197,7 @@ func (m *Module) fetchPhases(ctx context.Context, req buildstep.FetchRequest, id
|
||||
clock.lap(&took.Fetch)
|
||||
res := FetchResult{Workspace: id, Commit: commit, Took: took}
|
||||
if base != "" {
|
||||
if err := m.merge(ctx, &res, tree, remote, base, commit); err != nil {
|
||||
if err := m.merge(ctx, &res, tree, remote, base, commit, mergeOpts); err != nil {
|
||||
return FetchResult{}, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +349,8 @@ func TestTheFetchSaysTheTimeOfEachPhaseAndTheyAddUpToTheTotal(t *testing.T) {
|
||||
t.Fatalf("the result says no phase times: %s", st.Result)
|
||||
}
|
||||
got := *res.Took
|
||||
want := FetchTook{Mirror: 1, Fetch: 2, Merge: 3, Dissociate: 4, Modules: 5, Total: 15}
|
||||
// the mirror is brought to the head and to the base (1 s each), and the preview deepens from it (1 s) before merging
|
||||
want := FetchTook{Mirror: 2, Fetch: 2, Merge: 4, Dissociate: 4, Modules: 5, Total: 17}
|
||||
if got != want {
|
||||
t.Errorf("phases = %+v, want %+v", got, want)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
||||
)
|
||||
|
||||
func fetchOnce(t *testing.T, m *Module, states *keptStates, args map[string]any) FetchResult {
|
||||
@@ -188,3 +189,61 @@ func TestTheWorkspaceIsSelfContainedAfterAFetchThroughTheMirror(t *testing.T) {
|
||||
t.Errorf("the workspace is not whole: %v %s", err, out)
|
||||
}
|
||||
}
|
||||
|
||||
// 1921/S6: with a base, the mirror is brought to the trunk commit too, and the merge preview deepens the tree from the
|
||||
// mirror: it asks the forge for no history the mirror holds.
|
||||
func TestTheMirrorIsBroughtToTheBaseAndThePreviewFetchesFromIt(t *testing.T) {
|
||||
f := &fakeStep{gomods: "go.mod\n", rule: previewRules(false)}
|
||||
m, states := fetchModule(t, f)
|
||||
mirror := filepath.Join(m.Cache, "mirror", "novox", "mesh-sdk.git")
|
||||
f.files = map[string]string{"modules/m/module.json": "{}\n", "modules/m/go.sum": "sum\n", "go.mod": "module x\n", "go.sum": ""}
|
||||
fetchOnce(t, m, states, map[string]any{"repository": "novox/mesh-sdk", "commit": commitSHA, "base": baseSHA})
|
||||
lines := strings.Join(f.lines(), "\n")
|
||||
if !strings.Contains(lines, "-C "+mirror+" fetch --no-tags origin "+baseSHA) {
|
||||
t.Errorf("the mirror was not brought to the base:\n%s", lines)
|
||||
}
|
||||
if !strings.Contains(lines, "fetch --no-tags --unshallow "+mirror+" "+baseSHA) || strings.Contains(lines, "--unshallow origin") {
|
||||
t.Errorf("the preview fetched the trunk's history from the forge:\n%s", lines)
|
||||
}
|
||||
}
|
||||
|
||||
// 1921/S6: the siblings are placed side by side: each sibling's fetch has started before any of them ends.
|
||||
func TestTheSiblingsArePlacedAtOnce(t *testing.T) {
|
||||
var mu sync.Mutex
|
||||
started := map[string]bool{}
|
||||
both := make(chan struct{})
|
||||
f := &fakeStep{gomods: "go.mod\n"}
|
||||
f.rule = func(line string) (forgekey.Ran, bool) {
|
||||
if !strings.Contains(line, "/beside/") || !strings.Contains(line, " fetch --no-tags --depth 1 ") {
|
||||
return forgekey.Ran{}, false
|
||||
}
|
||||
mu.Lock()
|
||||
for _, name := range []string{"mesh-catalog", "mesh-host"} {
|
||||
if strings.Contains(line, "/beside/"+name) {
|
||||
started[name] = true
|
||||
}
|
||||
}
|
||||
if len(started) == 2 {
|
||||
select {
|
||||
case <-both:
|
||||
default:
|
||||
close(both)
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
select {
|
||||
case <-both:
|
||||
case <-time.After(2 * time.Second):
|
||||
return forgekey.Ran{Status: 1, Stderr: "the other sibling's fetch never started"}, true
|
||||
}
|
||||
return forgekey.Ran{}, false
|
||||
}
|
||||
m, states := fetchModule(t, f)
|
||||
res := fetchOnce(t, m, states, map[string]any{"repository": "novox/mesh-controller", "commit": commitSHA, "beside": []any{
|
||||
map[string]any{"repository": "novox/mesh-host", "commit": commitSHA},
|
||||
map[string]any{"repository": "novox/mesh-catalog", "commit": commitSHA},
|
||||
}})
|
||||
if len(res.Beside) != 2 || res.Beside[0].Dir != "mesh-catalog" || res.Beside[1].Dir != "mesh-host" {
|
||||
t.Errorf("beside = %+v, want both, in name order", res.Beside)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/buildstep"
|
||||
)
|
||||
@@ -34,8 +35,9 @@ func (m *Module) remote(repository string) string {
|
||||
}
|
||||
|
||||
// merge makes the merge preview of the head onto base and writes the answer into res.
|
||||
func (m *Module) merge(ctx context.Context, res *FetchResult, tree, remote, base, commit string) error {
|
||||
mr, err := buildstep.MergeInto(ctx, m.Run, tree, remote, base, commit, m.FetchOptions...)
|
||||
// opts are the fetch's options, with the mirror when it holds base.
|
||||
func (m *Module) merge(ctx context.Context, res *FetchResult, tree, remote, base, commit string, opts []buildstep.Option) error {
|
||||
mr, err := buildstep.MergeInto(ctx, m.Run, tree, remote, base, commit, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -89,23 +91,22 @@ func (m *Module) besideDir(workspace string) string {
|
||||
// placeSiblings fetches each sibling into beside/<name> of the workspace root, as a plain directory. A symlink anywhere
|
||||
// in a placed tree fails the step naming it: the mesh creates none, and a test must not be led out of its sibling.
|
||||
func (m *Module) placeSiblings(ctx context.Context, root string, siblings []siblingArg) ([]Sibling, error) {
|
||||
var placed []Sibling
|
||||
for _, s := range siblings {
|
||||
name := s.repository[strings.Index(s.repository, "/")+1:]
|
||||
dir := filepath.Join(root, "beside", name)
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
// The siblings are placed side by side (issue 1921, try speed S6); the first failure in the order given is the step's.
|
||||
placed := make([]Sibling, len(siblings))
|
||||
errs := make([]error, len(siblings))
|
||||
var wg sync.WaitGroup
|
||||
for i, s := range siblings {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
placed[i], errs[i] = m.placeSibling(ctx, root, s)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := buildstep.FetchCommit(ctx, m.Run, dir, m.remote(s.repository), s.commit, s.ref, m.fetchOptions(ctx, s.repository, s.commit, s.ref)...); err != nil {
|
||||
return nil, fmt.Errorf("beside %s: %w", s.repository, err)
|
||||
}
|
||||
if err := m.dissociate(ctx, dir); err != nil {
|
||||
return nil, fmt.Errorf("beside %s: %w", s.repository, err)
|
||||
}
|
||||
if link := firstSymlink(dir); link != "" {
|
||||
return nil, fmt.Errorf("beside %s holds a symlink, %s", s.repository, link)
|
||||
}
|
||||
placed = append(placed, Sibling{Repository: s.repository, Commit: s.commit, Dir: name})
|
||||
}
|
||||
sort.Slice(placed, func(i, j int) bool { return placed[i].Dir < placed[j].Dir })
|
||||
if len(placed) > 0 {
|
||||
@@ -121,6 +122,25 @@ func (m *Module) placeSiblings(ctx context.Context, root string, siblings []sibl
|
||||
return placed, nil
|
||||
}
|
||||
|
||||
// placeSibling fetches one sibling into beside/<name> of the workspace root.
|
||||
func (m *Module) placeSibling(ctx context.Context, root string, s siblingArg) (Sibling, error) {
|
||||
name := s.repository[strings.Index(s.repository, "/")+1:]
|
||||
dir := filepath.Join(root, "beside", name)
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
return Sibling{}, err
|
||||
}
|
||||
if err := buildstep.FetchCommit(ctx, m.Run, dir, m.remote(s.repository), s.commit, s.ref, m.fetchOptions(ctx, s.repository, s.commit, s.ref)...); err != nil {
|
||||
return Sibling{}, fmt.Errorf("beside %s: %w", s.repository, err)
|
||||
}
|
||||
if err := m.dissociate(ctx, dir); err != nil {
|
||||
return Sibling{}, fmt.Errorf("beside %s: %w", s.repository, err)
|
||||
}
|
||||
if link := firstSymlink(dir); link != "" {
|
||||
return Sibling{}, fmt.Errorf("beside %s holds a symlink, %s", s.repository, link)
|
||||
}
|
||||
return Sibling{Repository: s.repository, Commit: s.commit, Dir: name}, nil
|
||||
}
|
||||
|
||||
// besideRecord is the file in a workspace's root naming the siblings the fetch placed beside it.
|
||||
const besideRecord = "beside.json"
|
||||
|
||||
|
||||
@@ -85,7 +85,8 @@ func TestFetchWithABaseMergesAndAnswersThePreview(t *testing.T) {
|
||||
t.Errorf("trees = %+v", res.Trees)
|
||||
}
|
||||
lines := strings.Join(f.lines(), "\n")
|
||||
for _, want := range []string{"fetch --no-tags --unshallow origin " + baseSHA, "checkout -q --detach " + baseSHA,
|
||||
mirror := filepath.Join(m.Cache, "mirror", "novox", "mesh-sdk.git")
|
||||
for _, want := range []string{"fetch --no-tags --unshallow " + mirror + " " + baseSHA, "checkout -q --detach " + baseSHA,
|
||||
"core.hooksPath=/dev/null", "merge --no-ff --no-edit --no-verify"} {
|
||||
if !strings.Contains(lines, want) {
|
||||
t.Errorf("git was not asked %q:\n%s", want, lines)
|
||||
|
||||
@@ -3,7 +3,7 @@ module meshbuildgo
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024225846-cb548a6a588c
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024230839-4a12ccb78d19
|
||||
github.com/distribution/distribution/v3 v3.1.2
|
||||
github.com/nats-io/nats-server/v2 v2.11.17
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
|
||||
@@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024214154-bc16740feb0d h1:oJREw0gg
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024214154-bc16740feb0d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024225846-cb548a6a588c h1:GWHP9ozfkFXHVEL2gE4Xa5kc5e8uPO+UL9+mau6iaIs=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024225846-cb548a6a588c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024230839-4a12ccb78d19 h1:NqU4hkk/jHdTEcGFnnXvdOJwD8dH5u+qWaCdQQ+JYMc=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024230839-4a12ccb78d19/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
|
||||
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
|
||||
Reference in New Issue
Block a user