Rerun: Get non-green source build for flaky builders

We have builders that we don't expect to be green ever but we still
want to rerun them.

Bug: 39904
Change-Id: I0ee717a34f38cf67a977d5b7412b414049598af7
diff --git a/recipe_modules/buildbucket_util/api.py b/recipe_modules/buildbucket_util/api.py
index 9b1855a..a4bb48c 100644
--- a/recipe_modules/buildbucket_util/api.py
+++ b/recipe_modules/buildbucket_util/api.py
@@ -88,7 +88,7 @@
               failure_message,
           )
 
-  def last_green_build(self, project, bucket, builder, fields=None):
+  def last_build(self, project, bucket, builder, fields=None, status=None):
     """Returns the build proto for a builder's most recent successful build.
 
     Returns None if no successful builds could be found.
@@ -99,12 +99,15 @@
       builder (str): BuildBucket builder.
       fields (seq of str): BuildBucket Build proto message fields to include in
           the result. If None, defaults to api.buildbucket.DEFAULT_FIELDS.
+      status (common_pb2.Status enum member): If set, will return the
+          last build with this status.
     """
     predicate = rpc_pb2.BuildPredicate()
     predicate.builder.project = project
     predicate.builder.bucket = bucket
     predicate.builder.builder = builder
-    predicate.status = common_pb2.SUCCESS
+    if status is not None:
+      predicate.status = status
 
     fields = fields or self.m.buildbucket.DEFAULT_FIELDS
     builds = self.m.buildbucket.search(predicate, limit=1, fields=fields)
diff --git a/recipe_modules/buildbucket_util/examples/full.expected/basic_tryjob.json b/recipe_modules/buildbucket_util/examples/full.expected/basic_tryjob.json
index ae484fb..40c1ee0 100644
--- a/recipe_modules/buildbucket_util/examples/full.expected/basic_tryjob.json
+++ b/recipe_modules/buildbucket_util/examples/full.expected/basic_tryjob.json
@@ -144,7 +144,7 @@
     ],
     "infra_step": true,
     "name": "buildbucket.search",
-    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {}, \"status\": \"SUCCESS\"}}}]}",
+    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {}, \"status\": \"FAILURE\"}}}]}",
     "~followup_annotations": [
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
@@ -188,7 +188,7 @@
       "@@@STEP_LOG_LINE@request@        \"pageSize\": 1, @@@",
       "@@@STEP_LOG_LINE@request@        \"predicate\": {@@@",
       "@@@STEP_LOG_LINE@request@          \"builder\": {}, @@@",
-      "@@@STEP_LOG_LINE@request@          \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@request@          \"status\": \"FAILURE\"@@@",
       "@@@STEP_LOG_LINE@request@        }@@@",
       "@@@STEP_LOG_LINE@request@      }@@@",
       "@@@STEP_LOG_LINE@request@    }@@@",
diff --git a/recipe_modules/buildbucket_util/examples/full.expected/led_job.json b/recipe_modules/buildbucket_util/examples/full.expected/led_job.json
index 74683af..4fbe8c9 100644
--- a/recipe_modules/buildbucket_util/examples/full.expected/led_job.json
+++ b/recipe_modules/buildbucket_util/examples/full.expected/led_job.json
@@ -144,7 +144,7 @@
     ],
     "infra_step": true,
     "name": "buildbucket.search",
