e2e/commitrefs_test.go

32a5f76e5b270097b63a5bba9a43557cf50ad63d
gitbay/e2e/commitrefs_test.go history · blame · raw

138 lines · 6385 bytes

  1package e2e
  2
  3import (
  4	"os"
  5	"path/filepath"
  6	"strings"
  7	"testing"
  8)
  9
 10func TestCommitMessageIssueActions(t *testing.T) {
 11	t.Parallel()
 12	inst := startInstance(t)
 13	aliceKey := inst.newKey(t, "alice")
 14	inst.admin(t, "admin", "user", "create", "alice",
 15		"--key", aliceKey+".pub", "--email", "alice@example.test", "--verified")
 16
 17	if _, errOut, code := inst.ssh(t, aliceKey, "", "repo", "create", "alice/app"); code != 0 {
 18		t.Fatalf("repo create: %s", errOut)
 19	}
 20	work := t.TempDir()
 21	env := inst.gitEnv(aliceKey)
 22	mustGit(t, work, env, "clone", inst.sshURL("alice/app"), "w")
 23	dir := filepath.Join(work, "w")
 24	os.WriteFile(filepath.Join(dir, "a.txt"), []byte("a\n"), 0o644)
 25	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
 26	mustGit(t, dir, env, "add", ".")
 27	mustGit(t, dir, env, "commit", "-q", "-m", "base")
 28	mustGit(t, dir, env, "push", "-q", "origin", "main")
 29	for _, title := range []string{"'one'", "'two'", "'three'"} {
 30		if _, _, code := inst.ssh(t, aliceKey, "", "issue", "create", "alice/app", "--title", title); code != 0 {
 31			t.Fatal("issue create failed")
 32		}
 33	}
 34
 35	// A closing keyword on the default branch closes the issue with a
 36	// comment; a bare reference (and a nonexistent #99) only comments.
 37	os.WriteFile(filepath.Join(dir, "b.txt"), []byte("b\n"), 0o644)
 38	aliceEnv := append(append([]string{}, env...),
 39		"GIT_AUTHOR_NAME=Alice", "GIT_AUTHOR_EMAIL=alice@example.test")
 40	mustGit(t, dir, env, "add", ".")
 41	mustGit(t, dir, aliceEnv, "commit", "-q", "-m", "repair the widget\n\nFixes #1. Related to #2 but not #99.")
 42	mustGit(t, dir, env, "push", "-q", "origin", "main")
 43
 44	out, _, _ := inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "1", "--json")
 45	if !strings.Contains(out, `"state":"closed"`) || !strings.Contains(out, "closed by ") {
 46		t.Fatalf("issue 1 not closed by commit: %s", out)
 47	}
 48	// The entry is a system message with a linked sha, not a user comment.
 49	if !strings.Contains(out, `"author":"system"`) || !strings.Contains(out, "](/alice/app/commit/") {
 50		t.Fatalf("close entry not a linked system message: %s", out)
 51	}
 52	if status, body := inst.get(t, "/alice/app/issues/1"); status != 200 ||
 53		!strings.Contains(body, `class="syscomment"`) || !strings.Contains(body, `/alice/app/commit/`) {
 54		t.Fatalf("web system message: %d", status)
 55	}
 56	out, _, _ = inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "2", "--json")
 57	if !strings.Contains(out, `"state":"open"`) || !strings.Contains(out, "referenced in commit") ||
 58		!strings.Contains(out, "repair the widget") {
 59		t.Fatalf("issue 2 not referenced: %s", out)
 60	}
 61	// The reference names who wrote the commit, and links them when the
 62	// author email is verified on an account here.
 63	if !strings.Contains(out, "by [alice](/alice)") {
 64		t.Fatalf("reference does not attribute the author: %s", out)
 65	}
 66	if status, body := inst.get(t, "/alice/app/issues/2"); status != 200 ||
 67		!strings.Contains(body, `href="/alice"`) {
 68		t.Fatalf("web reference does not link the author: %d\n%s", status, body)
 69	}
 70
 71	// Commits on a feature branch do nothing until they land on the
 72	// default branch via a merge — then the merge path acts exactly once.
 73	mustGit(t, dir, env, "checkout", "-q", "-b", "feat")
 74	os.WriteFile(filepath.Join(dir, "c.txt"), []byte("c\n"), 0o644)
 75	mustGit(t, dir, env, "add", ".")
 76	mustGit(t, dir, env, "commit", "-q", "-m", "finish the gadget\n\nCloses #3")
 77	mustGit(t, dir, env, "push", "-q", "origin", "feat")
 78	out, _, _ = inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "3", "--json")
 79	if !strings.Contains(out, `"state":"open"`) {
 80		t.Fatalf("branch push acted early: %s", out)
 81	}
 82	if _, _, code := inst.ssh(t, aliceKey, "", "mr", "create", "alice/app",
 83		"--source", "feat", "--target", "main", "--title", "'gadget'"); code != 0 {
 84		t.Fatal("mr create failed")
 85	}
 86	if _, errOut, code := inst.ssh(t, aliceKey, "", "mr", "merge", "alice/app", "1"); code != 0 {
 87		t.Fatalf("merge: %s", errOut)
 88	}
 89	out, _, _ = inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "3", "--json")
 90	if !strings.Contains(out, `"state":"closed"`) || !strings.Contains(out, "closed by ") {
 91		t.Fatalf("merge did not close issue 3: %s", out)
 92	}
 93	// This one was authored by an address nobody has verified, so it names
 94	// git's author without inventing a profile link for them.
 95	if !strings.Contains(out, "closed by t in commit") || strings.Contains(out, "closed by [t]") {
 96		t.Fatalf("unresolved author should stay plain text: %s", out)
 97	}
 98	if strings.Count(out, "closed by ") != 1 {
 99		t.Fatalf("duplicate close comments: %s", out)
100	}
101
102	// Pushing more commits does not re-act on already-processed shas.
103	os.WriteFile(filepath.Join(dir, "d.txt"), []byte("d\n"), 0o644)
104	mustGit(t, dir, env, "checkout", "-q", "main")
105	mustGit(t, dir, env, "pull", "-q", "origin", "main")
106	mustGit(t, dir, env, "add", ".")
107	mustGit(t, dir, env, "commit", "-q", "-m", "unrelated")
108	mustGit(t, dir, env, "push", "-q", "origin", "main")
109	out, _, _ = inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "2", "--json")
110	if strings.Count(out, "referenced in commit") != 1 {
111		t.Fatalf("reference duplicated: %s", out)
112	}
113
114	// A commit written by repo commit-file (the web editor's path) lands
115	// on the default branch without receive-pack or a merge, and acts
116	// the same (#210). On another branch it does nothing.
117	if _, errOut, code := inst.ssh(t, aliceKey, "e\n", "repo", "commit-file", "alice/app", "e.txt",
118		"--ref", "feat", "--message", "'Closes #2 on a branch'", "--file", "-"); code != 0 {
119		t.Fatalf("commit-file on branch: %s", errOut)
120	}
121	out, _, _ = inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "2", "--json")
122	if !strings.Contains(out, `"state":"open"`) {
123		t.Fatalf("commit-file on a branch acted: %s", out)
124	}
125	if _, errOut, code := inst.ssh(t, aliceKey, "e\n", "repo", "commit-file", "alice/app", "e.txt",
126		"--ref", "main", "--message", "'Closes #2 from the editor'", "--file", "-"); code != 0 {
127		t.Fatalf("commit-file: %s", errOut)
128	}
129	out, _, _ = inst.ssh(t, aliceKey, "", "issue", "show", "alice/app", "2", "--json")
130	if !strings.Contains(out, `"state":"closed"`) ||
131		!strings.Contains(out, "closed by [alice](/alice) in commit") ||
132		!strings.Contains(out, ": Closes #2 from the editor") {
133		t.Fatalf("commit-file did not close issue 2: %s", out)
134	}
135	if strings.Count(out, "referenced in commit") != 1 {
136		t.Fatalf("commit-file re-acted on earlier commits: %s", out)
137	}
138}