Add bisect-config-trying script and a few example configs.
[chromium-blink-merge.git] / tools / auto_bisect / configs / try.py
blobe60f6def064deb85107684ec6b8420038d702a35
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Starts bisect try jobs on multiple platforms using known-good configs.
8 The purpose of this script is to serve as an integration test for the
9 auto-bisect project by starting try jobs for various config types and
10 various platforms.
12 The known-good configs are in this same directory as this script. They
13 are expected to all end in ".cfg" and start with the name of the platform
14 followed by a dot.
16 You can specify --full to try running each config on all applicable bots;
17 the default behavior is to try each config on only one bot.
18 """
20 import argparse
21 import logging
22 import os
23 import subprocess
24 import sys
26 SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
27 BISECT_CONFIG = os.path.join(SCRIPT_DIR, os.path.pardir, 'bisect.cfg')
28 PERF_TEST_CONFIG = os.path.join(
29 SCRIPT_DIR, os.path.pardir, os.path.pardir, 'run-perf-test.cfg')
30 PLATFORM_BOT_MAP = {
31 'linux': ['linux_perf_bot'],
32 'mac': ['mac_perf_bisect', 'mac_10_9_perf_bisect'],
33 'win': ['win_perf_bisect', 'win_8_perf_bisect', 'win_xp_perf_bisect'],
34 'android': [
35 'android_nexus4_perf_bisect',
36 'android_nexus5_perf_bisect',
37 'android_nexus7_perf_bisect',
38 'android_nexus10_perf_bisect',
41 SVN_URL = 'svn://svn.chromium.org/chrome-try/try-perf'
42 AUTO_COMMIT_MESSAGE = 'Automatic commit for bisect try job.'
45 def main(argv):
46 parser = argparse.ArgumentParser(description=__doc__)
47 parser.add_argument('--full', action='store_true',
48 help='Run each config on all applicable bots.')
49 parser.add_argument('--filter',
50 help='Filter for config filenames to use. Only configs '
51 'containing the given substring will be tried.')
52 parser.add_argument('--verbose', '-v', action='store_true')
53 args = parser.parse_args(argv[1:])
54 _SetupLogging(args.verbose)
55 source_configs = _SourceConfigs(args.filter)
56 logging.debug('Source configs: %s', source_configs)
57 try:
58 _StartTryJobs(source_configs, args.full)
59 except subprocess.CalledProcessError as error:
60 print str(error)
61 print error.output
64 def _SetupLogging(verbose):
65 level = logging.INFO
66 if verbose:
67 level = logging.DEBUG
68 logging.basicConfig(level=level)
71 def _SourceConfigs(name_filter):
72 """Gets a list of paths to sample configs to try."""
73 files = os.listdir(SCRIPT_DIR)
74 files = [os.path.join(SCRIPT_DIR, name) for name in files]
75 files = [name for name in files if name.endswith('.cfg')]
76 if name_filter:
77 files = [name for name in files if name_filter in name]
78 return files
81 def _StartTryJobs(source_configs, full_mode=False):
82 """Tries each of the given sample configs on one or more try bots."""
83 for source_config in source_configs:
84 dest_config = _DestConfig(source_config)
85 bot_names = _BotNames(source_config, full_mode=full_mode)
86 _StartTry(source_config, dest_config, bot_names)
89 def _DestConfig(source_config):
90 """Returns the path that a sample config should be copied to."""
91 if 'bisect' in source_config:
92 return BISECT_CONFIG
93 assert 'perf_test' in source_config, source_config
94 return PERF_TEST_CONFIG
97 def _BotNames(source_config, full_mode=False):
98 """Returns try bot names to use for the given config file name."""
99 platform = os.path.basename(source_config).split('.')[0]
100 assert platform in PLATFORM_BOT_MAP
101 bot_names = PLATFORM_BOT_MAP[platform]
102 if full_mode:
103 return bot_names
104 return [bot_names[0]]
107 def _StartTry(source_config, dest_config, bot_names):
108 """Sends a try job with the given config to the given try bots.
110 Args:
111 source_config: Path of the sample config to copy over.
112 dest_config: Destination path to copy sample to, e.g. "./bisect.cfg".
113 bot_names: List of try bot builder names.
115 assert os.path.exists(source_config)
116 assert os.path.exists(dest_config)
117 assert _LastCommitMessage() != AUTO_COMMIT_MESSAGE
119 # Copy the sample config over and commit it.
120 _Run(['cp', source_config, dest_config])
121 _Run(['git', 'commit', '--all', '-m', AUTO_COMMIT_MESSAGE])
123 try:
124 # Start the try job.
125 job_name = 'Automatically-started (%s)' % os.path.basename(source_config)
126 try_command = ['git', 'try', '--svn_repo', SVN_URL, '-n', job_name]
127 for bot_name in bot_names:
128 try_command.extend(['-b', bot_name])
129 print _Run(try_command)
130 finally:
131 # Revert the immediately-previous commit which was made just above.
132 assert _LastCommitMessage() == AUTO_COMMIT_MESSAGE
133 _Run(['git', 'reset', '--hard', 'HEAD~1'])
136 def _LastCommitMessage():
137 return _Run(['git', 'log', '--format=%s', '-1']).strip()
140 def _Run(command):
141 """Runs a command in a subprocess.
143 Args:
144 command: The command given as an args list.
146 Returns:
147 The output of the command.
149 Raises:
150 subprocess.CalledProcessError: The return-code was non-zero.
152 logging.debug('Running %s', command)
153 return subprocess.check_output(command)
156 if __name__ == '__main__':
157 sys.exit(main(sys.argv))