Allow to select the merge method in Github

Instead of creating a merge commit, Github also allows for two other
options, squash and rebase. This change makes the github reporter
aware of the merge-mode which already can be set. For now only merge
and merge-resolve are supported which both map to the Github merge
mode 'merge'. The other two merge modes that are supported by Github
are not yet supported by the merger and will be implemented in later
changes.

Change-Id: I3d51261f248072d2e3ee7e3212377f81b9a41010
Co-Authored-By: Tobias Henkel <tobias.henkel@bmw.de>
This commit is contained in:
Markus Hosch 2018-11-13 12:16:37 +01:00 committed by Tobias Henkel
parent 48c049db79
commit 3f485be486
No known key found for this signature in database
GPG Key ID: 03750DEC158E5FA2
7 changed files with 102 additions and 10 deletions

View File

@ -1342,7 +1342,8 @@ pipeline.
The merge mode which is used by Git for this project. Be sure
this matches what the remote system which performs merges (i.e.,
Gerrit or GitHub).
Gerrit). The requested merge mode will be used by the Github driver
when performing merges.
Each project may only have one ``merge-mode`` therefore Zuul
will use the first value that it encounters for a given project
@ -1353,18 +1354,20 @@ pipeline.
.. value:: merge
Uses the default git merge strategy (recursive).
Uses the default git merge strategy (recursive). This maps to
the merge mode ``merge`` in Github.
.. value:: merge-resolve
Uses the resolve git merge strategy. This is a very
conservative merge strategy which most closely matches the
behavior of Gerrit.
behavior of Gerrit. This maps to the merge mode ``merge`` in
Github.
.. value:: cherry-pick
Cherry-picks each change onto the branch rather than
performing any merges.
performing any merges. This is not supported by Github.
.. attr:: vars
:default: None

View File

@ -0,0 +1,4 @@
features:
- |
It is now possible to select the merge method GitHub uses to merge a Pull
Request to the base branch.

View File

@ -1271,9 +1271,9 @@ class FakeGithubConnection(githubconnection.GithubConnection):
pull_request.addComment(message)
def mergePull(self, project, pr_number, commit_message='', sha=None,
zuul_event_id=None):
method='merge', zuul_event_id=None):
# record that this got reported
self.reports.append((project, pr_number, 'merge'))
self.reports.append((project, pr_number, 'merge', method))
pull_request = self.pull_requests[int(pr_number)]
if self.merge_failure:
raise Exception('Pull request was not merged')

View File

@ -0,0 +1,38 @@
- pipeline:
name: gate
manager: dependent
trigger:
github:
- event: pull_request
action:
- opened
- changed
- reopened
branch: ^master$
success:
github:
status: success
merge: true
failure:
github: {}
- job:
name: base
parent: null
run: playbooks/base.yaml
- job:
name: project-test1
run: playbooks/project-test1.yaml
- job:
name: project-test2
run: playbooks/project-test2.yaml
- project:
name: org/project
merge-mode: cherry-pick
gate:
jobs:
- project-test1
- project-test2

View File

@ -1097,6 +1097,35 @@ class TestGithubDriver(ZuulTestCase):
MatchesRegex(r'.*\[project-test2 \]\(.*\).*', re.DOTALL))
self.assertEqual(2, len(self.history))
@simple_layout('layouts/gate-github-cherry-pick.yaml', driver='github')
def test_merge_method_cherry_pick(self):
"""
Tests that the merge mode gets forwarded to the reporter and the
merge fails because cherry-pick is not supported by github.
"""
github = self.fake_github.getGithubClient()
github._data.required_contexts[('org/project', 'master')] = [
'tenant-one/check',
'tenant-one/gate']
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
repo = github.repo_from_project('org/project')
repo.create_status(A.head_sha, 'success', 'example.com', 'description',
'tenant-one/check')
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
self.waitUntilSettled()
# the change should have entered the gate
self.assertEqual(2, len(self.history))
self.assertEqual(2, len(A.comments))
self.assertFalse(A.is_merged)
self.assertIn('Merge Failed', A.comments[1])
class TestGithubUnprotectedBranches(ZuulTestCase):
config_file = 'zuul-github-driver.conf'

View File

@ -1420,13 +1420,14 @@ class GithubConnection(BaseConnection):
self.log_rate_limit(self.log, github)
def mergePull(self, project, pr_number, commit_message='', sha=None,
zuul_event_id=None):
method='merge', zuul_event_id=None):
log = get_annotated_logger(self.log, zuul_event_id)
github = self.getGithubClient(project, zuul_event_id=zuul_event_id)
github = self.getGithubClient(project)
owner, proj = project.split('/')
pull_request = github.pull_request(owner, proj, pr_number)
try:
result = pull_request.merge(commit_message=commit_message, sha=sha)
result = pull_request.merge(commit_message=commit_message, sha=sha,
merge_method=method)
except github3.exceptions.MethodNotAllowed as e:
raise MergeFailure('Merge was not successful due to mergeability'
' conflict, original error is %s' % e)

View File

@ -17,6 +17,7 @@ import voluptuous as v
import time
from zuul.lib.logutil import get_annotated_logger
from zuul.model import MERGER_MERGE_RESOLVE, MERGER_MERGE, MERGER_MAP
from zuul.reporter import BaseReporter
from zuul.exceptions import MergeFailure
from zuul.driver.util import scalar_or_list
@ -29,6 +30,12 @@ class GithubReporter(BaseReporter):
name = 'github'
log = logging.getLogger("zuul.GithubReporter")
# Merge modes supported by github
merge_modes = {
MERGER_MERGE: 'merge',
MERGER_MERGE_RESOLVE: 'merge',
}
def __init__(self, driver, connection, pipeline, config=None):
super(GithubReporter, self).__init__(driver, connection, config)
self._commit_status = self.config.get('status', None)
@ -136,6 +143,15 @@ class GithubReporter(BaseReporter):
def mergePull(self, item):
log = get_annotated_logger(self.log, item.event)
merge_mode = item.current_build_set.getMergeMode()
if merge_mode not in self.merge_modes:
mode = [x[0] for x in MERGER_MAP.items() if x[1] == merge_mode][0]
self.log.warning('Merge mode %s not supported by Github', mode)
# TODO(tobiash): report error to user
return
merge_mode = self.merge_modes[merge_mode]
project = item.change.project.name
pr_number = item.change.number
sha = item.change.patchset
@ -145,7 +161,8 @@ class GithubReporter(BaseReporter):
for i in [1, 2]:
try:
self.connection.mergePull(project, pr_number, message, sha,
self.connection.mergePull(project, pr_number, message, sha=sha,
method=merge_mode,
zuul_event_id=item.event)
item.change.is_merged = True
return