Merge "Add rebase-merge merge mode"
This commit is contained in:
commit
45c04e4c69
|
@ -138,13 +138,20 @@ pipeline.
|
|||
.. value:: cherry-pick
|
||||
|
||||
Cherry-picks each change onto the branch rather than
|
||||
performing any merges. This is not supported by Github and GitLab.
|
||||
performing any merges. This is not supported by GitHub and GitLab.
|
||||
|
||||
.. value:: squash-merge
|
||||
|
||||
Squash merges each change onto the branch. This maps to the
|
||||
merge mode ``squash`` in GitHub and GitLab.
|
||||
|
||||
.. value:: rebase
|
||||
|
||||
Rebases the changes onto the branch. This is only supported
|
||||
by GitHub and maps to the ``rebase`` merge mode (but
|
||||
does not alter committer information in the way that GitHub
|
||||
does in the repos that Zuul prepares for jobs).
|
||||
|
||||
.. attr:: vars
|
||||
:default: None
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
The :value:`project.merge-mode.rebase` merge-mode is now supported
|
||||
for GitHub.
|
|
@ -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: rebase
|
||||
gate:
|
||||
jobs:
|
||||
- project-test1
|
||||
- project-test2
|
|
@ -1356,11 +1356,59 @@ class TestGithubDriver(ZuulTestCase):
|
|||
self.assertEquals(A.comments[1],
|
||||
'Merge mode cherry-pick not supported by Github')
|
||||
|
||||
@simple_layout('layouts/gate-github-rebase.yaml', driver='github')
|
||||
def test_merge_method_rebase(self):
|
||||
"""
|
||||
Tests that the merge mode gets forwarded to the reporter and the
|
||||
PR was rebased.
|
||||
"""
|
||||
self.executor_server.keep_jobdir = True
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
github = self.fake_github.getGithubClient()
|
||||
repo = github.repo_from_project('org/project')
|
||||
repo._set_branch_protection(
|
||||
'master', contexts=['tenant-one/check', 'tenant-one/gate'])
|
||||
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
repo.create_status(A.head_sha, 'success', 'example.com', 'description',
|
||||
'tenant-one/check')
|
||||
|
||||
# Create a second commit on master to verify rebase behavior
|
||||
self.create_commit('org/project', message="Test rebase commit")
|
||||
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
|
||||
build = self.builds[-1]
|
||||
path = os.path.join(build.jobdir.src_root, 'github.com/org/project')
|
||||
repo = git.Repo(path)
|
||||
repo_messages = [c.message.strip() for c in repo.iter_commits()]
|
||||
repo_messages.reverse()
|
||||
expected = [
|
||||
'initial commit',
|
||||
'initial commit', # simple_layout adds a second "initial commit"
|
||||
'Test rebase commit',
|
||||
'A-1',
|
||||
]
|
||||
self.assertEqual(expected, repo_messages)
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
|
||||
# the change should have entered the gate
|
||||
self.assertEqual(2, len(self.history))
|
||||
|
||||
# now check if the merge was done via rebase
|
||||
merges = [report for report in self.fake_github.github_data.reports
|
||||
if report[2] == 'merge']
|
||||
assert (len(merges) == 1 and merges[0][3] == 'rebase')
|
||||
|
||||
@simple_layout('layouts/gate-github-squash-merge.yaml', driver='github')
|
||||
def test_merge_method_squash_merge(self):
|
||||
"""
|
||||
Tests that the merge mode gets forwarded to the reporter and the
|
||||
merge fails because cherry-pick is not supported by github.
|
||||
PR was squashed.
|
||||
"""
|
||||
github = self.fake_github.getGithubClient()
|
||||
repo = github.repo_from_project('org/project')
|
||||
|
@ -1381,7 +1429,7 @@ class TestGithubDriver(ZuulTestCase):
|
|||
# the change should have entered the gate
|
||||
self.assertEqual(2, len(self.history))
|
||||
|
||||
# now check if the merge was done via rebase
|
||||
# now check if the merge was done via squash
|
||||
merges = [report for report in self.fake_github.github_data.reports
|
||||
if report[2] == 'merge']
|
||||
assert (len(merges) == 1 and merges[0][3] == 'squash')
|
||||
|
|
|
@ -1113,7 +1113,8 @@ class ProjectParser(object):
|
|||
'vars': ansible_vars_dict,
|
||||
'templates': [str],
|
||||
'merge-mode': vs.Any('merge', 'merge-resolve',
|
||||
'cherry-pick', 'squash-merge'),
|
||||
'cherry-pick', 'squash-merge',
|
||||
'rebase'),
|
||||
'default-branch': str,
|
||||
'queue': str,
|
||||
str: pipeline_contents,
|
||||
|
|
|
@ -17,9 +17,8 @@ import logging
|
|||
import voluptuous as v
|
||||
import time
|
||||
|
||||
from zuul import model
|
||||
from zuul.lib.logutil import get_annotated_logger
|
||||
from zuul.model import MERGER_MERGE_RESOLVE, MERGER_MERGE, MERGER_MAP, \
|
||||
MERGER_SQUASH_MERGE
|
||||
from zuul.reporter import BaseReporter
|
||||
from zuul.exceptions import MergeFailure
|
||||
from zuul.driver.util import scalar_or_list
|
||||
|
@ -34,9 +33,10 @@ class GithubReporter(BaseReporter):
|
|||
|
||||
# Merge modes supported by github
|
||||
merge_modes = {
|
||||
MERGER_MERGE: 'merge',
|
||||
MERGER_MERGE_RESOLVE: 'merge',
|
||||
MERGER_SQUASH_MERGE: 'squash',
|
||||
model.MERGER_MERGE: 'merge',
|
||||
model.MERGER_MERGE_RESOLVE: 'merge',
|
||||
model.MERGER_SQUASH_MERGE: 'squash',
|
||||
model.MERGER_REBASE: 'rebase',
|
||||
}
|
||||
|
||||
def __init__(self, driver, connection, pipeline, config=None):
|
||||
|
@ -189,7 +189,8 @@ class GithubReporter(BaseReporter):
|
|||
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]
|
||||
mode = [x[0] for x in model.MERGER_MAP.items()
|
||||
if x[1] == merge_mode][0]
|
||||
self.log.warning('Merge mode %s not supported by Github', mode)
|
||||
raise MergeFailure('Merge mode %s not supported by Github' % mode)
|
||||
|
||||
|
|
|
@ -582,7 +582,7 @@ class Repo(object):
|
|||
repo.git.merge(*args)
|
||||
return repo.head.commit
|
||||
|
||||
def squash_merge(self, item, zuul_event_id=None):
|
||||
def squashMerge(self, item, zuul_event_id=None):
|
||||
log = get_annotated_logger(self.log, zuul_event_id)
|
||||
repo = self.createRepoObject(zuul_event_id)
|
||||
args = ['--squash', 'FETCH_HEAD']
|
||||
|
@ -594,6 +594,17 @@ class Repo(object):
|
|||
'Merge change %s,%s' % (item['number'], item['patchset']))
|
||||
return repo.head.commit
|
||||
|
||||
def rebaseMerge(self, item, base, zuul_event_id=None):
|
||||
log = get_annotated_logger(self.log, zuul_event_id)
|
||||
repo = self.createRepoObject(zuul_event_id)
|
||||
args = [base]
|
||||
ref = item['ref']
|
||||
self.fetch(ref, zuul_event_id=zuul_event_id)
|
||||
log.debug("Rebasing %s with args %s", ref, args)
|
||||
repo.git.checkout('FETCH_HEAD')
|
||||
repo.git.rebase(*args)
|
||||
return repo.head.commit
|
||||
|
||||
def fetch(self, ref, zuul_event_id=None):
|
||||
repo = self.createRepoObject(zuul_event_id)
|
||||
# NOTE: The following is currently not applicable, but if we
|
||||
|
@ -1029,14 +1040,14 @@ class Merger(object):
|
|||
for message in messages:
|
||||
ref_log.debug(message)
|
||||
|
||||
def _mergeChange(self, item, ref, zuul_event_id):
|
||||
def _mergeChange(self, item, base, zuul_event_id):
|
||||
log = get_annotated_logger(self.log, zuul_event_id)
|
||||
repo = self.getRepo(item['connection'], item['project'],
|
||||
zuul_event_id=zuul_event_id)
|
||||
try:
|
||||
repo.checkout(ref, zuul_event_id=zuul_event_id)
|
||||
repo.checkout(base, zuul_event_id=zuul_event_id)
|
||||
except Exception:
|
||||
log.exception("Unable to checkout %s", ref)
|
||||
log.exception("Unable to checkout %s", base)
|
||||
return None, None
|
||||
|
||||
try:
|
||||
|
@ -1050,8 +1061,11 @@ class Merger(object):
|
|||
commit = repo.cherryPick(item['ref'],
|
||||
zuul_event_id=zuul_event_id)
|
||||
elif mode == zuul.model.MERGER_SQUASH_MERGE:
|
||||
commit = repo.squash_merge(
|
||||
commit = repo.squashMerge(
|
||||
item, zuul_event_id=zuul_event_id)
|
||||
elif mode == zuul.model.MERGER_REBASE:
|
||||
commit = repo.rebaseMerge(
|
||||
item, base, zuul_event_id=zuul_event_id)
|
||||
else:
|
||||
raise Exception("Unsupported merge mode: %s" % mode)
|
||||
except git.GitCommandError:
|
||||
|
|
|
@ -55,13 +55,15 @@ from zuul.zk.components import COMPONENT_REGISTRY
|
|||
MERGER_MERGE = 1 # "git merge"
|
||||
MERGER_MERGE_RESOLVE = 2 # "git merge -s resolve"
|
||||
MERGER_CHERRY_PICK = 3 # "git cherry-pick"
|
||||
MERGER_SQUASH_MERGE = 4 # "git merge --squash"
|
||||
MERGER_SQUASH_MERGE = 4 # "git merge --squash"
|
||||
MERGER_REBASE = 5 # "git rebase"
|
||||
|
||||
MERGER_MAP = {
|
||||
'merge': MERGER_MERGE,
|
||||
'merge-resolve': MERGER_MERGE_RESOLVE,
|
||||
'cherry-pick': MERGER_CHERRY_PICK,
|
||||
'squash-merge': MERGER_SQUASH_MERGE,
|
||||
'rebase': MERGER_REBASE,
|
||||
}
|
||||
|
||||
PRECEDENCE_NORMAL = 0
|
||||
|
|
Loading…
Reference in New Issue