-    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {}, \"status\": \"SUCCESS\"}}}]}",
+    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {}, \"status\": \"FAILURE\"}}}]}",
     "~followup_annotations": [
       "@@@STEP_LOG_LINE@json.output@{}@@@",
       "@@@STEP_LOG_END@json.output@@@",
@@ -156,7 +156,7 @@
       "@@@STEP_LOG_LINE@request@        \"pageSize\": 1, @@@",
       "@@@STEP_LOG_LINE@request@        \"predicate\": {@@@",
       "@@@STEP_LOG_LINE@request@          \"builder\": {}, @@@",
-      "@@@STEP_LOG_LINE@request@          \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@request@          \"status\": \"FAILURE\"@@@",
       "@@@STEP_LOG_LINE@request@        }@@@",
       "@@@STEP_LOG_LINE@request@      }@@@",
       "@@@STEP_LOG_LINE@request@    }@@@",
diff --git a/recipe_modules/buildbucket_util/examples/full.py b/recipe_modules/buildbucket_util/examples/full.py
index c8eab61..71848eb 100644
--- a/recipe_modules/buildbucket_util/examples/full.py
+++ b/recipe_modules/buildbucket_util/examples/full.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
+
 DEPS = [
     'fuchsia/buildbucket_util',
     'fuchsia/status_check',
@@ -25,10 +27,11 @@
       raise_on_failure=True,
   )
   build = builds.values()[0]
-  api.buildbucket_util.last_green_build(
+  api.buildbucket_util.last_build(
       build.builder.project,
       build.builder.bucket,
       build.builder.builder,
+      status=common_pb2.FAILURE,
   )
 
   # pylint: disable=pointless-statement
diff --git a/recipes/fuchsia/rerun.expected/no_search_results.json b/recipes/fuchsia/rerun.expected/no_search_results.json
index af2f8c4..afaab3b 100644
--- a/recipes/fuchsia/rerun.expected/no_search_results.json
+++ b/recipes/fuchsia/rerun.expected/no_search_results.json
@@ -8,7 +8,7 @@
     ],
     "infra_step": true,
     "name": "buildbucket.search",
-    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {\"bucket\": \"source-bucket\", \"builder\": \"source-builder\", \"project\": \"project\"}, \"status\": \"SUCCESS\"}}}]}",
+    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {\"bucket\": \"source-bucket\", \"builder\": \"source-builder-flaky\", \"project\": \"project\"}}}}]}",
     "~followup_annotations": [
       "@@@STEP_LOG_LINE@json.output@{}@@@",
       "@@@STEP_LOG_END@json.output@@@",
@@ -21,10 +21,9 @@
       "@@@STEP_LOG_LINE@request@        \"predicate\": {@@@",
       "@@@STEP_LOG_LINE@request@          \"builder\": {@@@",
       "@@@STEP_LOG_LINE@request@            \"bucket\": \"source-bucket\", @@@",
-      "@@@STEP_LOG_LINE@request@            \"builder\": \"source-builder\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"builder\": \"source-builder-flaky\", @@@",
       "@@@STEP_LOG_LINE@request@            \"project\": \"project\"@@@",
-      "@@@STEP_LOG_LINE@request@          }, @@@",
-      "@@@STEP_LOG_LINE@request@          \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
       "@@@STEP_LOG_LINE@request@        }@@@",
       "@@@STEP_LOG_LINE@request@      }@@@",
       "@@@STEP_LOG_LINE@request@    }@@@",
@@ -35,7 +34,7 @@
   },
   {
     "failure": {
-      "humanReason": "Failed to find source_build for builder project/source-bucket/source-builder"
+      "humanReason": "Failed to find source_build for builder project/source-bucket/source-builder-flaky"
     },
     "name": "$result"
   }
diff --git a/recipes/fuchsia/rerun.expected/success.json b/recipes/fuchsia/rerun.expected/success.json
index baaf957..f3a52eb 100644
--- a/recipes/fuchsia/rerun.expected/success.json
+++ b/recipes/fuchsia/rerun.expected/success.json
@@ -8,7 +8,7 @@
     ],
     "infra_step": true,
     "name": "buildbucket.search",
-    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {\"bucket\": \"source-bucket\", \"builder\": \"source-builder\", \"project\": \"project\"}, \"status\": \"SUCCESS\"}}}]}",
+    "stdin": "{\"requests\": [{\"searchBuilds\": {\"fields\": \"builds.*.builder,builds.*.createTime,builds.*.createdBy,builds.*.critical,builds.*.endTime,builds.*.id,builds.*.input,builds.*.number,builds.*.output,builds.*.startTime,builds.*.status,builds.*.updateTime\", \"pageSize\": 1, \"predicate\": {\"builder\": {\"bucket\": \"source-bucket\", \"builder\": \"source-builder-flaky\", \"project\": \"project\"}}}}]}",
     "~followup_annotations": [
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
@@ -58,10 +58,9 @@
       "@@@STEP_LOG_LINE@request@        \"predicate\": {@@@",
       "@@@STEP_LOG_LINE@request@          \"builder\": {@@@",
       "@@@STEP_LOG_LINE@request@            \"bucket\": \"source-bucket\", @@@",
-      "@@@STEP_LOG_LINE@request@            \"builder\": \"source-builder\", @@@",
+      "@@@STEP_LOG_LINE@request@            \"builder\": \"source-builder-flaky\", @@@",
       "@@@STEP_LOG_LINE@request@            \"project\": \"project\"@@@",
-      "@@@STEP_LOG_LINE@request@          }, @@@",
-      "@@@STEP_LOG_LINE@request@          \"status\": \"SUCCESS\"@@@",
+      "@@@STEP_LOG_LINE@request@          }@@@",
       "@@@STEP_LOG_LINE@request@        }@@@",
       "@@@STEP_LOG_LINE@request@      }@@@",
       "@@@STEP_LOG_LINE@request@    }@@@",
@@ -80,7 +79,7 @@
     ],
     "infra_step": true,
     "name": "buildbucket.schedule",
-    "stdin": "{\"requests\": [{\"scheduleBuild\": {\"builder\": {\"bucket\": \"rerun\", \"builder\": \"source-builder\", \"project\": \"project\"}, \"experimental\": \"NO\", \"fields\": \"builder,createTime,createdBy,critical,endTime,id,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"chromium.googlesource.com\", \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"project\": \"project\", \"ref\": \"refs/heads/master\"}, \"priority\": 30, \"properties\": {\"child_build_id\": 123}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", \"tags\": [{\"key\": \"user_agent\", \"value\": \"recipe\"}]}}]}",
+    "stdin": "{\"requests\": [{\"scheduleBuild\": {\"builder\": {\"bucket\": \"rerun\", \"builder\": \"source-builder-flaky\", \"project\": \"project\"}, \"experimental\": \"NO\", \"fields\": \"builder,createTime,createdBy,critical,endTime,id,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"chromium.googlesource.com\", \"id\": \"2d72510e447ab60a9728aeea2362d8be2cbd7789\", \"project\": \"project\", \"ref\": \"refs/heads/master\"}, \"priority\": 30, \"properties\": {\"child_build_id\": 123}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", \"tags\": [{\"key\": \"user_agent\", \"value\": \"recipe\"}]}}]}",
     "~followup_annotations": [
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"responses\": [@@@",
@@ -88,7 +87,7 @@
       "@@@STEP_LOG_LINE@json.output@      \"scheduleBuild\": {@@@",
       "@@@STEP_LOG_LINE@json.output@        \"builder\": {@@@",
       "@@@STEP_LOG_LINE@json.output@          \"bucket\": \"rerun\", @@@",
-      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"source-builder\", @@@",
+      "@@@STEP_LOG_LINE@json.output@          \"builder\": \"source-builder-flaky\", @@@",
       "@@@STEP_LOG_LINE@json.output@          \"project\": \"project\"@@@",
       "@@@STEP_LOG_LINE@json.output@        }, @@@",
       "@@@STEP_LOG_LINE@json.output@        \"id\": \"8922054662172514000\"@@@",
@@ -103,7 +102,7 @@
       "@@@STEP_LOG_LINE@request@      \"scheduleBuild\": {@@@",
       "@@@STEP_LOG_LINE@request@        \"builder\": {@@@",
       "@@@STEP_LOG_LINE@request@          \"bucket\": \"rerun\", @@@",
-      "@@@STEP_LOG_LINE@request@          \"builder\": \"source-builder\", @@@",
+      "@@@STEP_LOG_LINE@request@          \"builder\": \"source-builder-flaky\", @@@",
       "@@@STEP_LOG_LINE@request@          \"project\": \"project\"@@@",
       "@@@STEP_LOG_LINE@request@        }, @@@",
       "@@@STEP_LOG_LINE@request@        \"experimental\": \"NO\", @@@",
diff --git a/recipes/fuchsia/rerun.py b/recipes/fuchsia/rerun.py
index 62d1c83..7a799c6 100644
--- a/recipes/fuchsia/rerun.py
+++ b/recipes/fuchsia/rerun.py
@@ -41,9 +41,15 @@
 
 def RunSteps(api, source_bucket, source_builder):
   my_build = api.buildbucket.build
-  source_build = api.buildbucket_util.last_green_build(my_build.builder.project,
-                                                       source_bucket,
-                                                       source_builder)
+  last_build_status = common_pb2.SUCCESS
+  # Flaky builders are rarely successful, so we take any build.
+  if source_builder.endswith('-flaky'):
+    last_build_status = None
+  source_build = api.buildbucket_util.last_build(
+      my_build.builder.project,
+      source_bucket,
+      source_builder,
+      status=last_build_status)
   if not source_build:
     raise api.step.InfraFailure(
         'Failed to find source_build for builder %s/%s/%s' %
@@ -64,7 +70,7 @@
 
 def GenTests(api):
   properties = api.properties(
-      source_bucket='source-bucket', source_builder='source-builder')
+      source_bucket='source-bucket', source_builder='source-builder-flaky')
 
   yield (api.status_check.test('no_search_results', status='infra_failure') +
          properties + api.buildbucket.ci_build())
diff --git a/recipes/recipes.py b/recipes/recipes.py
index 5cba3e3..90ea66e 100644
--- a/recipes/recipes.py
+++ b/recipes/recipes.py
@@ -170,8 +170,12 @@
   project, bucket, builder = builder.split('/')
   # "infra.recipe" is not returned by default, so we have to specify it.
   required_fields = {'infra.recipe'}.union(api.buildbucket.DEFAULT_FIELDS)
-  build = api.buildbucket_util.last_green_build(
-      project, bucket, builder, fields=required_fields)
+  build = api.buildbucket_util.last_build(
+      project,
+      bucket,
+      builder,
+      fields=required_fields,
+      status=common_pb2.SUCCESS)
   if not build:
     return None