buildstep: deepen a merge preview's history from the mirror when it holds the trunk commit, so the preview fetches no history from the forge (issue 1921, try speed S6)
This commit is contained in:
+15
-6
@@ -24,7 +24,8 @@ type MergeResult struct {
|
||||
// signature, no hook, nothing of the machine's git configuration that changes a merge. Nothing is pushed.
|
||||
//
|
||||
// A merge needs both histories, so it makes the fetch whole (the shallow clone FetchCommit made is deepened) and
|
||||
// fetches base by its sha. A head that does not merge cleanly is an answer, not an error: the files in conflict, the
|
||||
// fetches base by its sha: from the mirror WithMirror names, when it holds base (UpdateMirror to base first), else
|
||||
// from remote. A head that does not merge cleanly is an answer, not an error: the files in conflict, the
|
||||
// merge undone and the workspace left at base. A head already in base answers a Merge equal to Base and no changed
|
||||
// paths. An error is that the merge could not be tried: a base or commit that is not a full sha, no base, a workspace
|
||||
// not at commit, or a fetch or git command that failed. remote and the options are those of FetchCommit; the runner's
|
||||
@@ -67,12 +68,20 @@ func MergeInto(ctx context.Context, run forgekey.Runner, dir, remote, base, comm
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
fetch := []string{"fetch", "--no-tags", "origin", base}
|
||||
if strings.TrimSpace(shallow) == "true" {
|
||||
fetch = []string{"fetch", "--no-tags", "--unshallow", "origin", base}
|
||||
fetchFrom := func(source string) error {
|
||||
fetch := []string{"fetch", "--no-tags", source, base}
|
||||
if strings.TrimSpace(shallow) == "true" {
|
||||
fetch = []string{"fetch", "--no-tags", "--unshallow", source, base}
|
||||
}
|
||||
_, err := git(fetch...)
|
||||
return err
|
||||
}
|
||||
if _, err := git(fetch...); err != nil {
|
||||
return res, fmt.Errorf("the trunk commit %s: %w", base, err)
|
||||
// With a mirror brought to the trunk commit, the history is deepened from it, a local fetch (issue 1921, try speed
|
||||
// S6); a mirror that cannot answer leaves it to the forge, as before.
|
||||
if o.mirror == "" || fetchFrom(o.mirror) != nil {
|
||||
if err := fetchFrom("origin"); err != nil {
|
||||
return res, fmt.Errorf("the trunk commit %s: %w", base, err)
|
||||
}
|
||||
}
|
||||
if _, err := git("checkout", "-q", "--detach", base); err != nil {
|
||||
return res, fmt.Errorf("the trunk commit %s cannot be checked out: %w", base, err)
|
||||
|
||||
@@ -170,3 +170,33 @@ func TestMergeIntoAHeadAlreadyInTheTrunkChangesNothing(t *testing.T) {
|
||||
t.Errorf("result = %+v, %v", res, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 1921/S6: with a mirror brought to the head and to the trunk commit, the merge asks the forge for nothing: it succeeds
|
||||
// with the forge gone.
|
||||
func TestMergeIntoWithAMirrorAtTheTrunkNeedsNoForge(t *testing.T) {
|
||||
r := newMergeRig(t)
|
||||
head := r.head(map[string]string{"b.txt": "head\n"})
|
||||
base := r.advance(map[string]string{"a.txt": "one\ntwo\nthree\nfour\n"})
|
||||
mirror := filepath.Join(t.TempDir(), "mirror.git")
|
||||
if err := os.MkdirAll(mirror, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, c := range []string{head, base} {
|
||||
if err := UpdateMirror(context.Background(), forgekey.ExecRunner, mirror, r.remote, c, "", AllowFileRemote()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err := FetchCommit(context.Background(), forgekey.ExecRunner, r.ws, r.remote, head, "", AllowFileRemote(), WithMirror(mirror)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.RemoveAll(r.bare); err != nil { // the forge is gone
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err := MergeInto(context.Background(), forgekey.ExecRunner, r.ws, r.remote, base, head, AllowFileRemote(), WithMirror(mirror))
|
||||
if err != nil {
|
||||
t.Fatalf("the merge asked the forge: %v", err)
|
||||
}
|
||||
if len(res.Merge) != 40 || !reflect.DeepEqual(res.Changed, []string{"b.txt"}) {
|
||||
t.Errorf("result = %+v", res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,3 +72,39 @@ func TestMergeIntoRunsTheCheckMergesCommands(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1921/S6: with a mirror that holds the trunk commit, the merge deepens the workspace from the mirror, a local fetch,
|
||||
// and asks the forge nothing; a mirror that cannot answer falls back to the forge.
|
||||
func TestMergeIntoWithAMirrorFetchesTheTrunkFromTheMirror(t *testing.T) {
|
||||
base := strings.Repeat("b", 40)
|
||||
mirror := t.TempDir()
|
||||
answer := func(failMirror bool) *fakeGit {
|
||||
return &fakeGit{rule: func(l string) forgekey.Ran {
|
||||
switch {
|
||||
case strings.HasSuffix(l, "rev-parse HEAD"):
|
||||
return forgekey.Ran{Stdout: sha + "\n"}
|
||||
case strings.Contains(l, "--is-shallow-repository"):
|
||||
return forgekey.Ran{Stdout: "true\n"}
|
||||
case failMirror && strings.Contains(l, " fetch ") && strings.Contains(l, mirror):
|
||||
return forgekey.Ran{Status: 128, Stderr: "fatal: not our ref"}
|
||||
}
|
||||
return forgekey.Ran{}
|
||||
}}
|
||||
}
|
||||
f := answer(false)
|
||||
dir := t.TempDir()
|
||||
if _, err := MergeInto(context.Background(), f.run, dir, "ssh://mesh-forge/o/r.git", base, sha, WithMirror(mirror)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
all := strings.Join(f.calls, "\n")
|
||||
if !strings.Contains(all, "fetch --no-tags --unshallow "+mirror+" "+base) || strings.Contains(all, "--unshallow origin") {
|
||||
t.Errorf("the trunk was not fetched from the mirror alone:\n%s", all)
|
||||
}
|
||||
g := answer(true)
|
||||
if _, err := MergeInto(context.Background(), g.run, t.TempDir(), "ssh://mesh-forge/o/r.git", base, sha, WithMirror(mirror)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if all := strings.Join(g.calls, "\n"); !strings.Contains(all, "fetch --no-tags --unshallow origin "+base) {
|
||||
t.Errorf("a mirror that could not answer did not fall back to the forge:\n%s", all)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user