| Index: commit-queue/verification/try_job_steps.py
|
| ===================================================================
|
| --- commit-queue/verification/try_job_steps.py (revision 249146)
|
| +++ commit-queue/verification/try_job_steps.py (working copy)
|
| @@ -1,247 +0,0 @@
|
| -# coding=utf8
|
| -# Copyright (c) 2013 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 model
|
| -
|
| -
|
| -# CQ uses this delay to decide if a triggered job hasn't show up from
|
| -# rietveld processing time or if it has gone missing
|
| -PROPOGATION_DELAY_S = 3 * 60 * 60
|
| -
|
| -
|
| -def need_to_trigger(builder_name, need_to_run, try_jobs):
|
| - """Returns which tests need to be triggered.
|
| -
|
| - These are the tests that are not pending on any try job, either running or
|
| - in the pending list.
|
| - """
|
| - need_to_run = set(need_to_run)
|
| - for try_job in try_jobs:
|
| - if try_job.builder == builder_name:
|
| - need_to_run -= set(try_job.steps_passed)
|
| - if not try_job.completed:
|
| - if try_job.requested_steps == []:
|
| - # Special case jobs discovered by CQ that it did not send. Wait for
|
| - # these jobs to complete rather than trying to interpret the filter
|
| - assert try_job.started
|
| - need_to_run.clear()
|
| - else:
|
| - need_to_run -= (
|
| - set(try_job.requested_steps) - set(try_job.steps_failed))
|
| -
|
| - return need_to_run
|
| -
|
| -
|
| -def waiting_for(builder_name, tests, try_jobs):
|
| - """Returns the tests that we are waiting for results on pending or running
|
| - builds.
|
| - """
|
| - tests = set(tests)
|
| - for try_job in try_jobs:
|
| - if try_job.builder == builder_name:
|
| - tests -= set(try_job.steps_passed)
|
| - return tests
|
| -
|
| -
|
| -class TryJobStepsBase(model.PersistentMixIn):
|
| - builder_name = unicode
|
| -
|
| - # Name of the prerequisite builder.
|
| - prereq_builder = unicode
|
| - # List of prerequisite tests to look for.
|
| - prereq_tests = list
|
| -
|
| - def __init__(self, **kwargs):
|
| - kwargs.setdefault('prereq_builder', u'')
|
| - kwargs.setdefault('prereq_tests', [])
|
| - required = set(self._persistent_members())
|
| - actual = set(kwargs)
|
| - assert required == actual, (required - actual, required, actual)
|
| - super(TryJobStepsBase, self).__init__(**kwargs)
|
| - # Then mark it read-only.
|
| - self._read_only = True
|
| -
|
| - @model.immutable
|
| - def unmet_prereqs(self, try_jobs):
|
| - """
|
| - Determine if this TryJobSteps has unmet prerequisites.
|
| -
|
| - Returns True iff prereq is unmet.
|
| - """
|
| - if not self.prereq_builder or not self.prereq_tests:
|
| - return None
|
| - unmet_steps = set(self.prereq_tests)
|
| - for try_job in try_jobs.itervalues():
|
| - if try_job.builder == self.prereq_builder:
|
| - unmet_steps -= set(try_job.steps_passed)
|
| - return bool(unmet_steps)
|
| -
|
| - @model.immutable
|
| - def get_triggered_steps(self, _builder, _steps):
|
| - """Returns the steps on this builder that will get triggered by the given
|
| - builder and its steps, which is always None since this isn't a triggered
|
| - bot."""
|
| - return (self.builder_name, [])
|
| -
|
| -
|
| -class TryJobSteps(TryJobStepsBase):
|
| - steps = list
|
| -
|
| - @model.immutable
|
| - def waiting_for(self, try_jobs):
|
| - """Returns the tests that we are waiting for results on pending or running
|
| - builds.
|
| - """
|
| - return (self.builder_name,
|
| - waiting_for(self.builder_name, self.steps, try_jobs.itervalues()))
|
| -
|
| - @model.immutable
|
| - def need_to_trigger(self, try_jobs, _now):
|
| - """Returns which tests need to be triggered.
|
| -
|
| - These are the tests that are not pending on any try job, either running or
|
| - in the pending list.
|
| - """
|
| - if self.unmet_prereqs(try_jobs):
|
| - return (self.builder_name, [])
|
| - return (self.builder_name,
|
| - need_to_trigger(self.builder_name, self.steps,
|
| - try_jobs.itervalues()))
|
| -
|
| -
|
| -class TryJobTriggeredSteps(TryJobStepsBase):
|
| - # The name of the bot that triggers this bot.
|
| - trigger_name = unicode
|
| - # Maps the triggered_bot_step -> trigger_bot_step required to trigger it.
|
| - steps = dict
|
| -
|
| - @model.immutable
|
| - def _triggered_try_jobs(self, try_jobs):
|
| - """Return all the try jobs that were on this builder and had been trigger
|
| - by the trigger_name bot."""
|
| - triggered_try_jobs = []
|
| - for try_job in try_jobs.itervalues():
|
| - if (try_job.builder == self.builder_name and
|
| - try_job.parent_key and try_job.parent_key in try_jobs and
|
| - try_jobs[try_job.parent_key].builder == self.trigger_name):
|
| - triggered_try_jobs.append(try_job)
|
| -
|
| - return triggered_try_jobs
|
| -
|
| - @model.immutable
|
| - def waiting_for(self, try_jobs):
|
| - """Returns the tests that we are waiting for results on pending or running
|
| - builds.
|
| - """
|
| - return (self.builder_name,
|
| - waiting_for(self.builder_name, self.steps,
|
| - self._triggered_try_jobs(try_jobs)))
|
| -
|
| - @model.immutable
|
| - def need_to_trigger(self, try_jobs, now):
|
| - """Returns which tests need to be triggered.
|
| -
|
| - These are the tests that are not pending on any try job, either running or
|
| - in the pending list.
|
| - """
|
| - if self.unmet_prereqs(try_jobs):
|
| - return (self.builder_name, [])
|
| - need_to_run = set(self.steps)
|
| - steps_to_trigger = need_to_trigger(self.builder_name, need_to_run,
|
| - self._triggered_try_jobs(try_jobs))
|
| -
|
| - # Convert the steps to trigger to their trigger options.
|
| - trigger_need_to_run = set(self.steps[step] for step in steps_to_trigger)
|
| -
|
| - # See which triggered builds have already started, so we can then ignore
|
| - # their parents when seeing if more triggered build are on the way.
|
| - detected_triggered_keys = set(
|
| - job.parent_key for key, job in try_jobs.iteritems()
|
| - if job.builder == self.builder_name)
|
| -
|
| - # Remove any trigger options that are waiting to run from the set to
|
| - # trigger.
|
| - for key, try_job in try_jobs.iteritems():
|
| - if try_job.builder == self.trigger_name:
|
| - if (try_job.completed and
|
| - not (now - try_job.init_time > PROPOGATION_DELAY_S) and
|
| - key not in detected_triggered_keys):
|
| - # If we get here a triggered build hasn't started yet, so wait for
|
| - # any steps that should run on the triggered build.
|
| - trigger_need_to_run -= (
|
| - set(step for step in self.steps.itervalues()
|
| - if step in try_job.requested_steps))
|
| - if not try_job.completed:
|
| - trigger_need_to_run -= (
|
| - set(try_job.requested_steps) - set(try_job.steps_failed))
|
| -
|
| - return (self.trigger_name, trigger_need_to_run)
|
| -
|
| - @model.immutable
|
| - def get_triggered_steps(self, builder, steps):
|
| - """Returns the steps on this builder that will get triggered by the given
|
| - builder and its steps."""
|
| - trigger_steps = []
|
| - if builder == self.trigger_name:
|
| - trigger_steps = [key for key, value in self.steps.iteritems()
|
| - if value in steps]
|
| -
|
| - return (self.builder_name, sorted(trigger_steps))
|
| -
|
| -
|
| -class TryJobTriggeredOrNormalSteps(TryJobTriggeredSteps):
|
| - """This class assumes that the triggered names can be run
|
| - on the trigger bot with the same name that they appear with on
|
| - the triggered bot."""
|
| -
|
| - # The list of steps that have to be run on the trigger bot.
|
| - trigger_bot_steps = list
|
| -
|
| - # True if the triggered bot should try and run the missing tests.
|
| - use_triggered_bot = bool
|
| -
|
| - @model.immutable
|
| - def need_to_trigger(self, try_jobs, now):
|
| - if self.unmet_prereqs(try_jobs):
|
| - return (self.builder_name, [])
|
| - name, steps = super(TryJobTriggeredOrNormalSteps,
|
| - self).need_to_trigger(try_jobs, now)
|
| -
|
| - # Remove any tests where that could still be triggered by the trigger bot.
|
| - steps = need_to_trigger(self.trigger_name, steps, try_jobs.itervalues())
|
| -
|
| - # Convert the trigger names to the triggered names.
|
| - steps = set(step for step, trigger
|
| - in self.steps.iteritems() if trigger in steps)
|
| -
|
| - # Add the trigger bot only steps and remove ones that have passed.
|
| - steps = steps.union(self.trigger_bot_steps)
|
| - steps = need_to_trigger(self.trigger_name, steps, try_jobs.itervalues())
|
| -
|
| - # If we want to use the triggered bot, convert the steps backs to their
|
| - # trigger name (where possible).
|
| - if self.use_triggered_bot:
|
| - # TODO(csharp): Remove this once the triggered bots should always handle
|
| - # retry (limit it to one attempt each to prevent too much breakage).
|
| - if any(try_job.builder == self.builder_name
|
| - for try_job in try_jobs.itervalues()):
|
| - return name, steps
|
| -
|
| - steps = set(self.steps.get(step, step) for step in steps)
|
| -
|
| - return name, steps
|
| -
|
| - @model.immutable
|
| - def waiting_for(self, try_jobs):
|
| - steps = waiting_for(self.builder_name, self.steps,
|
| - self._triggered_try_jobs(try_jobs))
|
| -
|
| - # Add the steps that can only run on the trigger bot and see what hasn't
|
| - # passed on the trigger bot yet.
|
| - steps = steps.union(self.trigger_bot_steps)
|
| -
|
| - steps = waiting_for(self.trigger_name, steps, try_jobs.itervalues())
|
| -
|
| - return self.trigger_name, steps
|
|
|