Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(327)

Unified Diff: scripts/slave/recipes/findit/chromium/compile.py

Issue 1416763007: Add a recipe to identify culprits for chromium compile failures. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Rebase and Address comments. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: scripts/slave/recipes/findit/chromium/compile.py
diff --git a/scripts/slave/recipes/findit/chromium/compile.py b/scripts/slave/recipes/findit/chromium/compile.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b5b8e0509324a8e25b0d7017cd91b4c86187595
--- /dev/null
+++ b/scripts/slave/recipes/findit/chromium/compile.py
@@ -0,0 +1,267 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+
+from recipe_engine.config import List
+from recipe_engine.recipe_api import Property
+
+
+DEPS = [
+ 'chromium',
+ 'chromium_tests',
+ 'findit',
+ 'gclient',
+ 'json',
+ 'path',
+ 'properties',
+ 'python',
+ 'step',
+]
+
+
+PROPERTIES = {
+ 'target_mastername': Property(
+ kind=str, help='The target master to match compile config to.'),
+ 'target_buildername': Property(
+ kind=str, help='The target builder to match compile config to.'),
+ 'target_solution': Property(
Paweł Hajdan Jr. 2015/11/24 13:20:41 Why is this needed? The mastername and buildernam
stgao 2015/11/24 23:19:20 This is very helpful, and it could save me one par
+ kind=str, help='The gclient solution, eg: src for chromium.'),
+ 'target_solution_revisions': Property(
+ kind=List(basestring),
+ help='The revisions to be tested for compile failure, '
+ 'ordered from older revisions to newer revisions.'),
+ 'requested_compile_targets': Property(
+ kind=List(basestring), default=None, param_name='compile_targets',
+ help='The failed compile targets, eg: browser_tests'),
+}
+
+
+class CompileResult(object):
+ SKIPPED = 'skipped' # No compile is needed.
+ PASSED = 'passed' # Compile passed.
+ FAILED = 'failed' # Compile failed.
+
+
+def _run_compile_at_revision(api, target_mastername, target_buildername,
+ target_solution, revision,
+ compile_targets):
+ with api.step.nest('test %s' % str(revision)):
+ # Configure the revision to recompile.
+ api.gclient.c.revisions[target_solution] = revision
+
+ bot_update_step, master_dict, test_spec = \
+ api.chromium_tests.prepare_checkout(
+ target_mastername,
+ target_buildername)
+
+ # If no compile targets are provided, use analyze to filter out the
Paweł Hajdan Jr. 2015/11/24 13:20:41 Why do you want to support the case where no compi
stgao 2015/11/24 23:19:20 For compile failures on the waterfall, now there i
+ # impacted compile targets by the given revision.
+ # TODO: if compile targets are provided, check if they exist and use analyze
+ # to filter out the impacted ones by the given revision.
+ compile_targets = sorted(set(compile_targets or []))
+ if not compile_targets:
+ affected_files = api.findit.get_files_affected_by_revision(
+ revision, target_solution)
+
+ test_targets, compile_targets, _ = \
+ api.chromium_tests.get_test_targets_compile_targets_and_tests(
Dirk Pranke 2015/11/24 00:17:41 why are you splitting test_targets and compile_tar
stgao 2015/11/24 06:15:29 Yes, to match the changed API in chromium_tests.an
stgao 2015/11/24 23:19:19 Done.
+ target_mastername,
+ target_buildername,
+ master_dict,
+ test_spec,
+ override_bot_type='builder_tester',
+ override_tests=[])
+ additional_compile_targets = sorted(
+ set(compile_targets) - set(test_targets))
+
+ _, compile_targets = api.chromium_tests.analyze(
Paweł Hajdan Jr. 2015/11/24 13:20:41 Is analyze _really_ needed here? Why can't we rely
stgao 2015/11/24 23:19:20 We could do that, but it will be slow, because mor
Paweł Hajdan Jr. 2015/11/30 16:19:05 What's the reasoning behind this? I'm not convince
stgao 2015/12/01 16:30:00 In this smoke test, build in http://shortn/_d3dv1O
+ affected_files,
+ test_targets,
+ additional_compile_targets,
+ 'trybot_analyze_config.json')
+
+ if not compile_targets:
+ # No compile target is impacted by the given revision.
+ return CompileResult.SKIPPED
+
+ assert compile_targets, 'compile targets should not be empty!'
Dirk Pranke 2015/11/24 00:17:41 nit: I'm not convinced this assert is really usefu
stgao 2015/11/24 23:19:20 Done.
+
+ try:
+ api.chromium_tests.compile_specific_targets(
+ target_mastername,
+ target_buildername,
+ bot_update_step,
+ master_dict,
+ compile_targets,
+ [], # Not run any test.
Dirk Pranke 2015/11/24 00:17:41 nit: I'd just say tests_including_triggered=[] ins
stgao 2015/11/24 23:19:20 Done.
+ override_bot_type='builder_tester')
Paweł Hajdan Jr. 2015/11/24 13:20:41 Why is this needed?
stgao 2015/11/24 23:19:20 Just want to make it explicit. I could remove it i
Paweł Hajdan Jr. 2015/11/30 16:19:05 That's actually a behavior change. chromium_trybot
stgao 2015/12/01 16:30:00 Oh, I see. I thought it was the same as a "builder
stgao 2015/12/01 17:15:02 As discussion in the meeting, I will add this bot-
+ return CompileResult.PASSED
+ except api.step.InfraFailure:
+ raise
+ except api.step.StepFailure:
+ return CompileResult.FAILED
+
+
+def RunSteps(api, target_mastername, target_buildername,
+ target_solution, target_solution_revisions,
+ requested_compile_targets):
+ api.chromium_tests.configure_build(
+ target_mastername, target_buildername, override_bot_type='builder_tester')
Paweł Hajdan Jr. 2015/11/24 13:20:41 Why is override_bot_type needed here?
stgao 2015/11/24 23:19:20 Just want to make it explicit. I could remove it i
+
+ results = []
+ try:
+ for current_revision in target_solution_revisions:
+ try:
+ compile_result = _run_compile_at_revision(
+ api, target_mastername, target_buildername, target_solution,
+ current_revision, requested_compile_targets)
+ except api.step.InfraFailure:
+ # Retry once only on infra failure.
Paweł Hajdan Jr. 2015/11/24 13:20:41 Is this retry really needed/useful here?
stgao 2015/11/24 23:19:19 For compile failures on the waterfall, I saw a lot
Paweł Hajdan Jr. 2015/11/30 16:19:05 Can we start with a version of this recipe which d
stgao 2015/12/01 16:30:00 OK. Removed.
+ compile_result = _run_compile_at_revision(
+ api, target_mastername, target_buildername, target_solution,
+ current_revision, requested_compile_targets)
+
+ results.append([current_revision, compile_result])
+ if compile_result == CompileResult.FAILED:
+ # TODO: if compile targets are specified, compile may fail because those
Paweł Hajdan Jr. 2015/11/24 13:20:41 Please follow the style guide's TODO(...) format.
stgao 2015/11/24 23:19:20 Done.
+ # targets are added in a later revision.
+ break # Found the culprit, no need to check later revisions.
+ finally:
+ # Report the result.
+ step_result = api.python.inline(
Paweł Hajdan Jr. 2015/11/24 13:20:41 Why not use api.python.result_step (or succeeding/
stgao 2015/11/24 23:19:20 I'm afraid I can't do that. Because they don't su
Paweł Hajdan Jr. 2015/11/30 16:19:05 Could you at the very least add a TODO, and eventu
stgao 2015/12/01 16:30:00 Done.
+ 'report', 'import sys; sys.exit(0)', add_python_log=False)
+ if (not requested_compile_targets and
+ results and results[-1][1] == CompileResult.FAILED):
+ step_result.presentation.step_text = '<br/>Culprit: %s' % results[-1][0]
+ step_result.presentation.logs.setdefault('result', []).append(
+ json.dumps(results, indent=2))
+
+ return results
+
+
+def GenTests(api):
+ def props(compile_targets=None):
+ properties = {
+ 'mastername': 'tryserver.chromium.linux',
+ 'buildername': 'linux_variable',
+ 'slavename': 'build1-a1',
+ 'buildnumber': '1',
+ 'target_mastername': 'chromium.linux',
+ 'target_buildername': 'Linux Builder',
+ 'target_solution': 'src',
+ 'target_solution_revisions': ['r1'],
+ }
+ if compile_targets:
+ properties['compile_targets'] = compile_targets
+ return api.properties(**properties)
+
+ yield (
+ api.test('compile_skipped') +
+ props() +
+ api.override_step_data(
+ 'test r1.analyze',
+ api.json.output({
+ 'status': 'No dependencies',
+ 'compile_targets': [],
+ 'test_targets': [],
+ })
+ )
+ )
+
+ yield (
+ api.test('successful_compile_targets_returned_by_analyze') +
+ props() +
+ api.override_step_data(
+ 'test r1.analyze',
+ api.json.output({
+ 'status': 'Found dependency',
+ 'compile_targets': ['test_target', 'test_target_run'],
+ 'test_targets': ['test_target', 'test_target_run'],
+ })
+ )
+ )
+
+ yield (
+ api.test('failed_compile_targets_returned_by_analyze') +
+ props() +
+ api.override_step_data(
+ 'test r1.analyze',
+ api.json.output({
+ 'status': 'Found dependency',
+ 'compile_targets': ['test_target', 'test_target_run'],
+ 'test_targets': ['test_target', 'test_target_run'],
+ })
+ ) +
+ api.override_step_data('test r1.compile', retcode=1)
+ )
+
+ yield (
+ api.test('compile_specified_targets') +
+ props(compile_targets=['target_name'])
+ )
+
+ yield (
+ api.test('compile_failed') +
+ props(compile_targets=['target_name']) +
+ api.override_step_data('test r1.compile', retcode=1)
+ )
+
+ yield (
+ api.test('successful_retry_compile_upon_infra_failure') +
+ props(compile_targets=['target_name']) +
+ api.override_step_data(
+ 'test r1.compile',
+ api.json.output({
+ 'notice': [
+ {
+ 'infra_status': {
+ 'ping_status_code': 408,
+ },
+ },
+ ],
+ }),
+ retcode=1) +
+ api.override_step_data(
+ 'test r1.compile (2)',
+ api.json.output({
+ 'notice': [
+ {
+ 'infra_status': {
+ 'ping_status_code': 200,
+ },
+ },
+ ],
+ }),
+ retcode=1)
+ )
+
+ yield (
+ api.test('failed_retry_compile_upon_infra_failure') +
+ props(compile_targets=['target_name']) +
+ api.override_step_data(
+ 'test r1.compile',
+ api.json.output({
+ 'notice': [
+ {
+ 'infra_status': {
+ 'ping_status_code': 408,
+ },
+ },
+ ],
+ }),
+ retcode=1) +
+ api.override_step_data(
+ 'test r1.compile (2)',
+ api.json.output({
+ 'notice': [
+ {
+ 'infra_status': {
+ 'ping_status_code': 408,
+ },
+ },
+ ],
+ }),
+ retcode=1)
+ )

Powered by Google App Engine
This is Rietveld 408576698