diff options
author | James E. Blair <jeblair@hp.com> | 2014-08-21 16:02:17 -0700 |
---|---|---|
committer | James E. Blair <jeblair@hp.com> | 2014-08-27 13:12:05 -0700 |
commit | f04202243e9cf079e60a3292775bf2ecaeeb478d (patch) | |
tree | c8ecbc743dcfabf96f6b3f81cc6465467be1404e | |
parent | bce35e18040460338b52783c415ea64094ae5849 (diff) | |
download | zuul-f04202243e9cf079e60a3292775bf2ecaeeb478d.tar.gz |
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
-rw-r--r-- | tests/test_cloner.py | 84 | ||||
-rwxr-xr-x | zuul/cmd/cloner.py | 21 | ||||
-rw-r--r-- | zuul/lib/cloner.py | 12 |
3 files changed, 112 insertions, 5 deletions
diff --git a/tests/test_cloner.py b/tests/test_cloner.py index 752f37c63..166c48666 100644 --- a/tests/test_cloner.py +++ b/tests/test_cloner.py @@ -339,3 +339,87 @@ class TestCloner(ZuulTestCase): self.worker.hold_jobs_in_build = False self.worker.release() 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() diff --git a/zuul/cmd/cloner.py b/zuul/cmd/cloner.py index 1310c1690..2fcaacd29 100755 --- a/zuul/cmd/cloner.py +++ b/zuul/cmd/cloner.py @@ -61,17 +61,24 @@ class Cloner(zuul.cmd.ZuulApp): project_env = parser.add_argument_group( 'project tuning' - ) + ) project_env.add_argument( '--branch', help=('branch to checkout instead of Zuul selected branch, ' 'for example to specify an alternate branch to test ' '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 environnement', - 'Let you override $ZUUL_* environnement variables.' + 'Let you override $ZUUL_* environment variables.' ) for zuul_suffix in ZUUL_ENV_SUFFIXES: env_name = 'ZUUL_%s' % zuul_suffix.upper() @@ -120,6 +127,11 @@ class Cloner(zuul.cmd.ZuulApp): def main(self): self.parse_arguments() 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( git_base_url=self.args.git_base_url, projects=self.args.projects, @@ -128,7 +140,8 @@ class Cloner(zuul.cmd.ZuulApp): zuul_ref=self.args.zuul_ref, zuul_url=self.args.zuul_url, 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() diff --git a/zuul/lib/cloner.py b/zuul/lib/cloner.py index a38281c64..579b9c7e1 100644 --- a/zuul/lib/cloner.py +++ b/zuul/lib/cloner.py @@ -28,7 +28,8 @@ class Cloner(object): log = logging.getLogger("zuul.Cloner") 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.dests = None @@ -40,6 +41,7 @@ class Cloner(object): self.zuul_branch = zuul_branch self.zuul_ref = zuul_ref self.zuul_url = zuul_url + self.project_branches = project_branches or {} if clone_map_file: self.readCloneMap(clone_map_file) @@ -98,6 +100,12 @@ class Cloner(object): 2) Zuul reference for the master branch 3) The tip of the indicated 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) @@ -107,6 +115,8 @@ class Cloner(object): repo.prune() 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, self.zuul_ref) |