cmd/gopherbot: accept if maintner metadata is ahead of Gerrit API

The purpose of function onLatestCL is to check that maintner data
isn't behind Gerrit's data (as determined by talking to the Gerrit
REST API directly). However, there are some meta commits that the
Gerrit REST API doesn't return a corresponding message to, so
sometimes maintner data is ahead of "latest Gerrit message".

Since ahead is not _behind_, make onLatestCL report positively in
such situations by checking all cl.Metas, not just the latest one.
Do so in reverse order as an optimization (if there's a match, it's
most likely near the end of cl.Metas slice).

An example of such a meta commit is one that updates an uploaded
patch set and sets the Reviewer field:

	$ git show fc20e3671f7b1ff889d5f947b11d7fda0b608751
	commit fc20e3671f7b1ff889d5f947b11d7fda0b608751 (meta/35/111335/meta)
	Author: Gerrit User 14805 <14805@62eb7196-b449-3ce5-99f1-c037f21e1705>
	Date:   Mon Feb 11 17:49:09 2019 +0000

	    Update patch set 6

	    Patch-set: 6
	    Reviewer: Gerrit User 14805 <14805@62eb7196-b449-3ce5-99f1-c037f21e1705>

It has no corresponding message with same ID in the output from a Gerrit
REST API call at
https://go-review.googlesource.com/changes/111335/detail?o=MESSAGES,
nor does it show up visually in the Gerrit UI at
https://go-review.googlesource.com/c/crypto/+/111335.

Before this change (with fix in CL 161977):

	2019/02/11 15:02:33 Reloaded data from log *maintner.netMutSource.
	2019/02/11 15:02:34 https://golang.org/cl/111335 -- remove wait-author; reply from Andreas Auernhammer <...@mail.de>
	2019/02/11 15:02:35 onLatestCL: maintner metadata for CL 111335 is behind; skipping action for now.

After this change:

	2019/02/11 15:06:46 Reloaded data from log *maintner.netMutSource.
	2019/02/11 15:06:46 https://golang.org/cl/111335 -- remove wait-author; reply from Andreas Auernhammer <...@mail.de>
	2019/02/11 15:06:46 [dry run] would remove hashtag 'wait-author' from CL 111335

Updates golang/go#30172

Change-Id: I1575ccffbf8c3edb337f55bf1bf2c96a4a04bbdd
Reviewed-on: https://go-review.googlesource.com/c/161901
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/gopherbot/gopherbot.go b/cmd/gopherbot/gopherbot.go
index 4093817..a4fffd5 100644
--- a/cmd/gopherbot/gopherbot.go
+++ b/cmd/gopherbot/gopherbot.go
@@ -1179,8 +1179,8 @@
 	})
 }
 
-// onLatestCL checks whether cl's metadata is in sync with Gerrit's
-// upstream data and, if so, returns f(). If it's out of sync, it does
+// onLatestCL checks whether cl's metadata is up to date with Gerrit's
+// upstream data and, if so, returns f(). If it's out of date, it does
 // nothing more and returns nil.
 func (b *gopherbot) onLatestCL(ctx context.Context, cl *maintner.GerritCL, f func() error) error {
 	ci, err := b.gerrit.GetChangeDetail(ctx, fmt.Sprint(cl.Number), gerrit.QueryChangesOpt{Fields: []string{"MESSAGES"}})
@@ -1191,8 +1191,15 @@
 		log.Printf("onLatestCL: CL %d has no messages. Odd. Ignoring.", cl.Number)
 		return nil
 	}
-	if ci.Messages[len(ci.Messages)-1].ID == cl.Meta.Commit.Hash.String() {
-		return f()
+	latestGerritID := ci.Messages[len(ci.Messages)-1].ID
+	// Check all metas and not just the latest, because there are some meta commits
+	// that don't have a corresponding message in the Gerrit REST API response.
+	for i := len(cl.Metas) - 1; i >= 0; i-- {
+		metaHash := cl.Metas[i].Commit.Hash.String()
+		if metaHash == latestGerritID {
+			// latestGerritID is contained by maintner metadata for this CL, so run f().
+			return f()
+		}
 	}
 	log.Printf("onLatestCL: maintner metadata for CL %d is behind; skipping action for now.", cl.Number)
 	return nil