Remove pipeline.getJobs

Previously, building the job tree for a change was the responsibility
of the Pipeline class.  However, with dynamic reconfiguration, that
now lies with QueueItem.  Remove the remaining use of getJobs from
the Pipeline class.  Most of the other invocations of this method
were updated in a previous change.

In doing so, attempt to make the full static reconfiguration handling
compatible with the new dynamic reconfiguration.  This is, as yet,
untested.

Change-Id: I0e40ea36e4834b939a17925f1bb9fd9fa782f07a
diff --git a/zuul/manager/__init__.py b/zuul/manager/__init__.py
index 181b599..fa4986b 100644
--- a/zuul/manager/__init__.py
+++ b/zuul/manager/__init__.py
@@ -242,6 +242,21 @@
                                (item.change, change_queue))
                 change_queue.enqueueItem(item)
 
+                # Get an updated copy of the layout if necessary.
+                # This will return one of the following:
+                # 1) An existing layout from the item ahead or pipeline.
+                # 2) A newly created layout from the cached pipeline
+                #    layout config plus the previously returned
+                #    in-repo files stored in the buildset.
+                # 3) None in the case that a fetch of the files from
+                #    the merger is still pending.
+                item.current_build_set.layout = self.getLayout(item)
+
+                # Rebuild the frozen job tree from the new layout, if
+                # we have one.  If not, it will be built later.
+                if item.current_build_set.layout:
+                    item.freezeJobTree()
+
                 # Re-set build results in case any new jobs have been
                 # added to the tree.
                 for build in item.current_build_set.getBuilds():
@@ -664,7 +679,7 @@
     def _reportItem(self, item):
         self.log.debug("Reporting change %s" % item.change)
         ret = True  # Means error as returned by trigger.report
-        if not self.pipeline.getJobs(item):
+        if not item.getJobs():
             # We don't send empty reports with +1,
             # and the same for -1's (merge failures or transient errors)
             # as they cannot be followed by +1's
diff --git a/zuul/model.py b/zuul/model.py
index fd2f626..33304f3 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -145,16 +145,6 @@
         tree = self.job_trees.get(project)
         return tree
 
-    def getJobs(self, item):
-        # TODOv3(jeblair): can this be removed in favor of the frozen
-        # job list in item?
-        if not item.live:
-            return []
-        tree = self.getJobTree(item.change.project)
-        if not tree:
-            return []
-        return item.change.filterJobs(tree.getJobs())
-
     def _findJobsToRun(self, job_trees, item, mutex):
         torun = []
         for tree in job_trees:
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index eca7c54..516be80 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -502,16 +502,17 @@
                     project_name = item.change.project.name
                     item.change.project = new_pipeline.source.getProject(
                         project_name)
-                    item_jobs = new_pipeline.getJobs(item)
-                    for build in item.current_build_set.getBuilds():
-                        job = tenant.layout.jobs.get(build.job.name)
-                        if job and job in item_jobs:
-                            build.job = job
-                        else:
-                            item.removeBuild(build)
-                            builds_to_cancel.append(build)
-                    if not new_pipeline.manager.reEnqueueItem(item,
-                                                              last_head):
+                    if new_pipeline.manager.reEnqueueItem(item,
+                                                          last_head):
+                        new_jobs = item.getJobs()
+                        for build in item.current_build_set.getBuilds():
+                            job = item.layout.getJob(build.job.name)
+                            if job and job in new_jobs:
+                                build.job = job
+                            else:
+                                item.removeBuild(build)
+                                builds_to_cancel.append(build)
+                    else:
                         items_to_remove.append(item)
             for item in items_to_remove:
                 for build in item.current_build_set.getBuilds():