blob: 16a41b105ff600645961de27548644faf420b359 [file] [log] [blame]
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07001# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module for tasks triggered by suite scheduler."""
6# pylint: disable=g-bad-import-order
Xixuan Wu244e0ec2018-05-23 14:49:55 -07007# pylint: disable=dangerous-default-value
Xixuan Wu0c76d5b2017-08-30 16:40:17 -07008
9from distutils import version
10import MySQLdb
11import logging
12
13import build_lib
14import task_executor
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070015import tot_manager
16
17# The max lifetime of a suite scheduled by suite scheduler
18_JOB_MAX_RUNTIME_MINS_DEFAULT = 72 * 60
19
20# One kind of formats for RO firmware spec.
21_RELEASE_RO_FIRMWARE_SPEC = 'released_ro_'
22
23
24class SchedulingError(Exception):
25 """Raised to indicate a failure in scheduling a task."""
26
27
28class Task(object):
29 """Represents an entry from the suite_scheduler config file.
30
31 Each entry from the suite_scheduler config file maps one-to-one to a
32 Task. Each instance has enough information to schedule itself.
33 """
34
Po-Hsien Wangdd833072018-08-16 18:09:20 -070035 def __init__(self, task_info, board_family_config={}, tot=None):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070036 """Initialize a task instance.
37
38 Args:
39 task_info: a config_reader.TaskInfo object, which includes:
40 name, name of this task, e.g. 'NightlyPower'
41 suite, the name of the suite to run, e.g. 'graphics_per-day'
42 branch_specs, a pre-vetted iterable of branch specifiers,
43 e.g. ['>=R18', 'factory']
44 pool, the pool of machines to schedule tasks. Default is None.
45 num, the number of devices to shard the test suite. It could
46 be an Integer or None. By default it's None.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070047 board_families, a common separated list of board family to run this
48 task on. Boards belong to one of the board family in this list
49 would be added to task_info.boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070050 boards, a comma separated list of boards to run this task on. Default
Po-Hsien Wangdd833072018-08-16 18:09:20 -070051 is None, which allows this task to run on all boards. If same board
52 is specified in 'boards' and 'exclude_boards', we exclude this
53 board.
54 exclude_board_families, a common separated list of board family not to
55 run task on. Boards belong to one of the board family in this list
56 would be added to task_info.exclude_boards.
Po-Hsien Wang6d589732018-05-15 17:19:34 -070057 exclude_boards, a comma separated list of boards not to run this task
58 on. Default is None, which allows this task to run on all boards.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070059 If same board is specified in 'boards' and 'exclude_boards', we
60 exclude this board.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070061 priority, the string name of a priority from constants.Priorities.
62 timeout, the max lifetime of the suite in hours.
63 cros_build_spec, spec used to determine the ChromeOS build to test
64 with a firmware build, e.g., tot, R41 etc.
65 firmware_rw_build_spec, spec used to determine the firmware RW build
66 test with a ChromeOS build.
67 firmware_ro_build_spec, spec used to determine the firmware RO build
68 test with a ChromeOS build.
69 test_source, the source of test code when firmware will be updated in
70 the test. The value can be 'firmware_rw', 'firmware_ro' or 'cros'.
71 job_retry, set to True to enable job-level retry. Default is False.
Xixuan Wu80531932017-10-12 17:26:51 -070072 no_delay, set to True to raise the priority of this task in task.
73 force, set to True to schedule this suite no matter whether there's
74 duplicate jobs before.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070075 queue, so the suite jobs can start running tests with no waiting.
76 hour, an integer specifying the hour that a nightly run should be
77 triggered, default is set to 21.
78 day, an integer specifying the day of a week that a weekly run should
79 be triggered, default is set to 5 (Saturday).
80 os_type, type of OS, e.g., cros, brillo, android. Default is cros.
81 The argument is required for android/brillo builds.
82 launch_control_branches, comma separated string of launch control
83 branches. The argument is required and only applicable for
84 android/brillo builds.
85 launch_control_targets, comma separated string of build targets for
86 launch control builds. The argument is required and only
87 applicable for android/brillo builds.
88 testbed_dut_count, number of duts to test when using a testbed.
Po-Hsien Wangdd833072018-08-16 18:09:20 -070089 board_family_config: A board family dictionary mapping board_family name to
Xixuan Wu244e0ec2018-05-23 14:49:55 -070090 its corresponding boards.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070091 tot: The tot manager for checking ToT. If it's None, a new tot_manager
92 instance will be initialized.
93 """
Xixuan Wu5451a662017-10-17 10:57:40 -070094 # Indicate whether there're suites get pushed into taskqueue for this task.
95 self.is_pushed = False
96
Xixuan Wu0c76d5b2017-08-30 16:40:17 -070097 self.name = task_info.name
98 self.suite = task_info.suite
99 self.branch_specs = task_info.branch_specs
100 self.pool = task_info.pool
101 self.num = task_info.num
102 self.priority = task_info.priority
103 self.timeout = task_info.timeout
104 self.cros_build_spec = task_info.cros_build_spec
105 self.firmware_rw_build_spec = task_info.firmware_rw_build_spec
106 self.firmware_ro_build_spec = task_info.firmware_ro_build_spec
107 self.test_source = task_info.test_source
108 self.job_retry = task_info.job_retry
109 self.no_delay = task_info.no_delay
Xixuan Wu80531932017-10-12 17:26:51 -0700110 self.force = task_info.force
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700111 self.os_type = task_info.os_type
112 self.testbed_dut_count = task_info.testbed_dut_count
Xixuan Wu008ee832017-10-12 16:59:34 -0700113 self.hour = task_info.hour
114 self.day = task_info.day
Craig Bergstrom58263d32018-04-26 14:11:35 -0600115 self.only_hwtest_sanity_required = task_info.only_hwtest_sanity_required
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700116
117 if task_info.lc_branches:
118 self.launch_control_branches = [
119 t.strip() for t in task_info.lc_branches.split(',')]
120 else:
121 self.launch_control_branches = []
122
123 if task_info.lc_targets:
124 self.launch_control_targets = [
125 t.strip() for t in task_info.lc_targets.split(',')]
126 else:
127 self.launch_control_targets = []
128
129 if task_info.boards:
130 self.boards = [t.strip() for t in task_info.boards.split(',')]
131 else:
132 self.boards = []
133
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700134 if task_info.exclude_boards:
135 self.exclude_boards = [
136 t.strip() for t in task_info.exclude_boards.split(',')]
137 else:
138 self.exclude_boards = []
139
Po-Hsien Wangdd833072018-08-16 18:09:20 -0700140 if task_info.board_families:
141 # Finetune the allowed boards list with board_families & boards.
142 families = [family.strip()
143 for family in task_info.board_families.split(',')]
144 for family in families:
145 self.boards += board_family_config.get(family, [])
146 if task_info.exclude_board_families:
147 # Finetune the disallowed boards list with exclude_board_families
148 # & exclude_boards.
149 families = [family.strip()
150 for family in task_info.exclude_board_families.split(',')]
151 for family in families:
152 self.exclude_boards += board_family_config.get(family, [])
153
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700154 if tot is None:
155 self.tot_manager = tot_manager.TotMilestoneManager()
156 else:
157 self.tot_manager = tot
158
159 self._set_spec_compare_info()
160
Craig Bergstrom58263d32018-04-26 14:11:35 -0600161 def schedule(self, launch_control_builds, cros_builds_tuple, lab_config,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700162 db_client):
163 """Schedule the task by its settings.
164
165 Args:
166 launch_control_builds: the build dict for Android boards, see
167 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600168 cros_builds_tuple: the two-tuple of build dicts for ChromeOS boards,
169 see return value of |get_cros_builds|.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700170 lab_config: a config.LabConfig object, to read lab config file.
171 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
172
173 Raises:
174 SchedulingError: if tasks that should be scheduled fail to schedule.
Xixuan Wu5451a662017-10-17 10:57:40 -0700175
176 Returns:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700177 A boolean indicator; true if there were any suites related to this
178 task which got pushed into the suites queue.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700179 """
180 assert lab_config is not None
Xixuan Wu5451a662017-10-17 10:57:40 -0700181 self.is_pushed = False
182
Craig Bergstrom58263d32018-04-26 14:11:35 -0600183 branch_builds, relaxed_builds = cros_builds_tuple
184 builds_dict = branch_builds
185 if self.only_hwtest_sanity_required:
186 builds_dict = relaxed_builds
187
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700188 logging.info('######## Scheduling task %s ########', self.name)
189 if self.os_type == build_lib.OS_TYPE_CROS:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600190 if not builds_dict:
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700191 logging.info('No CrOS build to run, skip running.')
192 else:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600193 self._schedule_cros_builds(builds_dict, lab_config, db_client)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700194 else:
195 if not launch_control_builds:
196 logging.info('No Android build to run, skip running.')
197 else:
198 self._schedule_launch_control_builds(launch_control_builds)
199
Xixuan Wu5451a662017-10-17 10:57:40 -0700200 return self.is_pushed
201
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700202 def _set_spec_compare_info(self):
203 """Set branch spec compare info for task for further check."""
204 self._bare_branches = []
205 self._version_equal_constraint = False
206 self._version_gte_constraint = False
207 self._version_lte_constraint = False
208
209 if not self.branch_specs:
210 # Any milestone is OK.
211 self._numeric_constraint = version.LooseVersion('0')
212 else:
213 self._numeric_constraint = None
214 for spec in self.branch_specs:
215 if 'tot' in spec.lower():
216 # Convert spec >=tot-1 to >=RXX.
217 tot_str = spec[spec.index('tot'):]
218 spec = spec.replace(
219 tot_str, self.tot_manager.convert_tot_spec(tot_str))
220
221 if spec.startswith('>='):
222 self._numeric_constraint = version.LooseVersion(
223 spec.lstrip('>=R'))
224 self._version_gte_constraint = True
225 elif spec.startswith('<='):
226 self._numeric_constraint = version.LooseVersion(
227 spec.lstrip('<=R'))
228 self._version_lte_constraint = True
229 elif spec.startswith('=='):
230 self._version_equal_constraint = True
231 self._numeric_constraint = version.LooseVersion(
232 spec.lstrip('==R'))
233 else:
234 self._bare_branches.append(spec)
235
236 def _fits_spec(self, branch):
237 """Check if a branch is deemed OK by this task's branch specs.
238
239 Will return whether a branch 'fits' the specifications stored in this task.
240
241 Examples:
242 Assuming tot=R40
243 t = Task('Name', 'suite', ['factory', '>=tot-1'])
244 t._fits_spec('factory') # True
245 t._fits_spec('40') # True
246 t._fits_spec('38') # False
247 t._fits_spec('firmware') # False
248
249 Args:
250 branch: the branch to check.
251
252 Returns:
253 True if branch 'fits' with stored specs, False otherwise.
254 """
255 if branch in build_lib.BARE_BRANCHES:
256 return branch in self._bare_branches
257
258 if self._numeric_constraint:
259 if self._version_equal_constraint:
260 return version.LooseVersion(branch) == self._numeric_constraint
261 elif self._version_gte_constraint:
262 return version.LooseVersion(branch) >= self._numeric_constraint
263 elif self._version_lte_constraint:
264 return version.LooseVersion(branch) <= self._numeric_constraint
265 else:
266 return version.LooseVersion(branch) >= self._numeric_constraint
267 else:
268 return False
269
270 def _get_latest_firmware_build_from_db(self, spec, board, db_client):
271 """Get the latest firmware build from CIDB database.
272
273 Args:
274 spec: a string build spec for RO or RW firmware, eg. firmware,
275 cros. For RO firmware, the value can also be released_ro_X.
276 board: the board against which this task will run suite job.
277 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
278
279 Returns:
280 the latest firmware build.
281
282 Raises:
283 MySQLdb.OperationalError: if connection operations are not valid.
284 """
285 build_type = 'release' if spec == 'cros' else spec
286 # TODO(xixuan): not all firmware are saved in cidb.
287 build = db_client.get_latest_passed_builds('%s-%s' % (board, build_type))
288
289 if build is None:
290 return None
291 else:
292 latest_build = str(build_lib.CrOSBuild(
293 board, build_type, build.milestone, build.platform))
294 logging.debug('latest firmware build for %s-%s: %s', board,
295 build_type, latest_build)
296 return latest_build
297
298 def _get_latest_firmware_build_from_lab_config(self, spec, board,
299 lab_config):
300 """Get latest firmware from lab config file.
301
302 Args:
303 spec: a string build spec for RO or RW firmware, eg. firmware,
304 cros. For RO firmware, the value can also be released_ro_X.
305 board: a string board against which this task will run suite job.
306 lab_config: a config.LabConfig object, to read lab config file.
307
308 Returns:
309 A string latest firmware build.
310
311 Raises:
312 ValueError: if no firmware build list is found in lab config file.
313 """
314 index = int(spec[len(_RELEASE_RO_FIRMWARE_SPEC):])
315 released_ro_builds = lab_config.get_firmware_ro_build_list(
316 'RELEASED_RO_BUILDS_%s' % board).split(',')
317 if len(released_ro_builds) < index:
318 raise ValueError('No %dth ro_builds in the lab_config firmware '
319 'list %r' % (index, released_ro_builds))
320
321 logging.debug('Get ro_build: %s', released_ro_builds[index - 1])
322 return released_ro_builds[index - 1]
323
324 def _get_firmware_build(self, spec, board, lab_config, db_client):
325 """Get the firmware build name to test with ChromeOS build.
326
327 Args:
328 spec: a string build spec for RO or RW firmware, eg. firmware,
329 cros. For RO firmware, the value can also be released_ro_X.
330 board: a string board against which this task will run suite job.
331 lab_config: a config.LabConfig object, to read lab config file.
332 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
333
334 Returns:
335 A string firmware build name.
336
337 Raises:
338 ValueError: if failing to get firmware from lab config file;
339 MySQLdb.OperationalError: if DB connection is not available.
340 """
341 if not spec or spec == 'stable':
342 # TODO(crbug.com/577316): Query stable RO firmware.
343 logging.debug('%s RO firmware build is not supported.', spec)
344 return None
345
346 try:
347 if spec.startswith(_RELEASE_RO_FIRMWARE_SPEC):
348 # For RO firmware whose value is released_ro_X, where X is the index of
349 # the list defined in lab config file:
350 # CROS/RELEASED_RO_BUILDS_[board].
351 # For example, for spec 'released_ro_2', and lab config file
352 # CROS/RELEASED_RO_BUILDS_veyron_jerry: build1,build2,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600353 # return firmware RO build should be 'build2'.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700354 return self._get_latest_firmware_build_from_lab_config(
355 spec, board, lab_config)
356 else:
357 return self._get_latest_firmware_build_from_db(spec, board, db_client)
358 except ValueError as e:
359 logging.warning('Failed to get firmware from lab config file'
360 'for spec %s, board %s: %s', spec, board, str(e))
361 return None
362 except MySQLdb.OperationalError as e:
363 logging.warning('Failed to get firmware from cidb for spec %s, '
364 'board %s: %s', spec, board, str(e))
365 return None
366
C Shapiro7f24a002017-12-05 14:25:09 -0700367 def _push_suite(
368 self,
369 board=None,
370 model=None,
371 cros_build=None,
372 firmware_rw_build=None,
373 firmware_ro_build=None,
374 test_source_build=None,
375 launch_control_build=None,
Xixuan Wubb74a372018-08-21 17:37:08 -0700376 run_prod_code=False,
377 is_skylab=False):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700378 """Schedule suite job for the task by pushing suites to SuiteQueue.
379
380 Args:
381 board: the board against which this suite job run.
C Shapiro7f24a002017-12-05 14:25:09 -0700382 model: the model name for unibuild.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700383 cros_build: the CrOS build of this suite job.
384 firmware_rw_build: Firmware RW build to run this suite job with.
385 firmware_ro_build: Firmware RO build to run this suite job with.
386 test_source_build: Test source build, used for server-side
387 packaging of this suite job.
388 launch_control_build: the launch control build of this suite job.
389 run_prod_code: If True, the suite will run the test code that lives
390 in prod aka the test code currently on the lab servers. If
391 False, the control files and test code for this suite run will
392 be retrieved from the build artifacts. Default is False.
Xixuan Wubb74a372018-08-21 17:37:08 -0700393 is_skylab: If True, schedule this suite to skylab, otherwise schedule
394 it to AFE. Default is False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700395 """
396 android_build = None
397 testbed_build = None
398
399 if self.testbed_dut_count:
400 launch_control_build = '%s#%d' % (launch_control_build,
401 self.testbed_dut_count)
402 test_source_build = launch_control_build
403 board = '%s-%d' % (board, self.testbed_dut_count)
404
405 if launch_control_build:
406 if not self.testbed_dut_count:
407 android_build = launch_control_build
408 else:
409 testbed_build = launch_control_build
410
411 suite_job_parameters = {
412 'suite': self.suite,
413 'board': board,
C Shapiro7f24a002017-12-05 14:25:09 -0700414 'model': model,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700415 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
416 build_lib.BuildVersionKey.FW_RW_VERSION: firmware_rw_build,
417 build_lib.BuildVersionKey.FW_RO_VERSION: firmware_ro_build,
418 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: android_build,
419 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: testbed_build,
420 'num': self.num,
421 'pool': self.pool,
422 'priority': self.priority,
423 'timeout': self.timeout,
424 'timeout_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
425 'max_runtime_mins': _JOB_MAX_RUNTIME_MINS_DEFAULT,
Xixuan Wu2ba72652017-09-15 15:49:42 -0700426 'no_wait_for_results': not self.job_retry,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700427 'test_source_build': test_source_build,
428 'job_retry': self.job_retry,
429 'no_delay': self.no_delay,
Xixuan Wu80531932017-10-12 17:26:51 -0700430 'force': self.force,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700431 'run_prod_code': run_prod_code,
Xixuan Wubb74a372018-08-21 17:37:08 -0700432 'is_skylab': is_skylab,
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700433 }
434
435 task_executor.push(task_executor.SUITES_QUEUE, **suite_job_parameters)
436 logging.info('Pushing task %r into taskqueue', suite_job_parameters)
Xixuan Wu5451a662017-10-17 10:57:40 -0700437 self.is_pushed = True
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700438
Craig Bergstrom58263d32018-04-26 14:11:35 -0600439 def _schedule_cros_builds(self, build_dict, lab_config, db_client):
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700440 """Schedule tasks with branch builds.
441
442 Args:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600443 build_dict: the build dict for ChromeOS boards, see return
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700444 value of |build_lib.get_cros_builds_since_date_from_db|.
445 lab_config: a config.LabConfig object, to read lab config file.
446 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
447 """
C Shapiro7f24a002017-12-05 14:25:09 -0700448 models_by_board = lab_config.get_cros_model_map() if lab_config else {}
Xixuan Wubb74a372018-08-21 17:37:08 -0700449 skylab_boards = lab_config.get_skylab_board_list() if lab_config else []
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700450 for (board, build_type,
Craig Bergstrom58263d32018-04-26 14:11:35 -0600451 milestone), manifest in build_dict.iteritems():
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700452 cros_build = str(build_lib.CrOSBuild(board, build_type, milestone,
453 manifest))
454 logging.info('Running %s on %s', self.name, cros_build)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700455 if self.exclude_boards and board in self.exclude_boards:
456 logging.debug('Board %s is in excluded board list: %s',
457 board, self.exclude_boards)
458 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700459 if self.boards and board not in self.boards:
460 logging.debug('Board %s is not in supported board list: %s',
461 board, self.boards)
462 continue
463
464 # Check the fitness of the build's branch for task
465 branch_build_spec = _pick_branch(build_type, milestone)
466 if not self._fits_spec(branch_build_spec):
467 logging.debug("branch_build spec %s doesn't fit this task's "
468 "requirement: %s", branch_build_spec, self.branch_specs)
469 continue
470
471 firmware_rw_build = None
472 firmware_ro_build = None
473 if self.firmware_rw_build_spec or self.firmware_ro_build_spec:
474 firmware_rw_build = self._get_firmware_build(
475 self.firmware_rw_build_spec, board, lab_config, db_client)
476 firmware_ro_build = self._get_firmware_build(
477 self.firmware_ro_build_spec, board, lab_config, db_client)
478
479 if not firmware_ro_build and self.firmware_ro_build_spec:
480 logging.debug('No firmware ro build to run, skip running')
481 continue
482
483 if self.test_source == build_lib.BuildType.FIRMWARE_RW:
484 test_source_build = firmware_rw_build
485 else:
Jacob Kopczynski79d00102018-07-13 15:37:03 -0700486 # Default test source build to CrOS build if it's not specified.
487 # Past versions chose based on run_prod_code, but we no longer respect
488 # that option and scheduler settings should always set it to False.
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700489 test_source_build = cros_build
490
C Shapiro7f24a002017-12-05 14:25:09 -0700491 models = models_by_board.get(board, [None])
492
493 for model in models:
494 self._push_suite(board=board,
495 model=model,
496 cros_build=cros_build,
497 firmware_rw_build=firmware_rw_build,
498 firmware_ro_build=firmware_ro_build,
Xixuan Wubb74a372018-08-21 17:37:08 -0700499 test_source_build=test_source_build,
500 is_skylab=board in skylab_boards)
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700501
502 def _schedule_launch_control_builds(self, launch_control_builds):
503 """Schedule tasks with launch control builds.
504
505 Args:
506 launch_control_builds: the build dict for Android boards.
507 """
508 for board, launch_control_build in launch_control_builds.iteritems():
509 logging.debug('Running %s on %s', self.name, board)
Po-Hsien Wang6d589732018-05-15 17:19:34 -0700510 if self.exclude_boards and board in self.exclude_boards:
511 logging.debug('Board %s is in excluded board list: %s',
512 board, self.exclude_boards)
513 continue
Xixuan Wu0c76d5b2017-08-30 16:40:17 -0700514 if self.boards and board not in self.boards:
515 logging.debug('Board %s is not in supported board list: %s',
516 board, self.boards)
517 continue
518
519 for android_build in launch_control_build:
520 if not any([branch in android_build
521 for branch in self.launch_control_branches]):
522 logging.debug('Branch %s is not required to run for task '
523 '%s', android_build, self.name)
524 continue
525
526 self._push_suite(board=board,
527 test_source_build=android_build,
528 launch_control_build=android_build)
529
530
531def _pick_branch(build_type, milestone):
532 """Select branch based on build type.
533
534 If the build_type is a bare branch, return build_type as the build spec.
535 If the build_type is a normal CrOS branch, return milestone as the build
536 spec.
537
538 Args:
539 build_type: a string builder name, like 'release'.
540 milestone: a string milestone, like '55'.
541
542 Returns:
543 A string milestone if build_type represents CrOS build, otherwise
544 return build_type.
545 """
546 return build_type if build_type in build_lib.BARE_BRANCHES else milestone