Add support for requiring github pr head status

When creating a github pull request change object, the statuses of the
head commit are fetched, and the latest status of each user and context
set is appended into a list of statuses. The string is
'user:context:state', where state can be success, error, or failure.
Context is freeform, and the user is the login of the entity that set
the status.

Tests have been added to validate that github based requirements on
pipelines are honored.

Change-Id: I45abbd6cbddd36b8491bdf9bb8d545216537ad2f
Signed-off-by: Jesse Keating <omgjlk@us.ibm.com>
diff --git a/tests/unit/test_github_driver.py b/tests/unit/test_github_driver.py
index f918218..f287790 100644
--- a/tests/unit/test_github_driver.py
+++ b/tests/unit/test_github_driver.py
@@ -253,10 +253,14 @@
         A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
         self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
         self.waitUntilSettled()
-        self.assertIn('check', A.statuses)
-        check_status = A.statuses['check']
+        # We should have a status container for the head sha
+        self.assertIn(A.head_sha, A.statuses.keys())
+        # We should only have one status for the head sha
+        self.assertEqual(1, len(A.statuses[A.head_sha]))
+        check_status = A.statuses[A.head_sha][0]
         check_url = ('http://zuul.example.com/status/#%s,%s' %
                      (A.number, A.head_sha))
+        self.assertEqual('check', check_status['context'])
         self.assertEqual('Standard check', check_status['description'])
         self.assertEqual('pending', check_status['state'])
         self.assertEqual(check_url, check_status['url'])
@@ -265,8 +269,12 @@
         self.executor_server.hold_jobs_in_build = False
         self.executor_server.release()
         self.waitUntilSettled()
-        check_status = A.statuses['check']
-        self.assertEqual('Standard check', check_status['description'])
+        # We should only have two statuses for the head sha
+        self.assertEqual(2, len(A.statuses[A.head_sha]))
+        check_status = A.statuses[A.head_sha][0]
+        check_url = ('http://zuul.example.com/status/#%s,%s' %
+                     (A.number, A.head_sha))
+        self.assertEqual('check', check_status['context'])
         self.assertEqual('success', check_status['state'])
         self.assertEqual(check_url, check_status['url'])
         self.assertEqual(1, len(A.comments))
@@ -278,7 +286,7 @@
         self.fake_github.emitEvent(
             A.getCommentAddedEvent('reporting check'))
         self.waitUntilSettled()
-        self.assertNotIn('reporting', A.statuses)
+        self.assertEqual(2, len(A.statuses[A.head_sha]))
         # comments increased by one for the start message
         self.assertEqual(2, len(A.comments))
         self.assertThat(A.comments[1],
@@ -286,7 +294,11 @@
         self.executor_server.hold_jobs_in_build = False
         self.executor_server.release()
         self.waitUntilSettled()
-        self.assertNotIn('reporting', A.statuses)
+        # pipeline reports success status
+        self.assertEqual(3, len(A.statuses[A.head_sha]))
+        report_status = A.statuses[A.head_sha][0]
+        self.assertEqual('reporting', report_status['context'])
+        self.assertEqual('success', report_status['state'])
         self.assertEqual(2, len(A.comments))
 
     @simple_layout('layouts/merging-github.yaml', driver='github')