Bug 1307326 - consider only tasks with rank greater than 0. r=rail THUNDERBIRD_50_0b2_BUILD1 THUNDERBIRD_50_0b2_RELEASE
authorMihai Tabara <mtabara@mozilla.com>
Fri, 14 Oct 2016 16:08:50 +0100
changeset 7260 78748858da198ca43c54765522a91ecebee0e075
parent 7259 5e27e3753eff6ac11631192797b35a942e23f783
child 7262 3382d429d053fe47aab65e236e365e63e71606d5
push id164
push userbmo:mtabara@mozilla.com
push dateFri, 14 Oct 2016 15:10:40 +0000
reviewersrail
bugs1307326
Bug 1307326 - consider only tasks with rank greater than 0. r=rail MozReview-Commit-ID: 4lUJZ0YFnFq
buildfarm/release/release-runner.py
lib/python/kickoff/build_status.py
lib/python/kickoff/test/test_build_status.py
--- 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'}