Chromium Code Reviews| 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) |
| + ) |