Merge "Revert "Make job registration with labels optional""
diff --git a/other-requirements.txt b/bindep.txt
similarity index 100%
rename from other-requirements.txt
rename to bindep.txt
diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py
index 628775d..335f987 100755
--- a/tests/test_scheduler.py
+++ b/tests/test_scheduler.py
@@ -4267,6 +4267,25 @@
         self.waitUntilSettled()
         self.assertEqual(self.history[-1].changes, '3,2 2,1 1,2')
 
+    def test_crd_check_unknown(self):
+        "Test unknown projects in independent pipeline"
+        self.init_repo("org/unknown")
+        A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
+        B = self.fake_gerrit.addFakeChange('org/unknown', 'master', 'D')
+        # A Depends-On: B
+        A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
+            A.subject, B.data['id'])
+
+        # Make sure zuul has seen an event on B.
+        self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
+        self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+        self.waitUntilSettled()
+
+        self.assertEqual(A.data['status'], 'NEW')
+        self.assertEqual(A.reported, 1)
+        self.assertEqual(B.data['status'], 'NEW')
+        self.assertEqual(B.reported, 0)
+
     def test_crd_cycle_join(self):
         "Test an updated change creates a cycle"
         A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
diff --git a/zuul/ansible/library/zuul_console.py b/zuul/ansible/library/zuul_console.py
index 78f3249..e70dac8 100644
--- a/zuul/ansible/library/zuul_console.py
+++ b/zuul/ansible/library/zuul_console.py
@@ -60,28 +60,13 @@
 class Server(object):
     def __init__(self, path, port):
         self.path = path
-        s = None
-        for res in socket.getaddrinfo(None, port, socket.AF_UNSPEC,
-                                      socket.SOCK_STREAM, 0,
-                                      socket.AI_PASSIVE):
-            af, socktype, proto, canonname, sa = res
-            try:
-                s = socket.socket(af, socktype, proto)
-                s.setsockopt(socket.SOL_SOCKET,
-                             socket.SO_REUSEADDR, 1)
-            except socket.error:
-                s = None
-                continue
-            try:
-                s.bind(sa)
-                s.listen(1)
-            except socket.error:
-                s.close()
-                s = None
-                continue
-            break
-        if s is None:
-            sys.exit(1)
+
+        s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+        s.setsockopt(socket.SOL_SOCKET,
+                     socket.SO_REUSEADDR, 1)
+        s.bind(('::', port))
+        s.listen(1)
+
         self.socket = s
 
     def accept(self):
@@ -170,7 +155,7 @@
 
 
 def test():
-    s = Server('/tmp/console.html', 8088)
+    s = Server('/tmp/console.html', 19885)
     s.run()
 
 
@@ -178,7 +163,7 @@
     module = AnsibleModule(
         argument_spec=dict(
             path=dict(default='/tmp/console.html'),
-            port=dict(default=8088, type='int'),
+            port=dict(default=19885, type='int'),
         )
     )
 
diff --git a/zuul/launcher/ansiblelaunchserver.py b/zuul/launcher/ansiblelaunchserver.py
index 6cecb65..975a842 100644
--- a/zuul/launcher/ansiblelaunchserver.py
+++ b/zuul/launcher/ansiblelaunchserver.py
@@ -547,6 +547,11 @@
 
 
 class NodeWorker(object):
+    retry_args = dict(register='task_result',
+                      until='task_result.rc == 0',
+                      retries=3,
+                      delay=30)
+
     def __init__(self, config, jobs, builds, sites, name, host,
                  description, labels, manager_name, zmq_send_queue,
                  termination_queue, keep_jobdir, callback_dir,
@@ -883,7 +888,7 @@
             data = {
                 'manager': self.manager_name,
                 'number': job.unique,
-                'url': 'telnet://%s:8088' % self.host,
+                'url': 'telnet://%s:19885' % self.host,
             }
             job.sendWorkData(json.dumps(data))
             job.sendWorkStatus(0, 100)
@@ -955,6 +960,8 @@
                                 dest=os.path.join(scproot, '_zuul_ansible'))
                 task = dict(copy=copyargs,
                             delegate_to='127.0.0.1')
