Bug 1307326 - consider only tasks with rank greater than 0. r=rail
MozReview-Commit-ID: 4lUJZ0YFnFq
--- a/buildfarm/release/release-runner.py
+++ b/buildfarm/release/release-runner.py
@@ -374,17 +374,17 @@ def main(options):
ship_it_product_name = release['product']
tc_product_name = branchConfig['stage_product'][ship_it_product_name]
# XXX: Doesn't work with neither Fennec nor Thunderbird
platforms = branchConfig['release_platforms']
try:
if not are_en_us_builds_completed(index, release_name=release['name'], submitted_at=release['submittedAt'],
branch=release['branchShortName'], revision=release['mozillaRevision'],
- tc_product_name=tc_product_name, platforms=platforms):
+ tc_product_name=tc_product_name, platforms=platforms, queue=queue):
log.info('Builds are not completed yet, skipping release "%s" for now', release['name'])
rr.update_status(release, 'Waiting for builds to be completed')
continue
log.info('Every build is completed for release: %s', release['name'])
graph_id = slugId()
rr.update_status(release, 'Generating task graph')
--- a/lib/python/kickoff/build_status.py
+++ b/lib/python/kickoff/build_status.py
@@ -6,22 +6,25 @@ from kickoff import task_for_revision
import logging
log = logging.getLogger(__name__)
_BUILD_WATCHERS = {}
-# TODO: Bug 1300147. Avoid having 7 parameters by using a release object that contains only what's needed.
-def are_en_us_builds_completed(index, release_name, submitted_at, branch, revision, tc_product_name, platforms):
+# TODO: Bug 1300147. Avoid having 7 parameters by using a release object that
+# contains only what's needed.
+def are_en_us_builds_completed(index, release_name, submitted_at, branch,
+ revision, tc_product_name, platforms, queue):
try:
watcher = _BUILD_WATCHERS[release_name]
except KeyError:
- watcher = EnUsBuildsWatcher(index, release_name, submitted_at, branch, revision, tc_product_name, platforms)
+ watcher = EnUsBuildsWatcher(index, release_name, submitted_at, branch,
+ revision, tc_product_name, platforms, queue)
_BUILD_WATCHERS[release_name] = watcher
log.debug('New watcher created for "%s"', release_name)
result = watcher.are_builds_completed()
if result is True:
del _BUILD_WATCHERS[release_name]
log.debug('Builds for "%s" are completed. Watcher deleted', release_name)
@@ -32,24 +35,26 @@ def are_en_us_builds_completed(index, re
class LoggedError(Exception):
def __init__(self, message):
log.exception(message)
Exception.__init__(self, message)
class EnUsBuildsWatcher:
# TODO: Bug 1300147 as well
- def __init__(self, index, release_name, submitted_at, branch, revision, tc_product_name, platforms):
+ def __init__(self, index, release_name, submitted_at, branch, revision,
+ tc_product_name, platforms, queue):
self.taskcluster_index = index
self.taskcluster_product_name = tc_product_name
self.release_name = release_name
self.branch = branch
self.revision = revision
self.task_per_platform = {p: None for p in platforms}
+ self.queue = queue
self._timeout_watcher = TimeoutWatcher(start_timestamp=submitted_at)
def are_builds_completed(self):
if self._timeout_watcher.timed_out:
raise TimeoutWatcher.TimeoutError(self.release_name, self._timeout_watcher.start_timestamp)
self._fetch_completed_tasks()
@@ -62,16 +67,23 @@ class EnUsBuildsWatcher:
for platform in platforms_with_no_task:
try:
# Tasks are always completed if they are referenced in the index
# https://docs.taskcluster.net/reference/core/index
task_id = task_for_revision(
self.taskcluster_index, self.branch, self.revision, self.taskcluster_product_name, platform
)['taskId']
+ # Bug 1307326 - consider only tasks indexed with rank > 0
+ task = self.queue.task(task_id)
+ rank = task["extra"]["index"]["rank"]
+ if rank == 0:
+ log.debug("Ignoring task %s because the rank is set to 0",
+ task_id)
+ continue
except TaskclusterRestFailure:
log.debug('Task for platform "%s" is not yet created for release "%s"', platform, self.release_name)
continue
log.debug('Task "%s" was found for release "%s" and platform "%s"', task_id, self.release_name, platform)
self.task_per_platform[platform] = task_id
@property
--- a/lib/python/kickoff/test/test_build_status.py
+++ b/lib/python/kickoff/test/test_build_status.py
@@ -9,101 +9,110 @@ from kickoff.build_status import are_en_
class BuildsCompletedBase(unittest.TestCase):
def setUp(self):
self.index = MagicMock()
self.branch = 'mozilla-release'
self.revision = 'abcdef123456'
self.tc_product_name = 'firefox'
self.platforms = ('linux', 'win32', 'win64')
+ self.queue = MagicMock()
self.now = datetime.now(tz.tzutc())
self.submitted_at = '{}+00:00'.format(self.now.isoformat())
class AreEnUsBuildsCompletedTest(BuildsCompletedBase):
# Each test in this suite defines a different release_name. That's because
# tests are multi-threaded and there are collisions with the internal of
# memoization of are_en_us_builds_completed()
def test_returns_true_when_everything_is_ready(self):
self.index.findTask.side_effect = SideEffects.everything_has_an_id
release_name = 'Firefox-32.0b1-build1'
self.assertTrue(are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
))
def test_returns_false_if_one_task_is_missing(self):
self.index.findTask.side_effect = SideEffects.linux_has_no_task
release_name = 'Firefox-32.0b1-build2'
self.assertFalse(are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
))
def test_stores_results_of_the_previous_call(self):
self.index.findTask.side_effect = SideEffects.linux_has_no_task
release_name = 'Firefox-32.0b1-build5'
are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
)
self.assertEqual(self.index.findTask.call_count, len(self.platforms))
are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
)
self.assertEqual(self.index.findTask.call_count, len(self.platforms) + 1)
def test_creates_new_watcher_if_new_release_name(self):
self.index.findTask.side_effect = SideEffects.linux_has_no_task
release_name = 'Firefox-32.0b1-build6'
are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
)
self.assertEqual(self.index.findTask.call_count, len(self.platforms))
release_name = 'Firefox-32.0b1-build99'
are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
)
self.assertEqual(self.index.findTask.call_count, len(self.platforms) * 2)
def test_delete_watcher_if_all_builds_are_completed(self):
self.index.findTask.side_effect = SideEffects.everything_has_an_id
release_name = 'Firefox-32.0b1-build7'
are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
)
self.assertEqual(self.index.findTask.call_count, len(self.platforms))
are_en_us_builds_completed(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms,
+ self.queue
)
self.assertEqual(self.index.findTask.call_count, len(self.platforms) * 2)
class EnUsBuildsWatcherTest(BuildsCompletedBase):
def setUp(self):
BuildsCompletedBase.setUp(self)
release_name = 'Firefox-46.0b8-build1'
self.watcher = EnUsBuildsWatcher(
self.index, release_name, self.submitted_at, self.branch,
- self.revision, self.tc_product_name, self.platforms
+ self.revision, self.tc_product_name, self.platforms, self.queue
)
def test_returns_true_when_everything_is_ready(self):
self.index.findTask.side_effect = SideEffects.everything_has_an_id
self.assertTrue(self.watcher.are_builds_completed())
def test_returns_false_if_one_task_is_missing(self):
self.index.findTask.side_effect = SideEffects.linux_has_no_task
@@ -125,19 +134,39 @@ class EnUsBuildsWatcherTest(BuildsComple
with patch('kickoff.build_status.TimeoutWatcher._now', return_value=less_than_one_day_after_submission):
self.watcher.are_builds_completed()
one_day_after_submission = self.now + timedelta(days=1, seconds=1)
with patch('kickoff.build_status.TimeoutWatcher._now', return_value=one_day_after_submission):
with self.assertRaises(TimeoutWatcher.TimeoutError):
self.watcher.are_builds_completed()
+ def test_tcbuild_finished_but_no_buildbot(self):
+ self.index.findTask.side_effect = SideEffects.everything_has_an_id
+ self.queue.task.side_effect = SideEffects.tc_tier2_build_has_rank_0
+
+ self.assertFalse(self.watcher.are_builds_completed())
+ self.assertEqual(self.index.findTask.call_count, len(self.platforms))
+
+ self.watcher.are_builds_completed()
+ self.assertEqual(self.index.findTask.call_count, len(self.platforms) * 2)
+
class SideEffects:
@staticmethod
def everything_has_an_id(_):
return {'taskId': 'anId'}
@staticmethod
+ def tc_tier2_build_has_rank_0(_):
+ return {
+ 'extra': {
+ 'index': {
+ 'rank': 0,
+ }
+ }
+ }
+
+ @staticmethod
def linux_has_no_task(namespace):
if 'linux' in namespace:
raise taskcluster.exceptions.TaskclusterRestFailure('place', 'hold', 'ers')
return {'taskId': 'anId'}