Delay initialization of local repos
Now that live reconfiguration is an option, we sometimes load the Zuul config before the remote repo is created. To handle that, gracefully handle that case when the Repo object is created by the Merger. Keep track of whether the initial clone has happened, and check for that before every local Repo operation. If we get an event that involves a repo before it exists (unlikely!) that will still error and raise an exception (that should be caught higher up in the stack). Add a test for this case. In the test suite, when adding a fake change to the upstream repo, always reset it so that HEAD is master so that new repos clone from a consistent state. Also remove an errant assertEmptyQueues because it's handled by assertFinalState. Change-Id: Ic6eec83e3faa2a15be4b23d4cfcfbddcac82983c
This commit is contained in:
parent
c28d1b0d19
commit
287c06dca6
|
@ -0,0 +1,44 @@
|
|||
pipelines:
|
||||
- name: check
|
||||
manager: IndependentPipelineManager
|
||||
trigger:
|
||||
- event: patchset-created
|
||||
success:
|
||||
verified: 1
|
||||
failure:
|
||||
verified: -1
|
||||
|
||||
- name: post
|
||||
manager: IndependentPipelineManager
|
||||
trigger:
|
||||
- event: ref-updated
|
||||
ref: ^(?!refs/).*$
|
||||
|
||||
- name: gate
|
||||
manager: DependentPipelineManager
|
||||
failure-message: Build failed. For information on how to proceed, see http://wiki.example.org/Test_Failures
|
||||
trigger:
|
||||
- event: comment-added
|
||||
approval:
|
||||
- approved: 1
|
||||
success:
|
||||
verified: 2
|
||||
submit: true
|
||||
failure:
|
||||
verified: -2
|
||||
start:
|
||||
verified: 0
|
||||
precedence: high
|
||||
|
||||
projects:
|
||||
- name: org/new-project
|
||||
check:
|
||||
- project-merge:
|
||||
- project-test1
|
||||
- project-test2
|
||||
gate:
|
||||
- project-merge:
|
||||
- project-test1
|
||||
- project-test2
|
||||
post:
|
||||
- project-post
|
|
@ -148,7 +148,11 @@ class FakeChange(object):
|
|||
f.close()
|
||||
repo.index.add([fn])
|
||||
|
||||
return repo.index.commit(msg)
|
||||
r = repo.index.commit(msg)
|
||||
repo.head.reference = 'master'
|
||||
repo.head.reset(index=True, working_tree=True)
|
||||
repo.git.clean('-x', '-f', '-d')
|
||||
return r
|
||||
|
||||
def addPatchset(self, files=[], large=False):
|
||||
self.latest_patchset += 1
|
||||
|
@ -2445,4 +2449,23 @@ class TestScheduler(testtools.TestCase):
|
|||
'SUCCESS')
|
||||
self.assertEqual(A.data['status'], 'MERGED')
|
||||
self.assertEqual(A.reported, 2)
|
||||
self.assertEmptyQueues()
|
||||
|
||||
def test_delayed_repo_init(self):
|
||||
self.config.set('zuul', 'layout_config',
|
||||
'tests/fixtures/layout-delayed-repo-init.yaml')
|
||||
self.sched.reconfigure(self.config)
|
||||
|
||||
self.init_repo("org/new-project")
|
||||
A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
|
||||
|
||||
A.addApproval('CRVW', 2)
|
||||
self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(self.getJobFromHistory('project-merge').result,
|
||||
'SUCCESS')
|
||||
self.assertEqual(self.getJobFromHistory('project-test1').result,
|
||||
'SUCCESS')
|
||||
self.assertEqual(self.getJobFromHistory('project-test2').result,
|
||||
'SUCCESS')
|
||||
self.assertEqual(A.data['status'], 'MERGED')
|
||||
self.assertEqual(A.reported, 2)
|
||||
|
|
|
@ -29,24 +29,37 @@ class Repo(object):
|
|||
def __init__(self, remote, local, email, username):
|
||||
self.remote_url = remote
|
||||
self.local_path = local
|
||||
self._ensure_cloned()
|
||||
self.repo = git.Repo(self.local_path)
|
||||
if email:
|
||||
self.repo.config_writer().set_value('user', 'email', email)
|
||||
if username:
|
||||
self.repo.config_writer().set_value('user', 'name', username)
|
||||
self.repo.config_writer().write()
|
||||
self.email = email
|
||||
self.username = username
|
||||
self._initialized = False
|
||||
try:
|
||||
self._ensure_cloned()
|
||||
except:
|
||||
self.log.exception("Unable to initialize repo for %s" % remote)
|
||||
|
||||
def _ensure_cloned(self):
|
||||
if self._initialized:
|
||||
return
|
||||
if not os.path.exists(self.local_path):
|
||||
self.log.debug("Cloning from %s to %s" % (self.remote_url,
|
||||
self.local_path))
|
||||
git.Repo.clone_from(self.remote_url, self.local_path)
|
||||
self.repo = git.Repo(self.local_path)
|
||||
if self.email:
|
||||
self.repo.config_writer().set_value('user', 'email',
|
||||
self.email)
|
||||
if self.username:
|
||||
self.repo.config_writer().set_value('user', 'name',
|
||||
self.username)
|
||||
self.repo.config_writer().write()
|
||||
self._initialized = True
|
||||
|
||||
def recreateRepoObject(self):
|
||||
self._ensure_cloned()
|
||||
self.repo = git.Repo(self.local_path)
|
||||
|
||||
def reset(self):
|
||||
self._ensure_cloned()
|
||||
self.log.debug("Resetting repository %s" % self.local_path)
|
||||
self.update()
|
||||
origin = self.repo.remotes.origin
|
||||
|
@ -64,21 +77,25 @@ class Repo(object):
|
|||
return self.repo.heads[branch]
|
||||
|
||||
def checkout(self, ref):
|
||||
self._ensure_cloned()
|
||||
self.log.debug("Checking out %s" % ref)
|
||||
self.repo.head.reference = ref
|
||||
self.repo.head.reset(index=True, working_tree=True)
|
||||
|
||||
def cherryPick(self, ref):
|
||||
self._ensure_cloned()
|
||||
self.log.debug("Cherry-picking %s" % ref)
|
||||
self.fetch(ref)
|
||||
self.repo.git.cherry_pick("FETCH_HEAD")
|
||||
|
||||
def merge(self, ref):
|
||||
self._ensure_cloned()
|
||||
self.log.debug("Merging %s" % ref)
|
||||
self.fetch(ref)
|
||||
self.repo.git.merge("FETCH_HEAD")
|
||||
|
||||
def fetch(self, ref):
|
||||
self._ensure_cloned()
|
||||
# The git.remote.fetch method may read in git progress info and
|
||||
# interpret it improperly causing an AssertionError. Because the
|
||||
# data was fetched properly subsequent fetches don't seem to fail.
|
||||
|
@ -97,16 +114,19 @@ class Repo(object):
|
|||
self.repo = git.Repo(self.local_path)
|
||||
|
||||
def createZuulRef(self, ref, commit='HEAD'):
|
||||
self._ensure_cloned()
|
||||
self.log.debug("CreateZuulRef %s at %s " % (ref, commit))
|
||||
ref = ZuulReference.create(self.repo, ref, commit)
|
||||
return ref.commit
|
||||
|
||||
def push(self, local, remote):
|
||||
self._ensure_cloned()
|
||||
self.log.debug("Pushing %s:%s to %s " % (local, remote,
|
||||
self.remote_url))
|
||||
self.repo.remotes.origin.push('%s:%s' % (local, remote))
|
||||
|
||||
def update(self):
|
||||
self._ensure_cloned()
|
||||
self.log.debug("Updating repository %s" % self.local_path)
|
||||
origin = self.repo.remotes.origin
|
||||
origin.update()
|
||||
|
@ -151,7 +171,7 @@ class Merger(object):
|
|||
|
||||
self.repos[project] = repo
|
||||
except:
|
||||
self.log.exception("Unable to initialize repo for %s" % project)
|
||||
self.log.exception("Unable to add project %s" % project)
|
||||
|
||||
def getRepo(self, project):
|
||||
r = self.repos.get(project, None)
|
||||
|
|
Loading…
Reference in New Issue