Add support for override-checkout, deprecate override-branch

We want to support jobs specifying that they check out a tag
rather than merely a branch.  This accidentally worked in Zuul v2
with zuul-cloner, and some jobs have come to rely on the behavior.
There's no reason not to support it, so let's do so.

However, for clarity, change the name of the option to
"override-checkout".  This is intended to be intuitive (anything
you can tell git to 'checkout' you can put here), while avoiding
the suggestion that only branches or tags may be checked out.

The old form, "override-branch" is deprecated and will be removed.

Change-Id: Icc2907e72596626e96d2dc9f6ab1c3026f4085ab
This commit is contained in:
James E. Blair 2017-10-30 14:04:48 -07:00
parent c317fba760
commit edff2c26c2
12 changed files with 121 additions and 30 deletions

View File

@ -744,7 +744,7 @@ Here is an example of two job definitions:
If a job has an empty or no nodeset definition, it will still
run and may be able to perform actions on the Zuul executor.
.. attr:: override-branch
.. attr:: override-checkout
When Zuul runs jobs for a proposed change, it normally checks
out the branch associated with that change on every project
@ -752,13 +752,13 @@ Here is an example of two job definitions:
branch tip or tag), then that ref is normally checked out. This
attribute is used to override that behavior and indicate that
this job should, regardless of the branch for the queue item,
use the indicated branch instead. This can be used, for
example, to run a previous version of the software (from a
stable maintenance branch) under test even if the change being
tested applies to a different branch (this is only likely to be
useful if there is some cross-branch interaction with some
use the indicated ref (i.e., branch or tag) instead. This can
be used, for example, to run a previous version of the software
(from a stable maintenance branch) under test even if the change
being tested applies to a different branch (this is only likely
to be useful if there is some cross-branch interaction with some
component of the system being tested). See also the
project-specific :attr:`job.required-projects.override-branch`
project-specific :attr:`job.required-projects.override-checkout`
attribute to apply this behavior to a subset of a job's
projects.
@ -915,7 +915,7 @@ Here is an example of two job definitions:
The name of the required project.
.. attr:: override-branch
.. attr:: override-checkout
When Zuul runs jobs for a proposed change, it normally checks
out the branch associated with that change on every project
@ -923,9 +923,10 @@ Here is an example of two job definitions:
branch tip or tag), then that ref is normally checked out.
This attribute is used to override that behavior and indicate
that this job should, regardless of the branch for the queue
item, use the indicated branch instead, for only this
project. See also the :attr:`job.override-branch` attribute
to apply the same behavior to all projects in a job.
item, use the indicated ref (i.e., branch or tag) instead,
for only this project. See also the
:attr:`job.override-checkout` attribute to apply the same
behavior to all projects in a job.
.. attr:: vars

View File

@ -15,7 +15,7 @@
- job:
name: integration
branches: master
override-branch: stable/havana
override-checkout: stable/havana
required-projects:
- org/project1
run: playbooks/integration.yaml

View File

@ -14,7 +14,7 @@
- job:
name: integration
override-branch: stable/havana
override-checkout: stable/havana
required-projects:
- org/project1
run: playbooks/integration.yaml

View File

@ -44,7 +44,7 @@
- org/project2
- org/project3
- name: org/project4
override-branch: master
override-checkout: master
- org/project5
- org/project6
run: playbooks/integration.yaml

View File

@ -0,0 +1,36 @@
- pipeline:
name: check
manager: independent
trigger:
gerrit:
- event: patchset-created
success:
gerrit:
Verified: 1
failure:
gerrit:
Verified: -1
- job:
name: base
parent: null
- job:
name: integration
required-projects:
- org/project1
- name: org/project2
override-checkout: test-tag
run: playbooks/integration.yaml
- project:
name: org/project1
check:
jobs:
- integration
- project:
name: org/project2
check:
jobs:
- integration

View File

@ -13,7 +13,7 @@
- job:
name: integration
branches: master
override-branch: stable/havana
override-checkout: stable/havana
required-projects:
- org/project1
run: playbooks/integration.yaml

View File

@ -378,6 +378,32 @@ class TestExecutorRepos(ZuulTestCase):
self.assertBuildStates(states, projects)
@simple_layout('layouts/repo-checkout-tag.yaml')
def test_tag_checkout(self):
self.executor_server.hold_jobs_in_build = True
p1 = "review.example.com/org/project1"
p2 = "review.example.com/org/project2"
projects = [p1, p2]
upstream = self.getUpstreamRepos(projects)
self.create_branch('org/project2', 'stable/havana')
files = {'README': 'tagged readme'}
self.addCommitToRepo('org/project2', 'tagged commit',
files, branch='stable/havana', tag='test-tag')
A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
states = [
{p1: dict(present=[A], branch='master'),
p2: dict(commit=str(upstream[p2].commit('test-tag')),
absent=[A]),
},
]
self.assertBuildStates(states, projects)
class TestAnsibleJob(ZuulTestCase):
tenant_config_file = 'config/ansible/main.yaml'

View File

