support github pull request labels

Allow to match trigger on adding or removing github labels. Also
reporter can add or remove labels.

Change-Id: Id385b92590e252c283ba3ebe1ecfd33b34469a2e
Co-Authored-By: Jesse Keating <omgjlk@us.ibm.com>
diff --git a/tests/base.py b/tests/base.py
index d7bf467..382a593 100755
--- a/tests/base.py
+++ b/tests/base.py
@@ -557,6 +557,7 @@
         self.branch = branch
         self.upstream_root = upstream_root
         self.comments = []
+        self.labels = []
         self.statuses = {}
         self.updated_at = None
         self.head_sha = None
@@ -609,6 +610,64 @@
         }
         return (name, data)
 
+    def addLabel(self, name):
+        if name not in self.labels:
+            self.labels.append(name)
+            self._updateTimeStamp()
+            return self._getLabelEvent(name)
+
+    def removeLabel(self, name):
+        if name in self.labels:
+            self.labels.remove(name)
+            self._updateTimeStamp()
+            return self._getUnlabelEvent(name)
+
+    def _getLabelEvent(self, label):
+        name = 'pull_request'
+        data = {
+            'action': 'labeled',
+            'pull_request': {
+                'number': self.number,
+                'updated_at': self.updated_at,
+                'base': {
+                    'ref': self.branch,
+                    'repo': {
+                        'full_name': self.project
+                    }
+                },
+                'head': {
+                    'sha': self.head_sha
+                }
+            },
+            'label': {
+                'name': label
+            }
+        }
+        return (name, data)
+
+    def _getUnlabelEvent(self, label):
+        name = 'pull_request'
+        data = {
+            'action': 'unlabeled',
+            'pull_request': {
+                'number': self.number,
+                'updated_at': self.updated_at,
+                'base': {
+                    'ref': self.branch,
+                    'repo': {
+                        'full_name': self.project
+                    }
+                },
+                'head': {
+                    'sha': self.head_sha
+                }
+            },
+            'label': {
+                'name': label
+            }
+        }
+        return (name, data)
+
     def _getRepo(self):
         repo_path = os.path.join(self.upstream_root, self.project)
         return git.Repo(repo_path)
@@ -785,6 +844,14 @@
                 pr.head_sha == sha):
                 pr.setStatus(state, url, description, context)
 
+    def labelPull(self, project, pr_number, label):
+        pull_request = self.pull_requests[pr_number - 1]
+        pull_request.addLabel(label)
+
+    def unlabelPull(self, project, pr_number, label):
+        pull_request = self.pull_requests[pr_number - 1]
+        pull_request.removeLabel(label)
+
 
 class BuildHistory(object):
     def __init__(self, **kw):
diff --git a/tests/fixtures/layouts/labeling-github.yaml b/tests/fixtures/layouts/labeling-github.yaml
new file mode 100644
index 0000000..33ce993
--- /dev/null
+++ b/tests/fixtures/layouts/labeling-github.yaml
@@ -0,0 +1,29 @@
+- pipeline:
+    name: labels
+    description: Trigger on labels
+    manager: independent
+    trigger:
+      github:
+        - event: pull_request
+          action: labeled
+          label:
+            - 'test'
+        - event: pull_request
+          action: unlabeled
+          label:
+            - 'do not test'
+    success:
+      github:
+        label:
+          - 'tests passed'
+        unlabel:
+          - 'test'
+
+- job:
+    name: project-labels
+
+- project:
+    name: org/project
+    labels:
+      jobs:
+        - project-labels
diff --git a/tests/unit/test_github_driver.py b/tests/unit/test_github_driver.py
index 409d966..c7c5f3a 100644
--- a/tests/unit/test_github_driver.py
+++ b/tests/unit/test_github_driver.py
@@ -113,6 +113,31 @@
         self.assertEqual('SUCCESS',
                          self.getJobFromHistory('project-post').result)
 
+    @simple_layout('layouts/labeling-github.yaml', driver='github')
+    def test_labels(self):
+        A = self.fake_github.openFakePullRequest('org/project', 'master')
+        self.fake_github.emitEvent(A.addLabel('test'))
+        self.waitUntilSettled()
+        self.assertEqual(1, len(self.history))
+        self.assertEqual('project-labels', self.history[0].name)
+        self.assertEqual(['tests passed'], A.labels)
+
+        # test label removed
+        B = self.fake_github.openFakePullRequest('org/project', 'master')
+        B.addLabel('do not test')
+        self.fake_github.emitEvent(B.removeLabel('do not test'))
+        self.waitUntilSettled()
+        self.assertEqual(2, len(self.history))
+        self.assertEqual('project-labels', self.history[1].name)
+        self.assertEqual(['tests passed'], B.labels)
+
+        # test unmatched label
+        C = self.fake_github.openFakePullRequest('org/project', 'master')
+        self.fake_github.emitEvent(C.addLabel('other label'))
+        self.waitUntilSettled()
+        self.assertEqual(2, len(self.history))
+        self.assertEqual(['other label'], C.labels)
+
     @simple_layout('layouts/basic-github.yaml', driver='github')
     def test_git_https_url(self):
         """Test that git_ssh option gives git url with ssh"""