Cloner: add project-specific branch overrides

Add a facility to override the indicated branch for a specific
project.  In OpenStack, this is used to specify that tempest should
always use its master branch even though it has stable branches
(we no longer use stable branches for tempest).  It may also be
useful in some kinds of compatibility cross-testing.

The test for this is taken from 'test_multi_branch_project_override'
in devstack-gate.

Change-Id: I958af233d1def3b1c7362e1b2ddc77c108766358
This commit is contained in:
James E. Blair 2014-08-21 16:02:17 -07:00
parent bce35e1804
commit f04202243e
3 changed files with 112 additions and 5 deletions

View File

@ -339,3 +339,87 @@ class TestCloner(ZuulTestCase):
self.worker.hold_jobs_in_build = False self.worker.hold_jobs_in_build = False
self.worker.release() self.worker.release()
self.waitUntilSettled() self.waitUntilSettled()
def test_project_override(self):
self.worker.hold_jobs_in_build = True
projects = ['org/project1', 'org/project2', 'org/project3',
'org/project4', 'org/project5', 'org/project6']
self.create_branch('org/project3', 'stable/havana')
self.create_branch('org/project4', 'stable/havana')
self.create_branch('org/project6', 'stable/havana')
A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
D = self.fake_gerrit.addFakeChange('org/project3', 'stable/havana', 'D')
A.addApproval('CRVW', 2)
B.addApproval('CRVW', 2)
C.addApproval('CRVW', 2)
D.addApproval('CRVW', 2)
self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
self.waitUntilSettled()
self.assertEquals(4, len(self.builds), "Four builds are running")
upstream = self.getUpstreamRepos(projects)
states = [
{'org/project1': self.builds[0].parameters['ZUUL_COMMIT'],
'org/project2': str(upstream['org/project2'].commit('master')),
'org/project3': str(upstream['org/project3'].commit('master')),
'org/project4': str(upstream['org/project4'].commit('master')),
'org/project5': str(upstream['org/project5'].commit('master')),
'org/project6': str(upstream['org/project6'].commit('master')),
},
{'org/project1': self.builds[1].parameters['ZUUL_COMMIT'],
'org/project2': str(upstream['org/project2'].commit('master')),
'org/project3': str(upstream['org/project3'].commit('master')),
'org/project4': str(upstream['org/project4'].commit('master')),
'org/project5': str(upstream['org/project5'].commit('master')),
'org/project6': str(upstream['org/project6'].commit('master')),
},
{'org/project1': self.builds[1].parameters['ZUUL_COMMIT'],
'org/project2': self.builds[2].parameters['ZUUL_COMMIT'],
'org/project3': str(upstream['org/project3'].commit('master')),
'org/project4': str(upstream['org/project4'].commit('master')),
'org/project5': str(upstream['org/project5'].commit('master')),
'org/project6': str(upstream['org/project6'].commit('master')),
},
{'org/project1': self.builds[1].parameters['ZUUL_COMMIT'],
'org/project2': self.builds[2].parameters['ZUUL_COMMIT'],
'org/project3': self.builds[3].parameters['ZUUL_COMMIT'],
'org/project4': str(upstream['org/project4'].commit('master')),
'org/project5': str(upstream['org/project5'].commit('master')),
'org/project6': str(upstream['org/project6'].commit('stable/havana')),
},
]
for number, build in enumerate(self.builds):
self.log.debug("Build parameters: %s", build.parameters)
change_number = int(build.parameters['ZUUL_CHANGE'])
cloner = zuul.lib.cloner.Cloner(
git_base_url=self.upstream_root,
projects=projects,
workspace=self.workspace_root,
zuul_branch=build.parameters['ZUUL_BRANCH'],
zuul_ref=build.parameters['ZUUL_REF'],
zuul_url=self.git_root,
project_branches={'org/project4': 'master'},
)
cloner.execute()
work = self.getWorkspaceRepos(projects)
state = states[number]
for project in projects:
self.assertEquals(state[project],
str(work[project].commit('HEAD')),
'Project %s commit for build %s should '
'be correct' % (project, number))
shutil.rmtree(self.workspace_root)
self.worker.hold_jobs_in_build = False
self.worker.release()
self.waitUntilSettled()

View File

