diff --git a/tests/fixtures/layout-delayed-repo-init.yaml b/tests/fixtures/layout-delayed-repo-init.yaml new file mode 100644 index 0000000000..79f98980f9 --- /dev/null +++ b/tests/fixtures/layout-delayed-repo-init.yaml @@ -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 diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py index 4e59db87cd..85eb8adec0 100644 --- a/tests/test_scheduler.py +++ b/tests/test_scheduler.py @@ -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) diff --git a/zuul/merger.py b/zuul/merger.py index 8ab3ee869e..94db4999af 100644 --- a/zuul/merger.py +++ b/zuul/merger.py @@ -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)