Replace comments column with failing step names

I don't find the comments column on the LLVM status page very useful:
- For test failures, it gets truncated so it only shows the number of
  passes.
- For build failures it doesn't tell you which stage it was which
  failed.

Instead, we can show the names of the stages which are failing,
color-coded to match buildbot's conventions. I don't think this loses
any useful information compared to the comment field, and it makes it
easier to quickly see which types of failure are occuring.

Change-Id: I9a5cec73948ea6f6edc2998ef64a14704bc2c94b
diff --git a/monitor/bot-status.py b/monitor/bot-status.py
index 39fcb82..40630e5 100755
--- a/monitor/bot-status.py
+++ b/monitor/bot-status.py
@@ -59,6 +59,27 @@
                                             width=GIT_SHORT_LEN)
 
 
+# Map from buildbot status codes we want to treat as errors to the color they
+# should be shown in. The codes are documented at
+# https://docs.buildbot.net/latest/developer/results.html#build-result-codes,
+# and these colors match the suggested ones there.
+RESULT_COLORS = {
+  2: 'red',    # Error
+  4: 'purple', # Exception
+  5: 'purple', # Retry
+  6: 'pink',   # Cancelled
+}
+
+def get_bot_failing_steps(session, base_url, buildid):
+  contents, err = wget(session, "{}/api/v2/builds/{}/steps"
+                                .format(base_url, buildid))
+  if err:
+    return ""
+  for step in contents["steps"]:
+    if step["results"] in RESULT_COLORS.keys():
+      yield (step["name"], step["results"])
+
+
 # Get the status of a individual bot BOT.  Returns a dict with the
 # information.
 def get_bot_status(session, bot, base_url, builder_url, build_url):
@@ -80,7 +101,6 @@
       delta = int(build['complete_at']) - int(build['started_at'])
       status['time'] = str(timedelta(seconds=delta))
       if build['state_string'] != 'build successful':
-        status['comments'] = build['state_string']
         status['fail'] = True
 
         try:
@@ -90,6 +110,8 @@
         status['changes'] = get_bot_failure_changes(session, base_url,
                                                     build['buildid'],
                                                     prev_buildid)
+        status['steps'] = list(get_bot_failing_steps(session, base_url,
+                                                     build['buildid']))
       else:
         status['fail'] = False
       break
@@ -141,7 +163,7 @@
       temp.write("<tr><td colspan=5>&nbsp;</td><tr>\n")
       temp.write("<tr><th colspan=5>{}</td><tr>\n".format(builder['name']))
       temp.write("<tr><th>Buildbot</th><th>Status</th><th>Time</th>"
-                 "<th>Build #</th><th>Commits</th><th>Comments</th></tr>\n")
+                 "<th>Build #</th><th>Commits</th><th>Failing steps</th></tr>\n")
       for bot in builder['bots']:
         temp.write("<tr>\n")
         status = bot_cache["{}/{}".format(base_url, bot['name'])]
@@ -164,8 +186,11 @@
           temp.write("  <td>{}</td>\n".format(status['changes']))
         else:
           temp.write(empty_cell)
-        if status['fail']:
-          temp.write("  <td>{:.30}</td>\n".format(status['comments']))
+        if 'steps' in status and status['steps']:
+          def render_step(name, result):
+            return "<font color='{}'>{}</font>".format(RESULT_COLORS[result], name)
+          step_list = ', '.join(render_step(name, result) for name, result in status['steps'])
+          temp.write("  <td style=\"text-align:center\">{}</td>\n".format(step_list))
         else:
           temp.write(empty_cell)
         temp.write("</tr>\n")