Report YAML parse errors

The SourceContext is extended to support storing a path, and we
define our own YamlLoader to use that to include a complete
file location in the yaml error message, rather than "unicode string".

The resulting report looks like:

Zuul encountered a syntax error while parsing its configuration in the
repo org/project on branch master.  The error was:

  while parsing a block collection
  in "org/project/.zuul.yaml@master", line 2, column 1:
    - job:
    ^
expected <block end>, but found '?'
  in "org/project/.zuul.yaml@master", line 3, column 1:
    foo: error
    ^

Change-Id: I51cec01e45adaad5abeda9bf665cc0358b45486f
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index ea7e85a..e566479 100644
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -227,6 +227,26 @@
         self.assertIn('syntax error', A.messages[1],
                       "A should have a syntax error reported")
 
+    def test_untrusted_yaml_error(self):
+        in_repo_conf = textwrap.dedent(
+            """
+            - job:
+            foo: error
+            """)
+
+        file_dict = {'.zuul.yaml': in_repo_conf}
+        A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
+                                           files=file_dict)
+        A.addApproval('code-review', 2)
+        self.fake_gerrit.addEvent(A.addApproval('approved', 1))
+        self.waitUntilSettled()
+
+        self.assertEqual(A.data['status'], 'NEW')
+        self.assertEqual(A.reported, 2,
+                         "A should report start and failure")
+        self.assertIn('syntax error', A.messages[1],
+                      "A should have a syntax error reported")
+
 
 class TestAnsible(AnsibleZuulTestCase):
     # A temporary class to hold new tests while others are disabled