Return resulting commits from merger

Currently the results (i.e., the exact commits on each project-branch)
of a speculative merge operation are only available by examining the
Zuul refs created by the merger.  The executor appears to use the results
of the speculative merge in its tests, but that's only surface deep --
it simply leaves the repo in the last merge state, which is sufficient
for simple tests, but not for multi-branch cross-repo dependencies.

This change returns the branch names and commits for each project-branch
involved in a speculative merge.  The executor then updates the branch
head references in the job's working source directory to reflect the
merger results.  In other words, even if the job is running for a change
on master, if that change depends on a change in stable then the stable
branch of the repo will now include the stable change.

Note: this change does not yet alter the branch checked out -- we're still
on a detached head.  That will be addressed in a future change.

Change-Id: Id842d64312d87709f0ed93121735fe97faccc189
This commit is contained in:
James E. Blair 2017-05-24 13:53:35 -07:00
parent 7391ecbb77
commit 57c51a1cac
3 changed files with 22 additions and 7 deletions

View File

@ -491,7 +491,8 @@ class ExecutorServer(object):
if ret is None:
result['commit'] = result['files'] = result['repo_state'] = None
else:
result['commit'], result['files'], result['repo_state'] = ret
(result['commit'], result['files'], result['repo_state'],
recent) = ret
job.sendWorkComplete(json.dumps(result))
@ -640,6 +641,11 @@ class AnsibleJob(object):
result = dict(result='MERGER_FAILURE')
self.job.sendWorkComplete(json.dumps(result))
return False
recent = ret[3]
for key, commit in recent.items():
(connection, project, branch) = key
repo = merger.getRepo(connection, project)
repo.setRef('refs/heads/' + branch, commit)
return True
def runPlaybooks(self, args):

View File

@ -129,6 +129,14 @@ class Repo(object):
repo = self.createRepoObject()
return repo.refs
def setRef(self, path, hexsha, repo=None):
if repo is None:
repo = self.createRepoObject()
binsha = gitdb.util.to_bin_sha(hexsha)
obj = git.objects.Object.new_from_sha(repo, binsha)
self.log.debug("Create reference %s", path)
git.refs.Reference.create(repo, path, obj, force=True)
def setRefs(self, refs):
repo = self.createRepoObject()
current_refs = {}
@ -136,10 +144,7 @@ class Repo(object):
current_refs[ref.path] = ref
unseen = set(current_refs.keys())
for path, hexsha in refs.items():
binsha = gitdb.util.to_bin_sha(hexsha)
obj = git.objects.Object.new_from_sha(repo, binsha)
self.log.debug("Create reference %s", path)
git.refs.Reference.create(repo, path, obj, force=True)
self.setRef(path, hexsha, repo)
unseen.discard(path)
for path in unseen:
self.log.debug("Delete reference %s", path)
@ -439,7 +444,10 @@ class Merger(object):
project=item['project'],
branch=item['branch'],
files=repo_files))
return commit.hexsha, read_files, repo_state
ret_recent = {}
for k, v in recent.items():
ret_recent[k] = v.hexsha
return commit.hexsha, read_files, repo_state, ret_recent
def getFiles(self, connection_name, project_name, branch, files):
repo = self.getRepo(connection_name, project_name)

View File

@ -110,7 +110,8 @@ class MergeServer(object):
if ret is None:
result['commit'] = result['files'] = result['repo_state'] = None
else:
result['commit'], result['files'], result['repo_state'] = ret
(result['commit'], result['files'], result['repo_state'],
recent) = ret
job.sendWorkComplete(json.dumps(result))
def cat(self, job):