[dart] Start additional bisection build for different failure reason
Change-Id: Id042fcafe0222a43caa7195b425b76d8e421711f
Reviewed-on: https://dart-review.googlesource.com/c/recipes/+/158320
Commit-Queue: Karl Klose <karlklose@google.com>
Reviewed-by: Alexander Thomas <athom@google.com>
diff --git a/README.recipes.md b/README.recipes.md
index 1a000bd..6fe7d6e 100644
--- a/README.recipes.md
+++ b/README.recipes.md
@@ -35,7 +35,9 @@
— **def [is\_bisecting](/recipe_modules/bisect_build/api.py#20)(self):**
-— **def [schedule](/recipe_modules/bisect_build/api.py#23)(self, repo_url, reason, is_experimental=False):**
+  **@property**<br>— **def [is\_enabled](/recipe_modules/bisect_build/api.py#23)(self):**
+
+— **def [schedule](/recipe_modules/bisect_build/api.py#27)(self, repo_url, reason, is_experimental=False):**
### *recipe_modules* / [dart](/recipe_modules/dart)
[DEPS](/recipe_modules/dart/__init__.py#5): [build/goma][build/recipe_modules/goma], [bisect\_build](#recipe_modules-bisect_build), [depot\_tools/bot\_update][depot_tools/recipe_modules/bot_update], [depot\_tools/depot\_tools][depot_tools/recipe_modules/depot_tools], [depot\_tools/gclient][depot_tools/recipe_modules/gclient], [depot\_tools/git][depot_tools/recipe_modules/git], [depot\_tools/gsutil][depot_tools/recipe_modules/gsutil], [depot\_tools/tryserver][depot_tools/recipe_modules/tryserver], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/isolated][recipe_engine/recipe_modules/isolated], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/python][recipe_engine/recipe_modules/python], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime], [recipe\_engine/service\_account][recipe_engine/recipe_modules/service_account], [recipe\_engine/step][recipe_engine/recipe_modules/step], [recipe\_engine/swarming][recipe_engine/recipe_modules/swarming]
@@ -127,41 +129,39 @@
— **def [RunSteps](/recipes/dart/external.py#13)(api):**
### *recipes* / [dart/flutter\_engine](/recipes/dart/flutter_engine.py)
-[DEPS](/recipes/dart/flutter_engine.py#11): [build/goma][build/recipe_modules/goma], [bisect\_build](#recipe_modules-bisect_build), [dart](#recipe_modules-dart), [depot\_tools/bot\_update][depot_tools/recipe_modules/bot_update], [depot\_tools/depot\_tools][depot_tools/recipe_modules/depot_tools], [depot\_tools/gclient][depot_tools/recipe_modules/gclient], [depot\_tools/gitiles][depot_tools/recipe_modules/gitiles], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/python][recipe_engine/recipe_modules/python], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime], [recipe\_engine/step][recipe_engine/recipe_modules/step]
+[DEPS](/recipes/dart/flutter_engine.py#17): [build/goma][build/recipe_modules/goma], [bisect\_build](#recipe_modules-bisect_build), [dart](#recipe_modules-dart), [depot\_tools/bot\_update][depot_tools/recipe_modules/bot_update], [depot\_tools/depot\_tools][depot_tools/recipe_modules/depot_tools], [depot\_tools/gclient][depot_tools/recipe_modules/gclient], [depot\_tools/gitiles][depot_tools/recipe_modules/gitiles], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/python][recipe_engine/recipe_modules/python], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime], [recipe\_engine/step][recipe_engine/recipe_modules/step]
-— **def [AnalyzeDartUI](/recipes/dart/flutter_engine.py#73)(api, checkout_dir):**
+— **def [AnalyzeDartUI](/recipes/dart/flutter_engine.py#75)(api, checkout_dir):**
-— **def [Build](/recipes/dart/flutter_engine.py#56)(api, checkout_dir, config, \*targets):**
+— **def [Build](/recipes/dart/flutter_engine.py#58)(api, checkout_dir, config, \*targets):**
-— **def [BuildAndTest](/recipes/dart/flutter_engine.py#356)(api, start_dir, checkout_dir, flutter_rev):**
+— **def [BuildAndTest](/recipes/dart/flutter_engine.py#358)(api, start_dir, checkout_dir, flutter_rev):**
-— **def [BuildLinux](/recipes/dart/flutter_engine.py#106)(api, checkout_dir):**
+— **def [BuildLinux](/recipes/dart/flutter_engine.py#108)(api, checkout_dir):**
-— **def [BuildLinuxAndroidArm](/recipes/dart/flutter_engine.py#90)(api, checkout_dir):**
+— **def [BuildLinuxAndroidArm](/recipes/dart/flutter_engine.py#92)(api, checkout_dir):**
-— **def [BuildLinuxAndroidx86](/recipes/dart/flutter_engine.py#83)(api, checkout_dir):**
+— **def [BuildLinuxAndroidx86](/recipes/dart/flutter_engine.py#85)(api, checkout_dir):**
-— **def [CopyArtifacts](/recipes/dart/flutter_engine.py#182)(api, engine_src, cached_dest, file_paths):**
+— **def [CopyArtifacts](/recipes/dart/flutter_engine.py#184)(api, engine_src, cached_dest, file_paths):**
-— **def [GetCheckout](/recipes/dart/flutter_engine.py#133)(api):**
+— **def [GetCheckout](/recipes/dart/flutter_engine.py#135)(api):**
-— **def [KillTasks](/recipes/dart/flutter_engine.py#48)(api, checkout_dir, ok_ret='any'):**
+— **def [KillTasks](/recipes/dart/flutter_engine.py#50)(api, checkout_dir, ok_ret='any'):**
Kills leftover tasks from previous runs or steps.
-— **def [RunGN](/recipes/dart/flutter_engine.py#65)(api, checkout_dir, \*args):**
+— **def [RunGN](/recipes/dart/flutter_engine.py#67)(api, checkout_dir, \*args):**
-— **def [RunSteps](/recipes/dart/flutter_engine.py#326)(api):**
+— **def [RunSteps](/recipes/dart/flutter_engine.py#328)(api):**
-— **def [TestEngine](/recipes/dart/flutter_engine.py#78)(api, checkout_dir):**
+— **def [TestEngine](/recipes/dart/flutter_engine.py#80)(api, checkout_dir):**
-— **def [TestFlutter](/recipes/dart/flutter_engine.py#270)(api, start_dir, just_built_dart_sdk):**
+— **def [TestFlutter](/recipes/dart/flutter_engine.py#272)(api, start_dir, just_built_dart_sdk):**
-— **def [TestObservatory](/recipes/dart/flutter_engine.py#122)(api, checkout_dir):**
+— **def [TestObservatory](/recipes/dart/flutter_engine.py#124)(api, checkout_dir):**
-— **def [UpdateCachedEngineArtifacts](/recipes/dart/flutter_engine.py#195)(api, flutter, engine_src):**
-
-— **def [bisection\_is\_enabled](/recipes/dart/flutter_engine.py#44)(api):**
+— **def [UpdateCachedEngineArtifacts](/recipes/dart/flutter_engine.py#197)(api, flutter, engine_src):**
### *recipes* / [dart/forward\_branch](/recipes/dart/forward_branch.py)
[DEPS](/recipes/dart/forward_branch.py#8): [dart](#recipe_modules-dart), [depot\_tools/git][depot_tools/recipe_modules/git], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/step][recipe_engine/recipe_modules/step]
@@ -179,13 +179,9 @@
— **def [RunSteps](/recipes/dart/linearize.py#24)(api):**
### *recipes* / [dart/neo](/recipes/dart/neo.py)
-[DEPS](/recipes/dart/neo.py#16): [bisect\_build](#recipe_modules-bisect_build), [dart](#recipe_modules-dart), [depot\_tools/gitiles][depot_tools/recipe_modules/gitiles], [depot\_tools/osx\_sdk][depot_tools/recipe_modules/osx_sdk], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/step][recipe_engine/recipe_modules/step]
+[DEPS](/recipes/dart/neo.py#23): [bisect\_build](#recipe_modules-bisect_build), [dart](#recipe_modules-dart), [depot\_tools/gitiles][depot_tools/recipe_modules/gitiles], [depot\_tools/osx\_sdk][depot_tools/recipe_modules/osx_sdk], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/step][recipe_engine/recipe_modules/step]
-— **def [RunSteps](/recipes/dart/neo.py#84)(api, properties):**
-
-— **def [bisection\_is\_enabled](/recipes/dart/neo.py#64)(api):**
-
-— **def [schedule\_bisection](/recipes/dart/neo.py#68)(api, failure=None):**
+— **def [RunSteps](/recipes/dart/neo.py#94)(api, properties):**
### *recipes* / [dart/package\_co19](/recipes/dart/package_co19.py)
[DEPS](/recipes/dart/package_co19.py#8): [depot\_tools/git][depot_tools/recipe_modules/git], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/step][recipe_engine/recipe_modules/step]
diff --git a/recipe_modules/bisect_build/api.py b/recipe_modules/bisect_build/api.py
index 384dce2..f2da98a 100644
--- a/recipe_modules/bisect_build/api.py
+++ b/recipe_modules/bisect_build/api.py
@@ -20,6 +20,10 @@
def is_bisecting(self):
return 'bisect_reason' in self.m.properties
+ @property
+ def is_enabled(self): # pragma: no cover
+ return self.m.properties.get('bisection_enabled', False)
+
def schedule(self, repo_url, reason, is_experimental=False):
if self.is_bisecting():
base_build = self.get_base_build()
diff --git a/recipes/dart/flutter_engine.py b/recipes/dart/flutter_engine.py
index 8e237ed..b7426d9 100644
--- a/recipes/dart/flutter_engine.py
+++ b/recipes/dart/flutter_engine.py
@@ -5,8 +5,14 @@
import json
from recipe_engine import recipe_api
-from recipe_engine.post_process import (DoesNotRunRE, DropExpectation, Filter,
- MustRun, StatusSuccess, StatusException)
+from recipe_engine.post_process import (
+ DoesNotRunRE,
+ DropExpectation,
+ Filter,
+ MustRun,
+ StatusSuccess,
+ StatusException,
+)
DEPS = [
'bisect_build',
@@ -41,10 +47,6 @@
LINEARIZED_REPO_URL = DART_GERRIT + LINEARIZED_REPO
-def bisection_is_enabled(api):
- return api.properties.get('bisection_enabled', False)
-
-
def KillTasks(api, checkout_dir, ok_ret='any'):
"""Kills leftover tasks from previous runs or steps."""
dart_sdk_dir = checkout_dir.join('third_party', 'dart')
@@ -341,7 +343,7 @@
BuildAndTest(api, start_dir, checkout_dir, flutter_rev)
except recipe_api.StepFailure as failure:
- if bisection_is_enabled(api) and api.buildbucket.gitiles_commit.id:
+ if api.bisect_build.is_enabled and api.buildbucket.gitiles_commit.id:
api.bisect_build.schedule(LINEARIZED_REPO_URL, failure.reason)
raise
finally:
diff --git a/recipes/dart/neo.expected/failing-build-starts-bisection.json b/recipes/dart/neo.expected/failing-test-step-starts-bisection.json
similarity index 99%
rename from recipes/dart/neo.expected/failing-build-starts-bisection.json
rename to recipes/dart/neo.expected/failing-test-step-starts-bisection.json
index 02d573a..f4d6676 100644
--- a/recipes/dart/neo.expected/failing-build-starts-bisection.json
+++ b/recipes/dart/neo.expected/failing-test-step-starts-bisection.json
@@ -1839,7 +1839,7 @@
],
"infra_step": true,
"name": "schedule bisect (f4d35da881f8fd329a4d3e01dd78b66a502d5c49)",
- "stdin": "{\"requests\": [{\"scheduleBuild\": {\"builder\": {\"bucket\": \"ci\", \"builder\": \"dart2js-win-debug-x64-firefox\", \"project\": \"dart\"}, \"experimental\": \"NO\", \"fields\": \"builder,createTime,createdBy,critical,endTime,id,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"dart.googlesource.com\", \"id\": \"f4d35da881f8fd329a4d3e01dd78b66a502d5c49\", \"project\": \"sdk\", \"ref\": \"refs/heads/master\"}, \"priority\": 30, \"properties\": {\"bisect_base_build\": 4711, \"bisect_newer\": [\"8331c527346abecfe0ad081df241512bb4b7df50\"], \"bisect_older\": [], \"bisect_reason\": \"FAILURE\", \"bisection_enabled\": true}, \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", \"tags\": [{\"key\": \"user_agent\", \"value\": \"recipe\"}]}}]}",
+ "stdin": "{\"requests\": [{\"scheduleBuild\": {\"builder\": {\"bucket\": \"ci\", \"builder\": \"dart2js-win-debug-x64-firefox\", \"project\": \"dart\"}, \"experimental\": \"NO\", \"fields\": \"builder,createTime,createdBy,critical,endTime,id,input,number,output,startTime,status,updateTime\", \"gitilesCommit\": {\"host\": \"dart.googlesource.com\", \"id\": \"f4d35da881f8fd329a4d3e01dd78b66a502d5c49\", \"project\": \"sdk\", \"ref\": \"refs/heads/master\"}, \"priority\": 30, \"properties\": {\"bisect_base_build\": 4711, \"bisect_newer\": [\"8331c527346abecfe0ad081df241512bb4b7df50\"], \"bisect_older\": [], \"bisect_reason\": \"1 out of 1 aggregated steps failed: Step('test results') (retcode: 1)\", \"bisection_enabled\": true}, \"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\": [@@@",
@@ -1880,7 +1880,7 @@
"@@@STEP_LOG_LINE@request@ \"8331c527346abecfe0ad081df241512bb4b7df50\"@@@",
"@@@STEP_LOG_LINE@request@ ], @@@",
"@@@STEP_LOG_LINE@request@ \"bisect_older\": [], @@@",
- "@@@STEP_LOG_LINE@request@ \"bisect_reason\": \"FAILURE\", @@@",
+ "@@@STEP_LOG_LINE@request@ \"bisect_reason\": \"1 out of 1 aggregated steps failed: Step('test results') (retcode: 1)\", @@@",
"@@@STEP_LOG_LINE@request@ \"bisection_enabled\": true@@@",
"@@@STEP_LOG_LINE@request@ }, @@@",
"@@@STEP_LOG_LINE@request@ \"requestId\": \"8945511751514863184-00000000-0000-0000-0000-000000001337\", @@@",
diff --git a/recipes/dart/neo.py b/recipes/dart/neo.py
index 4e0958c..132947e 100644
--- a/recipes/dart/neo.py
+++ b/recipes/dart/neo.py
@@ -5,7 +5,14 @@
from google.protobuf import struct_pb2, json_format
from recipe_engine import recipe_api
-from recipe_engine.post_process import DoesNotRunRE, MustRun, StatusException, StatusFailure, StatusSuccess
+from recipe_engine.post_process import (
+ DoesNotRunRE,
+ DropExpectation,
+ MustRun,
+ StatusException,
+ StatusFailure,
+ StatusSuccess,
+)
from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
@@ -61,23 +68,26 @@
}
-def bisection_is_enabled(api):
- return api.properties.get('bisection_enabled', False)
+def _is_infra_failure(api, failure):
+ return (isinstance(failure, api.step.InfraFailure) or
+ api.dart.has_infra_failure(failure))
-def schedule_bisection(api, failure=None):
- if not bisection_is_enabled(api):
+def _compute_failure_reason(api, failure):
+ assert not failure or not _is_infra_failure(api, failure)
+ return failure.reason if failure else api.bisect_build.REASON_SUCCESS
+
+
+def _schedule_bisection(api, failure=None):
+ if not api.bisect_build.is_enabled:
# This builder is not configured to use bisection.
return
- if (isinstance(failure, api.step.InfraFailure) or
- api.dart.has_infra_failure(failure)):
+ if _is_infra_failure(api, failure):
# TODO(karlklose): fan out on infra failures during bisection and consider
# starting a bisection for some kinds of infra failures.
return
elif api.bisect_build.is_bisecting() or failure:
- # TODO(karlklose): distinguish between test failures and build failures (and
- # start additional bisection runs for different failures).
- reason = "FAILURE" if failure else api.bisect_build.REASON_SUCCESS
+ reason = _compute_failure_reason(api, failure)
api.bisect_build.schedule("https://dart.googlesource.com/sdk", reason)
@@ -89,9 +99,9 @@
with api.osx_sdk('mac'), api.context(env=env):
_run_steps_impl(api, properties)
except api.step.StepFailure as failure:
- schedule_bisection(api, failure)
+ _schedule_bisection(api, failure)
raise
- schedule_bisection(api)
+ _schedule_bisection(api)
def _run_steps_impl(api, properties):
@@ -184,7 +194,7 @@
)
yield api.test(
- 'failing-build-starts-bisection',
+ 'failing-test-step-starts-bisection',
api.buildbucket.ci_build(
builder='dart2js-win-debug-x64-firefox',
git_repo='https://dart.googlesource.com/sdk',
@@ -204,10 +214,32 @@
api.step_data(
'gitiles log: 2d72510e447ab60a9728aeea2362d8be2cbd7789..%s' %
TESTED_REVISION, api.gitiles.make_log_test_data('master')),
- # Make build fail by failing the 'test results' step
+ # Make test step fail by failing the 'test results' step
api.step_data('test results', retcode=1),
api.post_process(
MustRun,
'schedule bisect (f4d35da881f8fd329a4d3e01dd78b66a502d5c49)'),
api.post_process(StatusFailure),
)
+
+ yield api.test(
+ 'different-failure-in-bisection-schedules-two-bisection-builds',
+ api.buildbucket.ci_build(
+ builder='dart2js-win-debug-x64-firefox',
+ git_repo='https://dart.googlesource.com/sdk',
+ project='dart',
+ revision=TESTED_REVISION),
+ api.properties(
+ bisection_enabled=True,
+ bisect_newer=['a', 'b', 'c'],
+ bisect_older=['c', 'd', 'e'],
+ bisect_base_build=4711,
+ bisect_reason="Step('Build') (retcode: 1)",
+ ),
+ # Make build step fail by failing the 'test results' step
+ api.step_data('test results', retcode=1),
+ api.post_process(MustRun, 'schedule bisect (b)'),
+ api.post_process(MustRun, 'schedule bisect (d)'),
+ api.post_process(StatusFailure),
+ api.post_process(DropExpectation),
+ )