summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames E. Blair <jim@acmegating.com>2022-10-10 10:53:14 -0700
committerJames E. Blair <jim@acmegating.com>2022-10-10 10:54:33 -0700
commit7aba198bedcf2080f26e2498f834002971175c33 (patch)
tree9586c69102e0a0022d2c4a4a5f14bc227d90ffcf
parent51aeec13e682e2341d6c65379ef558bcb4d62ee0 (diff)
downloadzuul-7aba198bedcf2080f26e2498f834002971175c33.tar.gz
Add "draft" github pipeline requirement
This adds the "draft" PR status as a pipeline requirement to the GitHub driver. It is already used implicitly in dependent pipelines, but this will allow it to be added explicitly to other pipelines (for example, check). This also fixes some minor copy/pasta errors in debug messages related to github pipeline requirements. Change-Id: I05f8f61aee251af24c1479274904b429baedb29d
-rw-r--r--doc/source/drivers/github.rst6
-rw-r--r--releasenotes/notes/github-draft-requirement-29b4f44229bb1af1.yaml6
-rw-r--r--tests/fixtures/layouts/requirements-github.yaml48
-rw-r--r--tests/unit/test_github_requirements.py40
-rw-r--r--zuul/driver/github/githubmodel.py42
-rw-r--r--zuul/driver/github/githubsource.py4
6 files changed, 135 insertions, 11 deletions
diff --git a/doc/source/drivers/github.rst b/doc/source/drivers/github.rst
index 9ca7a1f38..9e2763d49 100644
--- a/doc/source/drivers/github.rst
+++ b/doc/source/drivers/github.rst
@@ -551,6 +551,12 @@ enqueued into the pipeline.
.. TODO: this could probably be expanded upon -- under what
circumstances might this happen with github
+ .. attr:: draft
+
+ A boolean value (``true`` or ``false``) that indicates whether
+ or not the change must be marked as a draft in GitHub in order
+ to be enqueued.
+
.. attr:: status
A string value that corresponds with the status of the pull
diff --git a/releasenotes/notes/github-draft-requirement-29b4f44229bb1af1.yaml b/releasenotes/notes/github-draft-requirement-29b4f44229bb1af1.yaml
new file mode 100644
index 000000000..1e3493080
--- /dev/null
+++ b/releasenotes/notes/github-draft-requirement-29b4f44229bb1af1.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ The GitHub driver now supports specifying the `draft` status of a
+ PR as a pipeline requirement.
+ See :attr:`pipeline.require.<github source>.draft`.
diff --git a/tests/fixtures/layouts/requirements-github.yaml b/tests/fixtures/layouts/requirements-github.yaml
index 9e376b8b6..51870e5db 100644
--- a/tests/fixtures/layouts/requirements-github.yaml
+++ b/tests/fixtures/layouts/requirements-github.yaml
@@ -286,6 +286,34 @@
comment: true
- pipeline:
+ name: require_draft
+ manager: independent
+ require:
+ github:
+ draft: true
+ trigger:
+ github:
+ - event: pull_request
+ action: changed
+ success:
+ github:
+ comment: true
+
+- pipeline:
+ name: reject_draft
+ manager: independent
+ reject:
+ github:
+ draft: true
+ trigger:
+ github:
+ - event: pull_request
+ action: changed
+ success:
+ github:
+ comment: true
+
+- pipeline:
name: require_label
manager: independent
require:
@@ -390,6 +418,14 @@
name: project16-require-check-run
run: playbooks/project16-require-check-run.yaml
+- job:
+ name: project17-require-draft
+ run: playbooks/project17-require-draft.yaml
+
+- job:
+ name: project18-reject-draft
+ run: playbooks/project18-reject-draft.yaml
+
- project:
name: org/project1
pipeline:
@@ -494,3 +530,15 @@
require_check_run:
jobs:
- project16-require-check-run
+
+- project:
+ name: org/project17
+ require_draft:
+ jobs:
+ - project17-require-draft
+
+- project:
+ name: org/project18
+ reject_draft:
+ jobs:
+ - project18-reject-draft
diff --git a/tests/unit/test_github_requirements.py b/tests/unit/test_github_requirements.py
index 0e2d2b7d5..ef1f75944 100644
--- a/tests/unit/test_github_requirements.py
+++ b/tests/unit/test_github_requirements.py
@@ -503,6 +503,46 @@ class TestGithubRequirements(ZuulTestCase):
self.assertEqual(len(self.history), 1)
@simple_layout('layouts/requirements-github.yaml', driver='github')
+ def test_require_draft(self):
+
+ A = self.fake_github.openFakePullRequest('org/project17', 'master',
+ 'A', draft=True)
+ # A sync event that we will keep submitting to trigger
+ sync = A.getPullRequestSynchronizeEvent()
+ self.fake_github.emitEvent(sync)
+ self.waitUntilSettled()
+
+ # PR is a draft, should enqueue
+ self.assertEqual(len(self.history), 1)
+
+ # Make the PR not a draft
+ A.draft = False
+ self.fake_github.emitEvent(sync)
+ self.waitUntilSettled()
+ # PR is not a draft, should not enqueue
+ self.assertEqual(len(self.history), 1)
+
+ @simple_layout('layouts/requirements-github.yaml', driver='github')
+ def test_reject_draft(self):
+
+ A = self.fake_github.openFakePullRequest('org/project18', 'master',
+ 'A', draft=True)
+ # A sync event that we will keep submitting to trigger
+ sync = A.getPullRequestSynchronizeEvent()
+ self.fake_github.emitEvent(sync)
+ self.waitUntilSettled()
+
+ # PR is a draft, should not enqueue
+ self.assertEqual(len(self.history), 0)
+
+ # Make the PR not a draft
+ A.draft = False
+ self.fake_github.emitEvent(sync)
+ self.waitUntilSettled()
+ # PR is not a draft, should enqueue
+ self.assertEqual(len(self.history), 1)
+
+ @simple_layout('layouts/requirements-github.yaml', driver='github')
def test_pipeline_require_label(self):
"Test pipeline requirement: label"
A = self.fake_github.openFakePullRequest('org/project10', 'master',
diff --git a/zuul/driver/github/githubmodel.py b/zuul/driver/github/githubmodel.py
index 5fa076316..256333234 100644
--- a/zuul/driver/github/githubmodel.py
+++ b/zuul/driver/github/githubmodel.py
@@ -455,11 +455,12 @@ class GithubEventFilter(EventFilter, GithubCommonFilter):
class GithubRefFilter(RefFilter, GithubCommonFilter):
- def __init__(self, connection_name, statuses=[], required_reviews=[],
- reject_reviews=[], open=None, merged=None,
- current_patchset=None, reject_open=None, reject_merged=None,
- reject_current_patchset=None, labels=[], reject_labels=[],
- reject_statuses=[]):
+ def __init__(self, connection_name, statuses=[],
+ required_reviews=[], reject_reviews=[], open=None,
+ merged=None, current_patchset=None, draft=None,
+ reject_open=None, reject_merged=None,
+ reject_current_patchset=None, reject_draft=None,
+ labels=[], reject_labels=[], reject_statuses=[]):
RefFilter.__init__(self, connection_name)
GithubCommonFilter.__init__(self, required_reviews=required_reviews,
@@ -479,6 +480,10 @@ class GithubRefFilter(RefFilter, GithubCommonFilter):
self.current_patchset = not reject_current_patchset
else:
self.current_patchset = current_patchset
+ if reject_draft is not None:
+ self.draft = not reject_draft
+ else:
+ self.draft = draft
self.labels = labels
self.reject_labels = reject_labels
@@ -496,12 +501,14 @@ class GithubRefFilter(RefFilter, GithubCommonFilter):
if self.reject_reviews:
ret += (' reject-reviews: %s' %
str(self.reject_reviews))
- if self.open:
+ if self.open is not None:
ret += ' open: %s' % self.open
- if self.merged:
+ if self.merged is not None:
ret += ' merged: %s' % self.merged
- if self.current_patchset:
+ if self.current_patchset is not None:
ret += ' current-patchset: %s' % self.current_patchset
+ if self.draft is not None:
+ ret += ' draft: %s' % self.draft
if self.labels:
ret += ' labels: %s' % self.labels
if self.reject_labels:
@@ -521,7 +528,8 @@ class GithubRefFilter(RefFilter, GithubCommonFilter):
# and cannot possibly pass this test.
if hasattr(change, 'number'):
if self.open != change.open:
- return FalseWithReason("Change is not a PR")
+ return FalseWithReason(
+ "Change does not match open requirement")
else:
return FalseWithReason("Change is not a PR")
@@ -530,7 +538,8 @@ class GithubRefFilter(RefFilter, GithubCommonFilter):
# and cannot possibly pass this test.
if hasattr(change, 'number'):
if self.merged != change.is_merged:
- return FalseWithReason("Change is not a PR")
+ return FalseWithReason(
+ "Change does not match merged requirement")
else:
return FalseWithReason("Change is not a PR")
@@ -539,7 +548,18 @@ class GithubRefFilter(RefFilter, GithubCommonFilter):
# and cannot possibly pass this test.
if hasattr(change, 'number'):
if self.current_patchset != change.is_current_patchset:
- return FalseWithReason("Change is not current")
+ return FalseWithReason(
+ "Change does not match current-patchset requirement")
+ else:
+ return FalseWithReason("Change is not a PR")
+
+ if self.draft is not None:
+ # if a "change" has no number, it's not a change, but a push
+ # and cannot possibly pass this test.
+ if hasattr(change, 'number'):
+ if self.draft != change.draft:
+ return FalseWithReason(
+ "Change does not match draft requirement")
else:
return FalseWithReason("Change is not a PR")
diff --git a/zuul/driver/github/githubsource.py b/zuul/driver/github/githubsource.py
index 7d4815237..bdc373f79 100644
--- a/zuul/driver/github/githubsource.py
+++ b/zuul/driver/github/githubsource.py
@@ -169,6 +169,7 @@ class GithubSource(BaseSource):
open=config.get('open'),
merged=config.get('merged'),
current_patchset=config.get('current-patchset'),
+ draft=config.get('draft'),
labels=to_list(config.get('label')),
)
return [f]
@@ -182,6 +183,7 @@ class GithubSource(BaseSource):
reject_open=config.get('open'),
reject_merged=config.get('merged'),
reject_current_patchset=config.get('current-patchset'),
+ reject_draft=config.get('draft'),
)
return [f]
@@ -207,6 +209,7 @@ def getRequireSchema():
'open': bool,
'merged': bool,
'current-patchset': bool,
+ 'draft': bool,
'label': scalar_or_list(str)}
return require
@@ -217,5 +220,6 @@ def getRejectSchema():
'open': bool,
'merged': bool,
'current-patchset': bool,
+ 'draft': bool,
'label': scalar_or_list(str)}
return reject