Add loginURL configuration option.

This is explained in the README. The fundamental function of this
configuration option is to give users the ability to click on the
login error and be taken to a page that may be able to help them
get the session cookies they need in order to make successful
requests.

Some login systems may instead provide a header as part of the
response that we should use instead. We could build out support
for this as we need it. For now, this gives users something
without having to get too complicated.

Bug: monorail:6459
Change-Id: I67940063f8c9d5a2bac45e994dc764b5b52acb6d
Reviewed-on: https://chromium-review.googlesource.com/c/infra/gerrit-plugins/chumpdetector/+/1842489
Reviewed-by: Andy Perelson <ajp@chromium.org>
Reviewed-by: Aaron Gable <agable@chromium.org>
diff --git a/README.md b/README.md
index 8e2991f..9ea4c09 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@
 
 ```
 [project "some-interesting-project"]
+  loginURL = https://login.appspot.com/?next=chromium-status
   viewURL = https://chromium-status.appspot.com/
   statusURL = https://chromium-status.appspot.com/current?format=json
   withCredentials = false
@@ -34,6 +35,14 @@
 
 The project name doesn't matter, it can be anything you'd like
 
+### loginURL
+
+If `withCredentials` is true and a request for status fails, the system
+assumes that a login is required and has not occurred. In that case the status
+message will change to "Login required. Click here to login." The text will be
+a link that points to the value of `loginURL`.  If `loginURL` is not set then
+the message will just be `RequestError: Login required.` with no link.
+
 ### viewURL
 
 This should be the URL to your status app. This is used to provide a link
diff --git a/src/main/java/com/googlesource/chromium/plugins/chumpdetector/GetProjectChumpConfig.java b/src/main/java/com/googlesource/chromium/plugins/chumpdetector/GetProjectChumpConfig.java
index a1e69f6..4973879 100644
--- a/src/main/java/com/googlesource/chromium/plugins/chumpdetector/GetProjectChumpConfig.java
+++ b/src/main/java/com/googlesource/chromium/plugins/chumpdetector/GetProjectChumpConfig.java
@@ -53,6 +53,7 @@
     r.treeName = name;
     r.disabled = cfg.getBoolean(PROJECT, name, "disabled", false);
     r.viewURL = cfg.getString(PROJECT, name, "viewURL");
+    r.loginURL = cfg.getString(PROJECT, name, "loginURL");
     r.statusURL = cfg.getString(PROJECT, name, "statusURL");
     r.withCredentials = cfg.getBoolean(PROJECT, name, "withCredentials", false);
     r.enforceCommitQueue = cfg.getBoolean(PROJECT, name, "enforceCommitQueue", false);
@@ -71,6 +72,9 @@
     @SerializedName("viewURL")
     String viewURL;
 
+    @SerializedName("loginURL")
+    String loginURL;
+
     @SerializedName("statusURL")
     String statusURL;
 
diff --git a/src/main/resources/static/chumpdetector.html b/src/main/resources/static/chumpdetector.html
index 9823813..494f44e 100644
--- a/src/main/resources/static/chumpdetector.html
+++ b/src/main/resources/static/chumpdetector.html
@@ -136,7 +136,8 @@
      */
     const getStatusFetcher = function(config) {
       if (!fetchers.hasOwnProperty(config.treeName)) {
-        fetchers[config.treeName] = new StatusFetcher(config.viewURL,
+        fetchers[config.treeName] = new StatusFetcher(config.loginURL,
+                                                      config.viewURL,
                                                       config.statusURL,
                                                       config.withCredentials);
       }
@@ -260,11 +261,13 @@
   <script>
     /**
      * Periodically fetches tree status for some project.
+     * @param {string} loginURL URL to link to when login failures occur.
      * @param {string} viewURL URL to link to normally for users to navigate to
      * @param {string} statusURL URL to fetch status from
      * @param {boolean} withCredentials True to send cookies with the request
      */
-    const StatusFetcher = function(viewURL, statusURL, withCredentials) {
+    const StatusFetcher = function(loginURL, viewURL, statusURL, withCredentials) {
+      this.loginURL = loginURL;
       this.viewURL = viewURL;
       this.statusURL = statusURL;
       this.withCredentials = withCredentials;
@@ -354,7 +357,17 @@
         let message;
         let url;
         if (this.withCredentials) {
-          message = 'Login required';
+          if (this.loginURL) {
+            message = 'Login required. Click here to login.';
+            url = this.loginURL;
+          } else {
+            message = 'Login required.';
+            console.warn("chumpdetector failed to request " + this.viewURL +
+              " and got status " + request.status + ". You may want to add " +
+              "a loginURL to your chumpdetector configuration to give your " +
+              "users a link they can click on to take them to a login page. " +
+              "See https://chromium.googlesource.com/infra/gerrit-plugins/chumpdetector/#loginurl.");
+          }
         } else {
           url = this.viewURL;
           message = (request.statusText ||