cl: hide DoNotReview changes

The actual spelling of DoNotReview that has meaning
to the dashboard includes spaces, but I can't put that
string in the commit message because it makes the
CL uncommitable. :-)

Add dnr flag so people can ask for them.

If people do ask, show DoNotReview as the reviewer.
Similarly, show Closed as the reviewer for closed CLs.

Change-Id: Ibe758bbb5f5f03fcb5035e7cb068c6d8d0b6baa4
Reviewed-on: https://go-review.googlesource.com/11260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
diff --git a/cmd/cl/cl.go b/cmd/cl/cl.go
index 2e8d4ea..11021ac 100644
--- a/cmd/cl/cl.go
+++ b/cmd/cl/cl.go
@@ -7,7 +7,7 @@
 
 Usage:
 
-	cl [-closed] [-json] [-r] [-url] [query ...]
+	cl [-closed] [-dnr] [-json] [-r] [-url] [query ...]
 
 CL searches Gerrit for CLs matching the query and then
 prints a line for each CL that is waiting for review
@@ -32,9 +32,13 @@
 If the CL has been reviewed by the reviewer,
 the reviewer column shows the current score.
 
-By default, CL omits closed reviews, those with an R=close reply
+By default, CL omits closed CLs, those with an R=close reply
 and no subsequent upload of a new patch set.
-If the -closed flag is specified, CL adds closed reviews to the output.
+If the -closed flag is specified, CL adds closed CLs to the output.
+
+By default, CL omits CLs containing ``DO NOT REVIEW'' in the
+latest patch's commit message.
+If the -dnr flag is specified, CL includes those CLs in its output.
 
 If the -r flag is specified, CL shows only CLs that need review,
 not those waiting for the author. In this mode, the
@@ -66,6 +70,7 @@
 		NeedsReview        bool           // CL is waiting for reviewer (otherwise author)
 		NeedsReviewChanged time.Time      // time NeedsReview last changed
 		Closed             bool           // CL closed with R=close
+		DoNotReview        bool           // CL marked DO NOT REVIEW
 		Issues             []int          // issues referenced by commit message
 		Scores             map[string]int // current review scores
 		Files              []string       // files changed in CL
@@ -91,7 +96,8 @@
 )
 
 var (
-	flagClosed      = flag.Bool("closed", false, "print closed CLs")
+	flagClosed      = flag.Bool("closed", false, "include CLs that are closed or DO NOT REVIEW")
+	flagDoNotReview = flag.Bool("dnr", false, "print only CLs in need of review")
 	flagNeedsReview = flag.Bool("r", false, "print only CLs in need of review")
 	flagJSON        = flag.Bool("json", false, "print CLs in JSON format")
 	flagURL         = flag.Bool("url", false, "print full URLs for CLs")
@@ -145,7 +151,7 @@
 	cls := []*CL{} // non-nil for json
 	for _, ci := range cis {
 		cl := parseCL(ci)
-		if *flagNeedsReview && !cl.NeedsReview || !*flagClosed && cl.Closed {
+		if *flagNeedsReview && !cl.NeedsReview || !*flagClosed && (cl.Closed || cl.DoNotReview) {
 			continue
 		}
 		cls = append(cls, cl)
@@ -223,6 +229,7 @@
 	NeedsReview        bool           // CL is waiting for reviewer (otherwise author)
 	NeedsReviewChanged time.Time      // time NeedsReview last changed
 	Closed             bool           // CL closed with R=close
+	DoNotReview        bool           // CL marked DO NOT REVIEW
 	Issues             []int          // issues referenced by commit message
 	Scores             map[string]int // current review scores
 	Files              []string       // files changed in CL
@@ -433,6 +440,9 @@
 	// We shouldn't see these, because the query always
 	// contains -message:do-not-review, but check anyway.
 	if _, ok := ci.Labels["Do-Not-Review"]; ok {
+		cl.Reviewer = "DoNotReview"
+		cl.ReviewerEmail = ""
+		cl.DoNotReview = true
 		cl.NeedsReview = false
 	}