git-codereview: add -hashtag flag to the mail command

It is now possible to mail a CL with any number of hashtags.

Fixes golang/go#26149

Change-Id: I231826f95ec357bd448de12a9a5aa30e581c3bb3
Reviewed-on: https://go-review.googlesource.com/121798
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/git-codereview/mail.go b/git-codereview/mail.go
index 3bea462..c96caff 100644
--- a/git-codereview/mail.go
+++ b/git-codereview/mail.go
@@ -16,18 +16,20 @@
 
 func cmdMail(args []string) {
 	var (
-		diff   = flags.Bool("diff", false, "show change commit diff and don't upload or mail")
-		force  = flags.Bool("f", false, "mail even if there are staged changes")
-		topic  = flags.String("topic", "", "set Gerrit topic")
-		trybot = flags.Bool("trybot", false, "run trybots on the uploaded CLs")
-		rList  = new(stringList) // installed below
-		ccList = new(stringList) // installed below
+		diff    = flags.Bool("diff", false, "show change commit diff and don't upload or mail")
+		force   = flags.Bool("f", false, "mail even if there are staged changes")
+		topic   = flags.String("topic", "", "set Gerrit topic")
+		trybot  = flags.Bool("trybot", false, "run trybots on the uploaded CLs")
+		rList   = new(stringList) // installed below
+		ccList  = new(stringList) // installed below
+		tagList = new(stringList) // installed below
 	)
 	flags.Var(rList, "r", "comma-separated list of reviewers")
 	flags.Var(ccList, "cc", "comma-separated list of people to CC:")
+	flags.Var(tagList, "hashtag", "comma-separated list of tags to set")
 
 	flags.Usage = func() {
-		fmt.Fprintf(stderr(), "Usage: %s mail %s [-r reviewer,...] [-cc mail,...] [-topic topic] [-trybot] [commit]\n", os.Args[0], globalFlags)
+		fmt.Fprintf(stderr(), "Usage: %s mail %s [-r reviewer,...] [-cc mail,...] [-topic topic] [-trybot] [-hashtag tag,...] [commit]\n", os.Args[0], globalFlags)
 	}
 	flags.Parse(args)
 	if len(flags.Args()) > 1 {
@@ -110,6 +112,15 @@
 		refSpec += mailList(start, "cc", string(*ccList))
 		start = ","
 	}
+	if *tagList != "" {
+		for _, tag := range strings.Split(string(*tagList), ",") {
+			if tag == "" {
+				dief("hashtag may not contain empty tags")
+			}
+			refSpec += start + "hashtag=" + tag
+			start = ","
+		}
+	}
 	if *topic != "" {
 		// There's no way to escape the topic, but the only
 		// ambiguous character is ',' (though other characters
diff --git a/git-codereview/mail_test.go b/git-codereview/mail_test.go
index b1b5201..3a63c33 100644
--- a/git-codereview/mail_test.go
+++ b/git-codereview/mail_test.go
@@ -244,6 +244,34 @@
 		"git tag -f work.mailed "+h)
 }
 
+func TestMailHashtag(t *testing.T) {
+	gt := newGitTest(t)
+	defer gt.done()
+	gt.work(t)
+
+	h := CurrentBranch().Pending()[0].ShortHash
+
+	// fake auth information to avoid Gerrit error
+	auth.host = "gerrit.fake"
+	auth.user = "not-a-user"
+	defer func() {
+		auth.host = ""
+		auth.user = ""
+	}()
+
+	testMain(t, "mail", "-hashtag", "test1,test2")
+	testRan(t,
+		"git push -q origin HEAD:refs/for/master%hashtag=test1,hashtag=test2",
+		"git tag -f work.mailed "+h)
+	testMain(t, "mail", "-hashtag", "")
+	testRan(t,
+		"git push -q origin HEAD:refs/for/master",
+		"git tag -f work.mailed "+h)
+
+	testMainDied(t, "mail", "-hashtag", "test1,,test3")
+	testPrintedStderr(t, "hashtag may not contain empty tags")
+}
+
 func TestMailEmpty(t *testing.T) {
 	gt := newGitTest(t)
 	defer gt.done()
diff --git a/git-codereview/review.go b/git-codereview/review.go
index 2e67396..a60e548 100644
--- a/git-codereview/review.go
+++ b/git-codereview/review.go
@@ -83,7 +83,7 @@
 		Every other operation except help also does this,
 		if they are not already installed.
 
-	mail [-f] [-r reviewer,...] [-cc mail,...] [-trybot] [commit]
+	mail [-f] [-r reviewer,...] [-cc mail,...] [-trybot] [-hashtag tag,...] [commit]
 		Upload change commit to the code review server and send mail
 		requesting a code review.
 		If there are multiple commits on this branch, upload commits
@@ -94,6 +94,7 @@
 		Multiple addresses are given as a comma-separated list.
 		If -trybot is specified, the trybots are run on the changes,
 		if permitted.
+		The -hashtag flag applies hashtags to the code review.
 
 	mail -diff
 		Show the changes but do not send mail or upload.