@ -61,17 +61,24 @@ class Cloner(zuul.cmd.ZuulApp):
project_env = parser.add_argument_group( project_env = parser.add_argument_group(
'project tuning' 'project tuning'
) )
project_env.add_argument( project_env.add_argument(
'--branch', '--branch',
help=('branch to checkout instead of Zuul selected branch, ' help=('branch to checkout instead of Zuul selected branch, '
'for example to specify an alternate branch to test ' 'for example to specify an alternate branch to test '
'client library compatibility.') 'client library compatibility.')
) )
project_env.add_argument(
'--project-branch', nargs=1, action='append',
metavar='PROJECT=BRANCH',
help=('project-specific branch to checkout which takes precedence '
'over --branch if it is provided; may be specified multiple '
'times.')
)
zuul_env = parser.add_argument_group( zuul_env = parser.add_argument_group(
'zuul environnement', 'zuul environnement',
'Let you override $ZUUL_* environnement variables.' 'Let you override $ZUUL_* environment variables.'
) )
for zuul_suffix in ZUUL_ENV_SUFFIXES: for zuul_suffix in ZUUL_ENV_SUFFIXES:
env_name = 'ZUUL_%s' % zuul_suffix.upper() env_name = 'ZUUL_%s' % zuul_suffix.upper()
@ -120,6 +127,11 @@ class Cloner(zuul.cmd.ZuulApp):
def main(self): def main(self):
self.parse_arguments() self.parse_arguments()
self.setup_logging(color=self.args.color, verbose=self.args.verbose) self.setup_logging(color=self.args.color, verbose=self.args.verbose)
project_branches = {}
if self.args.project_branch:
for x in self.args.project_branch:
project, branch = x[0].split('=')
project_branches[project] = branch
cloner = zuul.lib.cloner.Cloner( cloner = zuul.lib.cloner.Cloner(
git_base_url=self.args.git_base_url, git_base_url=self.args.git_base_url,
projects=self.args.projects, projects=self.args.projects,
@ -128,7 +140,8 @@ class Cloner(zuul.cmd.ZuulApp):
zuul_ref=self.args.zuul_ref, zuul_ref=self.args.zuul_ref,
zuul_url=self.args.zuul_url, zuul_url=self.args.zuul_url,
branch=self.args.branch, branch=self.args.branch,
clone_map_file=self.args.clone_map_file clone_map_file=self.args.clone_map_file,
project_branches=project_branches,
) )
cloner.execute() cloner.execute()

View File

@ -28,7 +28,8 @@ class Cloner(object):
log = logging.getLogger("zuul.Cloner") log = logging.getLogger("zuul.Cloner")
def __init__(self, git_base_url, projects, workspace, zuul_branch, def __init__(self, git_base_url, projects, workspace, zuul_branch,
zuul_ref, zuul_url, branch=None, clone_map_file=None): zuul_ref, zuul_url, branch=None, clone_map_file=None,
project_branches=None):
self.clone_map = [] self.clone_map = []
self.dests = None self.dests = None
@ -40,6 +41,7 @@ class Cloner(object):
self.zuul_branch = zuul_branch self.zuul_branch = zuul_branch
self.zuul_ref = zuul_ref self.zuul_ref = zuul_ref
self.zuul_url = zuul_url self.zuul_url = zuul_url
self.project_branches = project_branches or {}
if clone_map_file: if clone_map_file:
self.readCloneMap(clone_map_file) self.readCloneMap(clone_map_file)
@ -98,6 +100,12 @@ class Cloner(object):
2) Zuul reference for the master branch 2) Zuul reference for the master branch
3) The tip of the indicated branch 3) The tip of the indicated branch
4) The tip of the master branch 4) The tip of the master branch
The "indicated branch" is one of the following:
A) The project-specific override branch (from project_branches arg)
B) The user specified branch (from the branch arg)
C) ZUUL_BRANCH (from the zuul_branch arg)
""" """
repo = self.cloneUpstream(project, dest) repo = self.cloneUpstream(project, dest)
@ -107,6 +115,8 @@ class Cloner(object):
repo.prune() repo.prune()
indicated_branch = self.branch or self.zuul_branch indicated_branch = self.branch or self.zuul_branch
if project in self.project_branches:
indicated_branch = self.project_branches[project]
override_zuul_ref = re.sub(self.zuul_branch, indicated_branch, override_zuul_ref = re.sub(self.zuul_branch, indicated_branch,
self.zuul_ref) self.zuul_ref)