Merge "Cloner: use zuul_url always when project set"
diff --git a/tests/base.py b/tests/base.py
index a14b4a9..2559eb4 100755
--- a/tests/base.py
+++ b/tests/base.py
@@ -262,6 +262,25 @@
"comment": "This is a comment"}
return event
+ def getRefUpdatedEvent(self):
+ path = os.path.join(self.upstream_root, self.project)
+ repo = git.Repo(path)
+ oldrev = repo.heads[self.branch].commit.hexsha
+
+ event = {
+ "type": "ref-updated",
+ "submitter": {
+ "name": "User Name",
+ },
+ "refUpdate": {
+ "oldRev": oldrev,
+ "newRev": self.patchsets[-1]['revision'],
+ "refName": self.branch,
+ "project": self.project,
+ }
+ }
+ return event
+
def addApproval(self, category, value, username='reviewer_john',
granted_on=None, message=''):
if not granted_on:
diff --git a/tests/fixtures/layout-cloner.yaml b/tests/fixtures/layout-cloner.yaml
index 7429603..e8b5dde 100644
--- a/tests/fixtures/layout-cloner.yaml
+++ b/tests/fixtures/layout-cloner.yaml
@@ -30,6 +30,13 @@
gerrit:
verified: -2
+ - name: post
+ manager: IndependentPipelineManager
+ trigger:
+ gerrit:
+ - event: ref-updated
+ ref: ^(?!refs/).*$
+
projects:
- name: org/project
check:
@@ -42,6 +49,8 @@
- integration
gate:
- integration
+ post:
+ - postjob
- name: org/project2
check:
diff --git a/tests/test_cloner.py b/tests/test_cloner.py
index 7fc8dfc..896fcba 100644
--- a/tests/test_cloner.py
+++ b/tests/test_cloner.py
@@ -108,11 +108,34 @@
'be correct' % (project, number))
work = self.getWorkspaceRepos(projects)
- upstream_repo_path = os.path.join(self.upstream_root, 'org/project1')
- self.assertEquals(
+ # project1 is the zuul_project so the origin should be set to the
+ # zuul_url since that is the most up to date.
+ cache_repo_path = os.path.join(cache_root, 'org/project1')
+ self.assertNotEqual(
work['org/project1'].remotes.origin.url,
+ cache_repo_path,
+ 'workspace repo origin should not be the cache'
+ )
+ zuul_url_repo_path = os.path.join(self.git_root, 'org/project1')
+ self.assertEqual(
+ work['org/project1'].remotes.origin.url,
+ zuul_url_repo_path,
+ 'workspace repo origin should be the zuul url'
+ )
+
+ # project2 is not the zuul_project so the origin should be set
+ # to upstream since that is the best we can do
+ cache_repo_path = os.path.join(cache_root, 'org/project2')
+ self.assertNotEqual(
+ work['org/project2'].remotes.origin.url,
+ cache_repo_path,
+ 'workspace repo origin should not be the cache'
+ )
+ upstream_repo_path = os.path.join(self.upstream_root, 'org/project2')
+ self.assertEqual(
+ work['org/project2'].remotes.origin.url,
upstream_repo_path,
- 'workspace repo origin should be upstream, not cache'
+ 'workspace repo origin should be the upstream url'
)
self.worker.hold_jobs_in_build = False
@@ -656,55 +679,76 @@
self.waitUntilSettled()
def test_post_checkout(self):
- project = "org/project"
- path = os.path.join(self.upstream_root, project)
- repo = git.Repo(path)
- repo.head.reference = repo.heads['master']
- commits = []
- for i in range(0, 3):
- commits.append(self.create_commit(project))
- newRev = commits[1]
+ self.worker.hold_jobs_in_build = True
+ project = "org/project1"
+
+ A = self.fake_gerrit.addFakeChange(project, 'master', 'A')
+ event = A.getRefUpdatedEvent()
+ A.setMerged()
+ self.fake_gerrit.addEvent(event)
+ self.waitUntilSettled()
+
+ build = self.builds[0]
+ state = {'org/project1': build.parameters['ZUUL_COMMIT']}
+
+ build.release()
+ self.waitUntilSettled()
cloner = zuul.lib.cloner.Cloner(
git_base_url=self.upstream_root,
projects=[project],
workspace=self.workspace_root,
- zuul_project='org/project',
- zuul_branch=None,
- zuul_ref='master',
+ zuul_project=build.parameters.get('ZUUL_PROJECT', None),
+ zuul_branch=build.parameters.get('ZUUL_BRANCH', None),
+ zuul_ref=build.parameters.get('ZUUL_REF', None),
+ zuul_newrev=build.parameters.get('ZUUL_NEWREV', None),
zuul_url=self.git_root,
- zuul_newrev=newRev,
)
cloner.execute()
- repos = self.getWorkspaceRepos([project])
- cloned_sha = repos[project].rev_parse('HEAD').hexsha
- self.assertEqual(newRev, cloned_sha)
+ work = self.getWorkspaceRepos([project])
+ self.assertEquals(state[project],
+ str(work[project].commit('HEAD')),
+ 'Project %s commit for build %s should '
+ 'be correct' % (project, 0))
+ shutil.rmtree(self.workspace_root)
def test_post_and_master_checkout(self):
- project = "org/project1"
- master_project = "org/project2"
- path = os.path.join(self.upstream_root, project)
- repo = git.Repo(path)
- repo.head.reference = repo.heads['master']
- commits = []
- for i in range(0, 3):
- commits.append(self.create_commit(project))
- newRev = commits[1]
+ self.worker.hold_jobs_in_build = True
+ projects = ["org/project1", "org/project2"]
+
+ A = self.fake_gerrit.addFakeChange(projects[0], 'master', 'A')
+ event = A.getRefUpdatedEvent()
+ A.setMerged()
+ self.fake_gerrit.addEvent(event)
+ self.waitUntilSettled()
+
+ build = self.builds[0]
+ upstream = self.getUpstreamRepos(projects)
+ state = {'org/project1':
+ build.parameters['ZUUL_COMMIT'],
+ 'org/project2':
+ str(upstream['org/project2'].commit('master')),
+ }
+
+ build.release()
+ self.waitUntilSettled()
cloner = zuul.lib.cloner.Cloner(
git_base_url=self.upstream_root,
- projects=[project, master_project],
+ projects=projects,
workspace=self.workspace_root,
- zuul_project='org/project1',
- zuul_branch=None,
- zuul_ref='master',
+ zuul_project=build.parameters.get('ZUUL_PROJECT', None),
+ zuul_branch=build.parameters.get('ZUUL_BRANCH', None),
+ zuul_ref=build.parameters.get('ZUUL_REF', None),
+ zuul_newrev=build.parameters.get('ZUUL_NEWREV', None),
zuul_url=self.git_root,
- zuul_newrev=newRev
)
cloner.execute()
- repos = self.getWorkspaceRepos([project, master_project])
- cloned_sha = repos[project].rev_parse('HEAD').hexsha
- self.assertEqual(newRev, cloned_sha)
- self.assertEqual(
- repos[master_project].rev_parse('HEAD').hexsha,
- repos[master_project].rev_parse('master').hexsha)
+ work = self.getWorkspaceRepos(projects)
+
+ for project in projects:
+ self.assertEquals(state[project],
+ str(work[project].commit('HEAD')),
+ 'Project %s commit for build %s should '
+ 'be correct' % (project, 0))
+ shutil.rmtree(self.workspace_root)
diff --git a/zuul/lib/cloner.py b/zuul/lib/cloner.py
index 197c426..6e50eda 100644
--- a/zuul/lib/cloner.py
+++ b/zuul/lib/cloner.py
@@ -46,6 +46,8 @@
self.zuul_branch = zuul_branch or ''
self.zuul_ref = zuul_ref or ''
self.zuul_url = zuul_url
+ self.zuul_project = zuul_project
+
self.project_branches = project_branches or {}
self.project_revisions = {}
@@ -77,7 +79,18 @@
def cloneUpstream(self, project, dest):
# Check for a cached git repo first
git_cache = '%s/%s' % (self.cache_dir, project)
- git_upstream = '%s/%s' % (self.git_url, project)
+
+ # Then, if we are cloning the repo for the zuul_project, then
+ # set its origin to be the zuul merger, as it is guaranteed to
+ # be correct and up to date even if mirrors haven't updated
+ # yet. Otherwise, we can not be sure about the state of the
+ # project, so our best chance to get the most current state is
+ # by setting origin to the git_url.
+ if (self.zuul_url and project == self.zuul_project):
+ git_upstream = '%s/%s' % (self.zuul_url, project)
+ else:
+ git_upstream = '%s/%s' % (self.git_url, project)
+
repo_is_cloned = os.path.exists(os.path.join(dest, '.git'))
if (self.cache_dir and
os.path.exists(git_cache) and
@@ -104,23 +117,35 @@
return repo
- def fetchFromZuul(self, repo, project, ref):
- zuul_remote = '%s/%s' % (self.zuul_url, project)
+ def fetchRef(self, repo, project, ref):
+ # If we are fetching a zuul ref, the only place to get it is
+ # from the zuul merger (and it is guaranteed to be correct).
+ # Otherwise, the only way we can be certain that the ref
+ # (which, since it is not a zuul ref, is a branch or tag) is
+ # correct is in the case that it matches zuul_project. If
+ # neither of those two conditions are met, we are most likely
+ # to get the correct state from the git_url.
+ if (ref.startswith('refs/zuul') or
+ project == self.zuul_project):
+
+ remote = '%s/%s' % (self.zuul_url, project)
+ else:
+ remote = '%s/%s' % (self.git_url, project)
try:
- repo.fetchFrom(zuul_remote, ref)
- self.log.debug("Fetched ref %s from %s", ref, project)
+ repo.fetchFrom(remote, ref)
+ self.log.debug("Fetched ref %s from %s", ref, remote)
return True
except ValueError:
- self.log.debug("Project %s in Zuul does not have ref %s",
- project, ref)
+ self.log.debug("Repo %s does not have ref %s",
+ remote, ref)
return False
except GitCommandError as error:
# Bail out if fetch fails due to infrastructure reasons
if error.stderr.startswith('fatal: unable to access'):
raise
- self.log.debug("Project %s in Zuul does not have ref %s",
- project, ref)
+ self.log.debug("Repo %s does not have ref %s",
+ remote, ref)
return False
def prepareRepo(self, project, dest):
@@ -192,7 +217,7 @@
self.log.info("Attempting to check out revision %s for "
"project %s", indicated_revision, project)
try:
- self.fetchFromZuul(repo, project, self.zuul_ref)
+ self.fetchRef(repo, project, self.zuul_ref)
commit = repo.checkout(indicated_revision)
except (ValueError, GitCommandError):
raise exceptions.RevNotFound(project, indicated_revision)
@@ -201,10 +226,10 @@
# If we have a non empty zuul_ref to use, use it. Otherwise we fall
# back to checking out the branch.
elif ((override_zuul_ref and
- self.fetchFromZuul(repo, project, override_zuul_ref)) or
+ self.fetchRef(repo, project, override_zuul_ref)) or
(fallback_zuul_ref and
fallback_zuul_ref != override_zuul_ref and
- self.fetchFromZuul(repo, project, fallback_zuul_ref))):
+ self.fetchRef(repo, project, fallback_zuul_ref))):
# Work around a bug in GitPython which can not parse FETCH_HEAD
gitcmd = git.Git(dest)
fetch_head = gitcmd.rev_parse('FETCH_HEAD')