Merge "Fix missing source connections on merger" into feature/zuulv3
diff --git a/requirements.txt b/requirements.txt
index aeaabfa..e4f0212 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@
 
 # pull from master until https://github.com/sigmavirus24/github3.py/pull/671
 # is in a release
--e git://github.com/sigmavirus24/github3.py.git@develop#egg=Github3.py
+-e git+https://github.com/sigmavirus24/github3.py.git@develop#egg=Github3.py
 PyYAML>=3.1.0
 Paste
 WebOb>=1.2.3
diff --git a/zuul/ansible/callback/zuul_stream.py b/zuul/ansible/callback/zuul_stream.py
index e6b3461..2b4d7ef 100644
--- a/zuul/ansible/callback/zuul_stream.py
+++ b/zuul/ansible/callback/zuul_stream.py
@@ -40,6 +40,32 @@
         yield buff
 
 
+def zuul_filter_result(result):
+    """Remove keys from shell/command output.
+
+    Zuul streams stdout into the log above, so including stdout and stderr
+    in the result dict that ansible displays in the logs is duplicate
+    noise. We keep stdout in the result dict so that other callback plugins
+    like ARA could also have access to it. But drop them here.
+
+    Remove changed so that we don't show a bunch of "changed" titles
+    on successful shell tasks, since that doesn't make sense from a Zuul
+    POV. The super class treats missing "changed" key as False.
+
+    Remove cmd because most of the script content where people want to
+    see the script run is run with -x. It's possible we may want to revist
+    this to be smarter about when we remove it - like, only remove it
+    if it has an embedded newline - so that for normal 'simple' uses
+    of cmd it'll echo what the command was for folks.
+    """
+
+    for key in ('changed', 'cmd',
+                'stderr', 'stderr_lines',
+                'stdout', 'stdout_lines'):
+        result.pop(key, None)
+    return result
+
+
 class CallbackModule(default.CallbackModule):
 
     '''
@@ -103,3 +129,37 @@
                         target=self._read_log, args=(host, ip))
                     p.daemon = True
                     p.start()
+
+    def v2_runner_on_failed(self, result, ignore_errors=False):
+        if result._task.action in ('command', 'shell'):
+            zuul_filter_result(result._result)
+        super(CallbackModule, self).v2_runner_on_failed(
+            result, ignore_errors=ignore_errors)
+
+    def v2_runner_on_ok(self, result):
+        if result._task.action in ('command', 'shell'):
+            zuul_filter_result(result._result)
+        else:
+            return super(CallbackModule, self).v2_runner_on_ok(result)
+
+        if self._play.strategy == 'free':
+            return super(CallbackModule, self).v2_runner_on_ok(result)
+
+        delegated_vars = result._result.get('_ansible_delegated_vars', None)
+
+        if delegated_vars:
+            msg = "ok: [{host} -> {delegated_host} %s]".format(
+                host=result._host.get_name(),
+                delegated_host=delegated_vars['ansible_host'])
+        else:
+            msg = "ok: [{host}]".format(host=result._host.get_name())
+
+        if result._task.loop and 'results' in result._result:
+            self._process_items(result)
+        else:
+            msg += "Ran in {delta} seconds. Start: {start} end: {end}".format(
+                **result._result)
+
+        self._handle_warnings(result._result)
+
+        self._display.display(msg)