git-codereview: ensure blank line after subject

Fixes golang/go#9522

Change-Id: Ic06feda22711fe320a789957620af98f38f1df8f
Reviewed-on: https://go-review.googlesource.com/4130
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/git-codereview/hook.go b/git-codereview/hook.go
index 63163d6..ea01dcf 100644
--- a/git-codereview/hook.go
+++ b/git-codereview/hook.go
@@ -136,6 +136,14 @@
 		dief("empty commit message")
 	}
 
+	// Insert a blank line between first line and subsequent lines if not present.
+	eol := bytes.IndexByte(data, '\n')
+	if eol != -1 && len(data) > eol+1 && data[eol+1] != '\n' {
+		data = append(data, 0)
+		copy(data[eol+1:], data[eol:])
+		data[eol+1] = '\n'
+	}
+
 	// Add Change-Id to commit message if not present.
 	edited := false
 	if !bytes.Contains(data, []byte("\nChange-Id: ")) {
diff --git a/git-codereview/hook_test.go b/git-codereview/hook_test.go
index b7656a2..1b7bb92 100644
--- a/git-codereview/hook_test.go
+++ b/git-codereview/hook_test.go
@@ -46,6 +46,40 @@
 	if got := testStderr.String(); got != want {
 		t.Fatalf("unexpected output:\ngot: %q\nwant: %q", got, want)
 	}
+
+	// Check that hook inserts a blank line after the first line as needed.
+	rewrites := []struct {
+		in   string
+		want string
+	}{
+		{in: "all: gofmt", want: "all: gofmt"},
+		{in: "all: gofmt\n", want: "all: gofmt\n"},
+		{in: "all: gofmt\nahhh", want: "all: gofmt\n\nahhh"},
+		{in: "all: gofmt\n\nahhh", want: "all: gofmt\n\nahhh"},
+		{in: "all: gofmt\n\n\nahhh", want: "all: gofmt\n\n\nahhh"},
+	}
+	for _, tt := range rewrites {
+		write(t, gt.client+"/in.txt", tt.in)
+		testMain(t, "hook-invoke", "commit-msg", gt.client+"/in.txt")
+		write(t, gt.client+"/want.txt", tt.want)
+		testMain(t, "hook-invoke", "commit-msg", gt.client+"/want.txt")
+		got, err := ioutil.ReadFile(gt.client + "/in.txt")
+		if err != nil {
+			t.Fatal(err)
+		}
+		want, err := ioutil.ReadFile(gt.client + "/want.txt")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// pull off the Change-Id that got appended
+		const lenChangeId = len("\n\nChange-Id: I") + 2*20
+		got = got[:len(got)-lenChangeId]
+		want = want[:len(want)-lenChangeId]
+		if !bytes.Equal(got, want) {
+			t.Fatalf("failed to rewrite:\n%s\n\ngot:\n\n%s\n\nwant:\n\n%s\n", tt.in, got, want)
+		}
+	}
 }
 
 func TestHookCommitMsgBranchPrefix(t *testing.T) {