e2e/mrforkweb_test.go

69d8aa4ff9115d6ca1116e09a232e7a6416e4645
gitbay/e2e/mrforkweb_test.go history · blame · raw

83 lines · 3339 bytes

 1package e2e
 2
 3import (
 4	"net/url"
 5	"os"
 6	"path/filepath"
 7	"strings"
 8	"testing"
 9)
10
11// A contributor without write access proposes a change from the browser:
12// the source picker offers the branches of a fork they can push to, and
13// the merge request opens against the parent (#168).
14func TestMRFromForkWeb(t *testing.T) {
15	inst := startInstanceWith(t, "[web]\nmode = \"accounts\"\n")
16	aliceKey := inst.newKey(t, "alice")
17	bobKey := inst.newKey(t, "bob")
18	eveKey := inst.newKey(t, "eve")
19	inst.admin(t, "admin", "user", "create", "alice", "--key", aliceKey+".pub")
20	inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
21	inst.admin(t, "admin", "user", "create", "eve", "--key", eveKey+".pub")
22
23	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
24		t.Fatalf("repo create: %s", errOut)
25	}
26	env := inst.gitEnv(aliceKey)
27	work := t.TempDir()
28	mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
29	dir := filepath.Join(work, "w")
30	os.WriteFile(filepath.Join(dir, "f.txt"), []byte("x\n"), 0o644)
31	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
32	mustGit(t, dir, env, "add", ".")
33	mustGit(t, dir, env, "commit", "-q", "-m", "base")
34	mustGit(t, dir, env, "push", "-q", "origin", "main")
35
36	// bob forks and pushes a branch to the fork.
37	if _, errOut, code := inst.ssh(t, bobKey, "", "repo", "fork", "alice/app"); code != 0 {
38		t.Fatalf("fork: %s", errOut)
39	}
40	benv := inst.gitEnv(bobKey)
41	bwork := t.TempDir()
42	mustGit(t, bwork, benv, "clone", inst.sshURL("bob/app"), "w")
43	bdir := filepath.Join(bwork, "w")
44	mustGit(t, bdir, benv, "checkout", "-q", "-b", "feat")
45	os.WriteFile(filepath.Join(bdir, "f.txt"), []byte("y\n"), 0o644)
46	mustGit(t, bdir, benv, "add", ".")
47	mustGit(t, bdir, benv, "commit", "-q", "-m", "change")
48	mustGit(t, bdir, benv, "push", "-q", "origin", "feat")
49
50	// bob's fork branch is offered on alice's repo; eve, who can push to
51	// neither, sees only the target's own branches.
52	bob := inst.login(t, bobKey)
53	eve := inst.login(t, eveKey)
54	base := inst.base() + "/alice/app"
55	_, page := browserGet(t, bob, base+"/mrs/new")
56	if !strings.Contains(page, `value="bob/app:feat"`) {
57		t.Fatalf("fork branch not offered:\n%s", page)
58	}
59	if _, p := browserGet(t, eve, base+"/mrs/new"); strings.Contains(p, "bob/app:feat") {
60		t.Fatal("a fork branch is offered to someone who cannot push to it")
61	}
62
63	// Opening it lands on the merge request, with the fork as its source.
64	if status, _ := browserPost(t, bob, base+"/mrs/new", url.Values{
65		"source": {"bob/app:feat"}, "target": {"main"}, "title": {"change"}}); status != 200 {
66		t.Fatal("mr create from a fork failed")
67	}
68	out, _, _ := inst.ssh(t, bobKey, "", "mr", "show", "alice/app", "1", "--json")
69	if !strings.Contains(out, `"source":"bob/app:feat"`) {
70		t.Fatalf("merge request source is not the fork:\n%s", out)
71	}
72
73	// A branch of a repository that is not a fork of the target is
74	// refused by the command, whatever the form posts.
75	if _, errOut, code := inst.ssh(t, eveKey, "", "repo", "create", "eve/other"); code != 0 {
76		t.Fatalf("repo create: %s", errOut)
77	}
78	_, body := browserPost(t, eve, base+"/mrs/new", url.Values{
79		"source": {"eve/other:main"}, "target": {"main"}, "title": {"sneak"}})
80	if !strings.Contains(body, `class="error"`) {
81		t.Errorf("a non-fork source was accepted:\n%s", body)
82	}
83}