+                # This is a local copy and should not fail, so does
+                # not need a retry stanza.
                 tasks.append(task)
 
                 # Fetch the console log from the remote host.
@@ -976,10 +983,12 @@
             task = dict(synchronize=syncargs)
             if not scpfile.get('copy-after-failure'):
                 task['when'] = 'success'
+            task.update(self.retry_args)
             tasks.append(task)
 
             task = self._makeSCPTaskLocalAction(
                 site, scpfile, scproot, parameters)
+            task.update(self.retry_args)
             tasks.append(task)
         return tasks
 
@@ -1047,6 +1056,7 @@
             syncargs['rsync_opts'] = rsync_opts
         task = dict(synchronize=syncargs,
                     when='success')
+        task.update(self.retry_args)
         tasks.append(task)
         task = dict(shell='lftp -f %s' % ftpscript,
                     when='success',
@@ -1069,6 +1079,7 @@
             script.write('open %s\n' % site['host'])
             script.write('user %s %s\n' % (site['user'], site['pass']))
             script.write('mirror -R %s %s\n' % (ftpsource, ftptarget))
+        task.update(self.retry_args)
         tasks.append(task)
         return tasks
 
@@ -1182,7 +1193,8 @@
             task = dict(file=dict(path='/tmp/console.html', state='absent'))
             main_block.append(task)
 
-            task = dict(zuul_console=dict(path='/tmp/console.html', port=8088))
+            task = dict(zuul_console=dict(path='/tmp/console.html',
+                                          port=19885))
             main_block.append(task)
 
             task = dict(file=dict(path=parameters['WORKSPACE'],
@@ -1243,7 +1255,8 @@
             config.write('[defaults]\n')
             config.write('hostfile = %s\n' % jobdir.inventory)
             config.write('keep_remote_files = True\n')
-            config.write('local_tmp = %s/.ansible/tmp\n' % jobdir.root)
+            config.write('local_tmp = %s/.ansible/local_tmp\n' % jobdir.root)
+            config.write('remote_tmp = %s/.ansible/remote_tmp\n' % jobdir.root)
             config.write('private_key_file = %s\n' % self.private_key_file)
             config.write('retry_files_enabled = False\n')
             config.write('log_path = %s\n' % jobdir.ansible_log)
diff --git a/zuul/merger/merger.py b/zuul/merger/merger.py
index 94933de..0c9f168 100644
--- a/zuul/merger/merger.py
+++ b/zuul/merger/merger.py
@@ -182,6 +182,13 @@
         repo = self.createRepoObject()
         self.log.debug("Updating repository %s" % self.local_path)
         origin = repo.remotes.origin
+        if repo.git.version_info[:2] < (1, 9):
+            # Before 1.9, 'git fetch --tags' did not include the
+            # behavior covered by 'git --fetch', so we run both
+            # commands in that case.  Starting with 1.9, 'git fetch
+            # --tags' is all that is necessary.  See
+            # https://github.com/git/git/blob/master/Documentation/RelNotes/1.9.0.txt#L18-L20
+            origin.fetch()
         origin.fetch(tags=True)
 
 
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index b974762..b52931e 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -625,12 +625,12 @@
     def setMerger(self, merger):
         self.merger = merger
 
-    def getProject(self, name, create_foreign=False):
+    def getProject(self, name):
         self.layout_lock.acquire()
         p = None
         try:
             p = self.layout.projects.get(name)
-            if p is None and create_foreign:
+            if p is None:
                 self.log.info("Registering foreign project: %s" % name)
                 p = Project(name, foreign=True)
                 self.layout.projects[name] = p
diff --git a/zuul/source/gerrit.py b/zuul/source/gerrit.py
index 73cf726..463f315 100644
--- a/zuul/source/gerrit.py
+++ b/zuul/source/gerrit.py
@@ -243,11 +243,7 @@
 
         if 'project' not in data:
             raise exceptions.ChangeNotFound(change.number, change.patchset)
-        # If updated changed came as a dependent on
-        # and its project is not defined,
-        # then create a 'foreign' project for it in layout
-        change.project = self.sched.getProject(data['project'],
-                                               create_foreign=bool(history))
+        change.project = self.sched.getProject(data['project'])
         change.branch = data['branch']
         change.url = data['url']
         max_ps = 0