Add pragma directive

This allows the user to override the implied branch matcher behavior.

Change-Id: I3ef43fd868988666cb01e8a6bb28552cc42151b4
diff --git a/tests/fixtures/config/pragma/git/common-config/zuul.yaml b/tests/fixtures/config/pragma/git/common-config/zuul.yaml
new file mode 100644
index 0000000..7a8b45e
--- /dev/null
+++ b/tests/fixtures/config/pragma/git/common-config/zuul.yaml
@@ -0,0 +1,53 @@
+- pipeline:
+    name: check
+    manager: independent
+    trigger:
+      gerrit:
+        - event: patchset-created
+    success:
+      gerrit:
+        Verified: 1
+    failure:
+      gerrit:
+        Verified: -1
+
+- pipeline:
+    name: gate
+    manager: dependent
+    post-review: True
+    trigger:
+      gerrit:
+        - event: comment-added
+          approval:
+            - Approved: 1
+    success:
+      gerrit:
+        Verified: 2
+        submit: true
+    failure:
+      gerrit:
+        Verified: -2
+    start:
+      gerrit:
+        Verified: 0
+    precedence: high
+
+- job:
+    name: base
+    parent: null
+
+- project:
+    name: common-config
+    check:
+      jobs: []
+    gate:
+      jobs:
+        - noop
+
+- project:
+    name: org/project
+    check:
+      jobs: []
+    gate:
+      jobs:
+        - noop
diff --git a/tests/fixtures/config/pragma/git/org_project/README b/tests/fixtures/config/pragma/git/org_project/README
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/tests/fixtures/config/pragma/git/org_project/README
@@ -0,0 +1 @@
+test
diff --git a/tests/fixtures/config/pragma/git/org_project/nopragma.yaml b/tests/fixtures/config/pragma/git/org_project/nopragma.yaml
new file mode 100644
index 0000000..95a306b
--- /dev/null
+++ b/tests/fixtures/config/pragma/git/org_project/nopragma.yaml
@@ -0,0 +1,2 @@
+- job:
+    name: test-job
diff --git a/tests/fixtures/config/pragma/git/org_project/playbooks/test-job.yaml b/tests/fixtures/config/pragma/git/org_project/playbooks/test-job.yaml
new file mode 100644
index 0000000..f679dce
--- /dev/null
+++ b/tests/fixtures/config/pragma/git/org_project/playbooks/test-job.yaml
@@ -0,0 +1,2 @@
+- hosts: all
+  tasks: []
diff --git a/tests/fixtures/config/pragma/git/org_project/pragma.yaml b/tests/fixtures/config/pragma/git/org_project/pragma.yaml
new file mode 100644
index 0000000..89852b0
--- /dev/null
+++ b/tests/fixtures/config/pragma/git/org_project/pragma.yaml
@@ -0,0 +1,5 @@
+- pragma:
+    implied-branch-matchers: False
+
+- job:
+    name: test-job
diff --git a/tests/fixtures/config/pragma/main.yaml b/tests/fixtures/config/pragma/main.yaml
new file mode 100644
index 0000000..208e274
--- /dev/null
+++ b/tests/fixtures/config/pragma/main.yaml
@@ -0,0 +1,8 @@
+- tenant:
+    name: tenant-one
+    source:
+      gerrit:
+        config-projects:
+          - common-config
+        untrusted-projects:
+          - org/project
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index 70b898e..b9ae04b 100755
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -1907,6 +1907,57 @@
                          "B should not fail because of timeout limit")
 
 
+class TestPragma(ZuulTestCase):
+    tenant_config_file = 'config/pragma/main.yaml'
+
+    def test_no_pragma(self):
+        self.create_branch('org/project', 'stable')
+        with open(os.path.join(FIXTURE_DIR,
+                               'config/pragma/git/',
+                               'org_project/nopragma.yaml')) as f:
+            config = f.read()
+        file_dict = {'.zuul.yaml': config}
+        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.fake_gerrit.addEvent(A.getChangeMergedEvent())
+        self.waitUntilSettled()
+
+        # This is an untrusted repo with 2 branches, so it should have
+        # an implied branch matcher for the job.
+        tenant = self.sched.abide.tenants.get('tenant-one')
+        jobs = tenant.layout.getJobs('test-job')
+        self.assertEqual(len(jobs), 1)
+        for job in tenant.layout.getJobs('test-job'):
+            self.assertIsNotNone(job.branch_matcher)
+
+    def test_pragma(self):
+        self.create_branch('org/project', 'stable')
+        with open(os.path.join(FIXTURE_DIR,
+                               'config/pragma/git/',
+                               'org_project/pragma.yaml')) as f:
+            config = f.read()
+        file_dict = {'.zuul.yaml': config}
+        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.fake_gerrit.addEvent(A.getChangeMergedEvent())
+        self.waitUntilSettled()
+
+        # This is an untrusted repo with 2 branches, so it would
+        # normally have an implied branch matcher, but our pragma
+        # overrides it.
+        tenant = self.sched.abide.tenants.get('tenant-one')
+        jobs = tenant.layout.getJobs('test-job')
+        self.assertEqual(len(jobs), 1)
+        for job in tenant.layout.getJobs('test-job'):
+            self.assertIsNone(job.branch_matcher)
+
+
 class TestBaseJobs(ZuulTestCase):
     tenant_config_file = 'config/base-jobs/main.yaml'