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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
48
tests/fixtures/layouts/requirements-github.yaml
vendored
48
tests/fixtures/layouts/requirements-github.yaml
vendored
@@ -285,6 +285,34 @@
|
||||
github:
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -502,6 +502,46 @@ class TestGithubRequirements(ZuulTestCase):
|
||||
# Event hash is not current, should trigger
|
||||
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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user