cmd/gopherbot: don't remove NeedsDecision from Go 2 issues

CL 180925 was a bit too aggressive. We've since cleaned up its changes
(see patchset 1 of this CL).

Updates golang/go#31788

Change-Id: I96b8fa4f5cbc158869e4f607aa69be130c0eda75
Reviewed-on: https://go-review.googlesource.com/c/build/+/193120
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/cmd/gopherbot/Dockerfile b/cmd/gopherbot/Dockerfile
index d87cbf5..9ccca8a 100644
--- a/cmd/gopherbot/Dockerfile
+++ b/cmd/gopherbot/Dockerfile
@@ -27,6 +27,7 @@
 RUN go install golang.org/x/build/gerrit
 COPY maintner /go/src/golang.org/x/build/maintner
 COPY cmd/pubsubhelper /go/src/golang.org/x/build/cmd/pubsubhelper
+COPY internal/foreach /go/src/golang.org/x/build/internal/foreach
 RUN go install golang.org/x/build/maintner/maintnerd/apipb
 RUN go install golang.org/x/build/maintner/godata
 
diff --git a/cmd/gopherbot/gopherbot.go b/cmd/gopherbot/gopherbot.go
index 00ba122..5794048 100644
--- a/cmd/gopherbot/gopherbot.go
+++ b/cmd/gopherbot/gopherbot.go
@@ -756,8 +756,8 @@
 			}
 		}
 
-		// Remove NeedsDecision label if exists:
-		if gi.HasLabel("NeedsDecision") && !gopherbotRemovedLabel(gi, "NeedsDecision") {
+		// Remove NeedsDecision label if exists, but not for Go 2 issues:
+		if !isGo2Issue(gi) && gi.HasLabel("NeedsDecision") && !gopherbotRemovedLabel(gi, "NeedsDecision") {
 			if err := b.removeLabel(ctx, gi, "NeedsDecision"); err != nil {
 				return err
 			}
@@ -786,6 +786,18 @@
 	return hasRemoved
 }
 
+// isGo2Issue reports whether gi seems like it's about Go 2, based on either labels or its title.
+func isGo2Issue(gi *maintner.GitHubIssue) bool {
+	if gi.HasLabel("Go2") {
+		return true
+	}
+	if !strings.Contains(gi.Title, "2") {
+		// Common case.
+		return false
+	}
+	return strings.Contains(gi.Title, "Go 2") || strings.Contains(gi.Title, "go2") || strings.Contains(gi.Title, "Go2")
+}
+
 func (b *gopherbot) setSubrepoMilestones(ctx context.Context) error {
 	return b.gorepo.ForeachIssue(func(gi *maintner.GitHubIssue) error {
 		if gi.Closed || gi.PullRequest || !gi.Milestone.IsNone() || gi.HasEvent("demilestoned") || gi.HasEvent("milestoned") {