roll.go: add a flag to send the CL to the gardener

Bug: dawn:1940
Change-Id: I720d8f6507a18bfd50dcaa1ae8db34b566c7c469
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/147542
Auto-Submit: Austin Eng <enga@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/tools/src/cmd/cts/roll/roll.go b/tools/src/cmd/cts/roll/roll.go
index 4b8db34..b5523bd 100644
--- a/tools/src/cmd/cts/roll/roll.go
+++ b/tools/src/cmd/cts/roll/roll.go
@@ -17,9 +17,12 @@
 import (
 	"bytes"
 	"context"
+	"encoding/json"
 	"flag"
 	"fmt"
+	"io/ioutil"
 	"log"
+	"net/http"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -65,14 +68,15 @@
 )
 
 type rollerFlags struct {
-	gitPath  string
-	npmPath  string
-	nodePath string
-	auth     authcli.Flags
-	cacheDir string
-	force    bool // Create a new roll, even if CTS is up to date
-	rebuild  bool // Rebuild the expectations file from scratch
-	preserve bool // If false, abandon past roll changes
+	gitPath        string
+	npmPath        string
+	nodePath       string
+	auth           authcli.Flags
+	cacheDir       string
+	force          bool // Create a new roll, even if CTS is up to date
+	rebuild        bool // Rebuild the expectations file from scratch
+	preserve       bool // If false, abandon past roll changes
+	sendToGardener bool // If true, automatically send to the gardener for review
 }
 
 type cmd struct {
@@ -99,6 +103,7 @@
 	flag.BoolVar(&c.flags.force, "force", false, "create a new roll, even if CTS is up to date")
 	flag.BoolVar(&c.flags.rebuild, "rebuild", false, "rebuild the expectation file from scratch")
 	flag.BoolVar(&c.flags.preserve, "preserve", false, "do not abandon existing rolls")
+	flag.BoolVar(&c.flags.sendToGardener, "send-to-gardener", false, "send the CL to the WebGPU gardener for review")
 
 	return nil, nil
 }
@@ -396,7 +401,33 @@
 		}
 	}
 
-	if err := r.gerrit.SetReadyForReview(changeID, "CTS roll succeeded"); err != nil {
+	reviewer := ""
+	if r.flags.sendToGardener {
+		resp, err := http.Get("https://chrome-ops-rotation-proxy.appspot.com/current/grotation:webgpu-gardener")
+		if err != nil {
+			return err
+		}
+		defer resp.Body.Close()
+
+		jsonResponse, err := ioutil.ReadAll(resp.Body)
+		if err != nil {
+			return err
+		}
+
+		type StructuredJsonResponse struct {
+			Emails []string
+		}
+		var jsonRes StructuredJsonResponse
+		if err := json.Unmarshal(jsonResponse, &jsonRes); err != nil {
+			return err
+		}
+		if len(jsonRes.Emails) < 1 {
+			return fmt.Errorf("Expected at least one email in JSON response %s", jsonRes)
+		}
+		reviewer = jsonRes.Emails[0]
+	}
+
+	if err := r.gerrit.SetReadyForReview(changeID, "CTS roll succeeded", reviewer); err != nil {
 		return fmt.Errorf("failed to mark change as ready for review: %v", err)
 	}
 
diff --git a/tools/src/gerrit/gerrit.go b/tools/src/gerrit/gerrit.go
index 2777530..066b156 100644
--- a/tools/src/gerrit/gerrit.go
+++ b/tools/src/gerrit/gerrit.go
@@ -19,6 +19,7 @@
 	"context"
 	"flag"
 	"fmt"
+	"log"
 	"net/url"
 	"strconv"
 	"strings"
@@ -311,12 +312,24 @@
 }
 
 // SetReadyForReview marks the change as ready for review.
-func (g *Gerrit) SetReadyForReview(changeID, message string) error {
+func (g *Gerrit) SetReadyForReview(changeID, message, reviewer string) error {
 	resp, err := g.client.Changes.SetReadyForReview(changeID, &gerrit.ReadyForReviewInput{
 		Message: message,
 	})
 	if err != nil && resp.StatusCode != 409 { // 409: already ready
 		return err
 	}
+	if reviewer != "" {
+		// Log the reviewer and then replace with enga@.
+		// TODO(crbug.com/dawn/1940): Use the actual reviewer when the bot is stable.
+		log.Printf("Got reviewer %s", reviewer)
+		reviewer = "enga@chromium.org"
+		_, resp, err = g.client.Changes.AddReviewer(changeID, &gerrit.ReviewerInput{
+			Reviewer: reviewer,
+		})
+		if err != nil && resp.StatusCode != 409 { // 409: already ready
+			return err
+		}
+	}
 	return nil
 }