@ -417,7 +417,8 @@ class JobParser(object):
role = vs.Any(zuul_role, galaxy_role)
job_project = {vs.Required('name'): str,
'override-branch': str}
'override-branch': str,
'override-checkout': str}
secret = {vs.Required('name'): str,
vs.Required('secret'): str}
@ -452,6 +453,7 @@ class JobParser(object):
'dependencies': to_list(str),
'allowed-projects': to_list(str),
'override-branch': str,
'override-checkout': str,
'description': str,
'post-review': bool}
@ -474,6 +476,7 @@ class JobParser(object):
'failure-url',
'success-url',
'override-branch',
'override-checkout',
]
@staticmethod
@ -633,14 +636,18 @@ class JobParser(object):
if isinstance(project, dict):
project_name = project['name']
project_override_branch = project.get('override-branch')
project_override_checkout = project.get(
'override-checkout')
else:
project_name = project
project_override_branch = None
project_override_checkout = None
(trusted, project) = tenant.getProject(project_name)
if project is None:
raise Exception("Unknown project %s" % (project_name,))
job_project = model.JobProject(project_name,
project_override_branch)
project_override_branch,
project_override_checkout)
new_projects[project_name] = job_project
job.required_projects = new_projects

View File

@ -196,6 +196,7 @@ class ExecutorClient(object):
else:
params['branch'] = None
params['override_branch'] = job.override_branch
params['override_checkout'] = job.override_checkout
params['repo_state'] = item.current_build_set.repo_state
if job.name != 'noop':
@ -216,7 +217,8 @@ class ExecutorClient(object):
projects = set()
required_projects = set()
def make_project_dict(project, override_branch=None):
def make_project_dict(project, override_branch=None,
override_checkout=None):
project_config = item.layout.project_configs.get(
project.canonical_name, None)
if project_config:
@ -228,6 +230,7 @@ class ExecutorClient(object):
name=project.name,
canonical_name=project.canonical_name,
override_branch=override_branch,
override_checkout=override_checkout,
default_branch=project_default_branch)
if job.required_projects:
@ -239,7 +242,8 @@ class ExecutorClient(object):
(job_project.project_name,))
params['projects'].append(
make_project_dict(project,
job_project.override_branch))
job_project.override_branch,
job_project.override_checkout))
projects.add(project)
required_projects.add(project)
for change in dependent_changes:

View File

@ -681,7 +681,9 @@ class AnsibleJob(object):
ref,
args['branch'],
args['override_branch'],
args['override_checkout'],
project['override_branch'],
project['override_checkout'],
project['default_branch'])
# Delete the origin remote from each repo we set up since
@ -757,22 +759,32 @@ class AnsibleJob(object):
return True
def checkoutBranch(self, repo, project_name, ref, zuul_branch,
job_branch, project_override_branch,
job_override_branch, job_override_checkout,
project_override_branch, project_override_checkout,
project_default_branch):
branches = repo.getBranches()
refs = [r.name for r in repo.getRefs()]
if project_override_branch in branches:
self.log.info("Checking out %s project override branch %s",
project_name, project_override_branch)
repo.checkoutLocalBranch(project_override_branch)
elif job_branch in branches:
self.log.info("Checking out %s job branch %s",
project_name, job_branch)
repo.checkoutLocalBranch(job_branch)
repo.checkout(project_override_branch)
if project_override_checkout in refs:
self.log.info("Checking out %s project override ref %s",
project_name, project_override_checkout)
repo.checkout(project_override_checkout)
elif job_override_branch in branches:
self.log.info("Checking out %s job override branch %s",
project_name, job_override_branch)
repo.checkout(job_override_branch)
elif job_override_checkout in refs:
self.log.info("Checking out %s job override ref %s",
project_name, job_override_checkout)
repo.checkout(job_override_checkout)
elif ref and ref.startswith('refs/heads/'):
b = ref[len('refs/heads/'):]
self.log.info("Checking out %s branch ref %s",
project_name, b)
repo.checkoutLocalBranch(b)
repo.checkout(b)
elif ref and ref.startswith('refs/tags/'):
t = ref[len('refs/tags/'):]
self.log.info("Checking out %s tag ref %s",
@ -781,11 +793,11 @@ class AnsibleJob(object):
elif zuul_branch and zuul_branch in branches:
self.log.info("Checking out %s zuul branch %s",
project_name, zuul_branch)
repo.checkoutLocalBranch(zuul_branch)
repo.checkout(zuul_branch)
elif project_default_branch in branches:
self.log.info("Checking out %s project default branch %s",
project_name, project_default_branch)
repo.checkoutLocalBranch(project_default_branch)
repo.checkout(project_default_branch)
else:
raise ExecutorError("Project %s does not have the "
"default branch %s" %

View File

@ -176,6 +176,8 @@ class Repo(object):
return branch in origin.refs
def getBranches(self):
# TODO(jeblair): deprecate with override-branch; replaced by
# getRefs().
repo = self.createRepoObject()
return [x.name for x in repo.heads]
@ -386,7 +388,7 @@ class Merger(object):
self.log.info("Checking out %s/%s branch %s",
connection_name, project_name, branch)
repo = self.getRepo(connection_name, project_name)
repo.checkoutLocalBranch(branch)
repo.checkout(branch)
def _saveRepoState(self, connection_name, project_name, repo,
repo_state, recent):

View File

@ -845,6 +845,7 @@ class Job(object):
required_projects={},
allowed_projects=None,
override_branch=None,
override_checkout=None,
post_review=None,
)
@ -1073,9 +1074,11 @@ class Job(object):
class JobProject(object):
""" A reference to a project from a job. """
def __init__(self, project_name, override_branch=None):
def __init__(self, project_name, override_branch=None,
override_checkout=None):
self.project_name = project_name
self.override_branch = override_branch
self.override_checkout = override_checkout
class JobList(object):