OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Starts bisect try jobs on multiple platforms using known-good configs. | 6 """Starts bisect try jobs on multiple platforms using known-good configs. |
7 | 7 |
8 The purpose of this script is to serve as an integration test for the | 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 | 9 auto-bisect project by starting try jobs for various config types and |
10 various platforms. | 10 various platforms. |
(...skipping 28 matching lines...) Expand all Loading... | |
39 ], | 39 ], |
40 } | 40 } |
41 SVN_URL = 'svn://svn.chromium.org/chrome-try/try-perf' | 41 SVN_URL = 'svn://svn.chromium.org/chrome-try/try-perf' |
42 AUTO_COMMIT_MESSAGE = 'Automatic commit for bisect try job.' | 42 AUTO_COMMIT_MESSAGE = 'Automatic commit for bisect try job.' |
43 | 43 |
44 | 44 |
45 def main(argv): | 45 def main(argv): |
46 parser = argparse.ArgumentParser(description=__doc__) | 46 parser = argparse.ArgumentParser(description=__doc__) |
47 parser.add_argument('--full', action='store_true', | 47 parser.add_argument('--full', action='store_true', |
48 help='Run each config on all applicable bots.') | 48 help='Run each config on all applicable bots.') |
49 parser.add_argument('--filter', | 49 parser.add_argument('configs', nargs='+', |
50 help='Filter for config filenames to use. Only configs ' | 50 help='One or more sample config files.') |
51 'containing the given substring will be tried.') | 51 parser.add_argument('--verbose', '-v', action='store_true', |
52 parser.add_argument('--verbose', '-v', action='store_true') | 52 help='Output additional debugging information.') |
53 parser.add_argument('--dry-run', action='store_true', | |
54 help='Don\'t execute "git try" while running.') | |
53 args = parser.parse_args(argv[1:]) | 55 args = parser.parse_args(argv[1:]) |
54 _SetupLogging(args.verbose) | 56 _SetupLogging(args.verbose) |
55 source_configs = _SourceConfigs(args.filter) | 57 logging.debug('Source configs: %s', args.configs) |
56 logging.debug('Source configs: %s', source_configs) | |
57 try: | 58 try: |
58 _StartTryJobs(source_configs, args.full) | 59 _StartTryJobs(args.configs, args.full, args.dry_run) |
59 except subprocess.CalledProcessError as error: | 60 except subprocess.CalledProcessError as error: |
60 print str(error) | 61 print str(error) |
61 print error.output | 62 print error.output |
62 | 63 |
63 | 64 |
64 def _SetupLogging(verbose): | 65 def _SetupLogging(verbose): |
65 level = logging.INFO | 66 level = logging.INFO |
66 if verbose: | 67 if verbose: |
67 level = logging.DEBUG | 68 level = logging.DEBUG |
68 logging.basicConfig(level=level) | 69 logging.basicConfig(level=level) |
69 | 70 |
70 | 71 |
71 def _SourceConfigs(name_filter): | 72 def _StartTryJobs(source_configs, full_mode=False, dry_run=False): |
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 | |
79 | |
80 | |
81 def _StartTryJobs(source_configs, full_mode=False): | |
82 """Tries each of the given sample configs on one or more try bots.""" | 73 """Tries each of the given sample configs on one or more try bots.""" |
83 for source_config in source_configs: | 74 for source_config in source_configs: |
84 dest_config = _DestConfig(source_config) | 75 dest_config = _DestConfig(source_config) |
85 bot_names = _BotNames(source_config, full_mode=full_mode) | 76 bot_names = _BotNames(source_config, full_mode=full_mode) |
86 _StartTry(source_config, dest_config, bot_names) | 77 _StartTry(source_config, dest_config, bot_names, dry_run=dry_run) |
87 | 78 |
88 | 79 |
89 def _DestConfig(source_config): | 80 def _DestConfig(source_config): |
90 """Returns the path that a sample config should be copied to.""" | 81 """Returns the path that a sample config should be copied to.""" |
91 if 'bisect' in source_config: | 82 if 'bisect' in source_config: |
92 return BISECT_CONFIG | 83 return BISECT_CONFIG |
93 assert 'perf_test' in source_config, source_config | 84 assert 'perf_test' in source_config, source_config |
94 return PERF_TEST_CONFIG | 85 return PERF_TEST_CONFIG |
95 | 86 |
96 | 87 |
97 def _BotNames(source_config, full_mode=False): | 88 def _BotNames(source_config, full_mode=False): |
98 """Returns try bot names to use for the given config file name.""" | 89 """Returns try bot names to use for the given config file name.""" |
99 platform = os.path.basename(source_config).split('.')[0] | 90 platform = os.path.basename(source_config).split('.')[0] |
100 assert platform in PLATFORM_BOT_MAP | 91 assert platform in PLATFORM_BOT_MAP |
101 bot_names = PLATFORM_BOT_MAP[platform] | 92 bot_names = PLATFORM_BOT_MAP[platform] |
102 if full_mode: | 93 if full_mode: |
103 return bot_names | 94 return bot_names |
104 return [bot_names[0]] | 95 return [bot_names[0]] |
105 | 96 |
106 | 97 |
107 def _StartTry(source_config, dest_config, bot_names): | 98 def _StartTry(source_config, dest_config, bot_names, dry_run=False): |
108 """Sends a try job with the given config to the given try bots. | 99 """Sends a try job with the given config to the given try bots. |
109 | 100 |
110 Args: | 101 Args: |
111 source_config: Path of the sample config to copy over. | 102 source_config: Path of the sample config to copy over. |
112 dest_config: Destination path to copy sample to, e.g. "./bisect.cfg". | 103 dest_config: Destination path to copy sample to, e.g. "./bisect.cfg". |
113 bot_names: List of try bot builder names. | 104 bot_names: List of try bot builder names. |
114 """ | 105 """ |
115 assert os.path.exists(source_config) | 106 assert os.path.exists(source_config) |
116 assert os.path.exists(dest_config) | 107 assert os.path.exists(dest_config) |
117 assert _LastCommitMessage() != AUTO_COMMIT_MESSAGE | 108 assert _LastCommitMessage() != AUTO_COMMIT_MESSAGE |
118 | 109 |
119 # Copy the sample config over and commit it. | 110 # Copy the sample config over and commit it. |
120 _Run(['cp', source_config, dest_config]) | 111 _Run(['cp', source_config, dest_config]) |
121 _Run(['git', 'commit', '--all', '-m', AUTO_COMMIT_MESSAGE]) | 112 _Run(['git', 'commit', '--all', '-m', AUTO_COMMIT_MESSAGE]) |
122 | 113 |
123 try: | 114 try: |
124 # Start the try job. | 115 # Start the try job. |
125 job_name = 'Automatically-started (%s)' % os.path.basename(source_config) | 116 job_name = 'Automatically-started (%s)' % os.path.basename(source_config) |
126 try_command = ['git', 'try', '--svn_repo', SVN_URL, '-n', job_name] | 117 try_command = ['git', 'try', '-S', SVN_URL, '-n', job_name] |
Sergiy Byelozyorov
2014/10/30 11:49:13
The previous option name was more readable. Why ch
| |
127 for bot_name in bot_names: | 118 for bot_name in bot_names: |
128 try_command.extend(['-b', bot_name]) | 119 try_command.extend(['-b', bot_name]) |
129 print _Run(try_command) | 120 print _Run(try_command, dry_run=dry_run) |
130 finally: | 121 finally: |
131 # Revert the immediately-previous commit which was made just above. | 122 # Revert the immediately-previous commit which was made just above. |
132 assert _LastCommitMessage() == AUTO_COMMIT_MESSAGE | 123 assert _LastCommitMessage() == AUTO_COMMIT_MESSAGE |
133 _Run(['git', 'reset', '--hard', 'HEAD~1']) | 124 _Run(['git', 'reset', '--hard', 'HEAD~1']) |
134 | 125 |
135 | 126 |
136 def _LastCommitMessage(): | 127 def _LastCommitMessage(): |
137 return _Run(['git', 'log', '--format=%s', '-1']).strip() | 128 return _Run(['git', 'log', '--format=%s', '-1']).strip() |
138 | 129 |
139 | 130 |
140 def _Run(command): | 131 def _Run(command, dry_run=False): |
141 """Runs a command in a subprocess. | 132 """Runs a command in a subprocess. |
142 | 133 |
143 Args: | 134 Args: |
144 command: The command given as an args list. | 135 command: The command given as an args list. |
145 | 136 |
146 Returns: | 137 Returns: |
147 The output of the command. | 138 The output of the command. |
148 | 139 |
149 Raises: | 140 Raises: |
150 subprocess.CalledProcessError: The return-code was non-zero. | 141 subprocess.CalledProcessError: The return-code was non-zero. |
151 """ | 142 """ |
152 logging.debug('Running %s', command) | 143 logging.debug('Running %s', command) |
144 if dry_run: | |
145 return 'Did not run command because this is a dry run.' | |
153 return subprocess.check_output(command) | 146 return subprocess.check_output(command) |
154 | 147 |
155 | 148 |
156 if __name__ == '__main__': | 149 if __name__ == '__main__': |
157 sys.exit(main(sys.argv)) | 150 sys.exit(main(sys.argv)) |
OLD | NEW |