Make sure playbook and role repos are updated

These repos may be used by the job, but may not show up in the
dependency chain, or as required-projects for the job.  To make
sure that the executor always runs the most recent content,
add them to the list of projects to update before running a job.

Change-Id: Ia6c454e52f0ecb8b6d1b80124692ab7d63f81bd1
diff --git a/zuul/executor/server.py b/zuul/executor/server.py
index 657a063..3a4ddaf 100644
--- a/zuul/executor/server.py
+++ b/zuul/executor/server.py
@@ -734,11 +734,27 @@
                        (self.job.unique, self.jobdir.root))
         args = json.loads(self.job.arguments)
         tasks = []
+        projects = set()
+
+        # Make sure all projects used by the job are updated...
         for project in args['projects']:
             self.log.debug("Job %s: updating project %s" %
                            (self.job.unique, project))
             tasks.append(self.executor_server.update(
                 project['connection'], project['name']))
+            projects.add((project['connection'], project['name']))
+
+        # ...as well as all playbook and role projects.
+        repos = (args['pre_playbooks'] + args['playbooks'] +
+                 args['post_playbooks'] + args['roles'])
+        for repo in repos:
+            self.log.debug("Job %s: updating playbook or role %s" %
+                           (self.job.unique, repo))
+            key = (repo['connection'], repo['project'])
+            if key not in projects:
+                tasks.append(self.executor_server.update(*key))
+                projects.add(key)
+
         for task in tasks:
             task.wait()