Merge "Support zuul.child_jobs via zuul_return"

This commit is contained in:
Zuul 2018-07-11 06:36:26 +00:00 committed by Gerrit Code Review
commit 2125035a21
12 changed files with 190 additions and 6 deletions

View File

@ -587,6 +587,25 @@ To set the log URL for a build, use *zuul_return* to set the
zuul:
log_url: http://logs.example.com/path/to/build/logs
To skip a child job for the current build, use *zuul_return* to set the
:var:`zuul.child_jobs` value. For example:
.. code-block:: yaml
tasks:
- zuul_return:
data:
zuul:
child_jobs:
- child_jobA
- child_jobC
Will tell zuul to only run the child_jobA and child_jobC for pre-configured
child jobs. If child_jobB was configured, it would be now marked as SKIPPED. If
zuul.child_jobs is empty, all jobs will be marked as SKIPPED. Invalid child jobs
are stripped and ignored, if only invalid jobs are listed it is the same as
providing an empty list to zuul.child_jobs.
Any values other than those in the ``zuul`` hierarchy will be supplied
as Ansible variables to child jobs. These variables have less
precedence than any other type of variable in Zuul, so be sure their

View File

@ -0,0 +1,8 @@
---
features:
- |
It is now possible to use zuul_return to skip child jobs. You can
use the :var:`zuul.child_jobs` inventory variable to get a list of
child jobs configured to run, then use zuul_return to modify the
list. Any child job not in zuul_return zuul.child_jobs will be
skipped. See :ref:`return_values` for examples.

View File

@ -0,0 +1,8 @@
- hosts: localhost
tasks:
- zuul_return:
data:
zuul:
child_jobs:
- data-return
log_url: http://example.com/test/log/url/

View File

@ -0,0 +1,8 @@
- hosts: localhost
tasks:
- zuul_return:
data:
zuul:
child_jobs:
- invalid-job
log_url: http://example.com/test/log/url/

View File

@ -0,0 +1,7 @@
- hosts: localhost
tasks:
- zuul_return:
data:
zuul:
child_jobs: []
log_url: http://example.com/test/log/url/

View File

@ -20,6 +20,18 @@
name: data-return
run: playbooks/data-return.yaml
- job:
name: data-return-child-jobs
run: playbooks/data-return-child-jobs.yaml
- job:
name: data-return-invalid-child-job
run: playbooks/data-return-invalid-child-job.yaml
- job:
name: data-return-skip-all
run: playbooks/data-return-skip-all.yaml
- job:
name: data-return-relative
success-url: docs/index.html
@ -39,3 +51,36 @@
dependencies:
- data-return
- data-return-relative
- project:
name: org/project1
check:
jobs:
- data-return-child-jobs
- data-return:
dependencies:
- data-return-child-jobs
- child:
dependencies:
- data-return-child-jobs
- project:
name: org/project2
check:
jobs:
- data-return-invalid-child-job
- data-return:
dependencies:
- data-return-invalid-child-job
- project:
name: org/project3
check:
jobs:
- data-return-skip-all
- data-return:
dependencies:
- data-return-skip-all
- child:
dependencies:
- data-return-skip-all

View File

@ -0,0 +1 @@
test

View File

@ -0,0 +1 @@
test

View File

@ -0,0 +1 @@
test

View File

@ -6,3 +6,6 @@
- common-config
untrusted-projects:
- org/project
- org/project1
- org/project2
- org/project3

View File

@ -2937,6 +2937,52 @@ class TestDataReturn(AnsibleZuulTestCase):
'http://example.com/test/log/url/docs/index.html',
A.messages[-1])
def test_data_return_child_jobs(self):
A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertHistory([
dict(name='data-return-child-jobs', result='SUCCESS',
changes='1,1'),
dict(name='data-return', result='SUCCESS', changes='1,1'),
])
self.assertIn(
'- data-return-child-jobs http://example.com/test/log/url/',
A.messages[-1])
self.assertIn(
'- data-return http://example.com/test/log/url/',
A.messages[-1])
self.assertIn('child : SKIPPED', A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
def test_data_return_invalid_child_job(self):
A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertHistory([
dict(name='data-return-invalid-child-job', result='SUCCESS',
changes='1,1')])
self.assertIn(
'- data-return-invalid-child-job http://example.com/test/log/url/',
A.messages[-1])
self.assertIn('data-return : SKIPPED', A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
def test_data_return_skip_all_child_jobs(self):
A = self.fake_gerrit.addFakeChange('org/project3', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertHistory([
dict(name='data-return-skip-all', result='SUCCESS',
changes='1,1'),
])
self.assertIn(
'- data-return-skip-all http://example.com/test/log/url/',
A.messages[-1])
self.assertIn('child : SKIPPED', A.messages[-1])
self.assertIn('data-return : SKIPPED', A.messages[-1])
self.assertIn('Build succeeded', A.messages[-1])
class TestDiskAccounting(AnsibleZuulTestCase):
config_file = 'zuul-disk-accounting.conf'

View File

@ -1808,14 +1808,24 @@ class QueueItem(object):
def didAllJobsSucceed(self):
if not self.hasJobGraph():
return False
skipped = True
for job in self.getJobs():
if not job.voting:
continue
build = self.current_build_set.getBuild(job.name)
if not build:
return False
if build.result != 'SUCCESS':
if build.result == 'SKIPPED':
continue
elif build.result != 'SUCCESS':
return False
skipped = False
# NOTE(pabelanger): We shouldn't be able to skip all jobs.
if skipped:
return False
return True
def didAnyJobFail(self):
@ -1977,12 +1987,39 @@ class QueueItem(object):
def setResult(self, build):
if build.retry:
self.removeBuild(build)
return
skipped = []
# NOTE(pabelanger): Check successful jobs to see if zuul_return
# includes zuul.child_jobs.
build_result = build.result_data.get('zuul', {})
if 'child_jobs' in build_result:
zuul_return = build_result.get('child_jobs', [])
dependent_jobs = self.job_graph.getDirectDependentJobs(
build.job.name)
if not zuul_return:
# If zuul.child_jobs exists and is empty, user want to skip all
# child jobs.
skipped += self.job_graph.getDependentJobsRecursively(
build.job.name)
else:
# We have list of jobs to run.
intersect_jobs = dependent_jobs.intersection(zuul_return)
for skip in (dependent_jobs - intersect_jobs):
skipped.append(self.job_graph.jobs.get(skip))
skipped += self.job_graph.getDependentJobsRecursively(
skip)
elif build.result != 'SUCCESS':
for job in self.job_graph.getDependentJobsRecursively(
build.job.name):
fakebuild = Build(job, None)
fakebuild.result = 'SKIPPED'
self.addBuild(fakebuild)
skipped += self.job_graph.getDependentJobsRecursively(
build.job.name)
for job in skipped:
fakebuild = Build(job, None)
fakebuild.result = 'SKIPPED'
self.addBuild(fakebuild)
def setNodeRequestFailure(self, job):
fakebuild = Build(job, None)