Merge "Add support for result data in child jobs" into feature/zuulv3
diff --git a/doc/source/user/jobs.rst b/doc/source/user/jobs.rst
index cf607b9..f65ee19 100644
--- a/doc/source/user/jobs.rst
+++ b/doc/source/user/jobs.rst
@@ -83,9 +83,12 @@
* Job variables
+* Parent job results
+
Meaning that a site-wide variable with the same name as any other will
override its value, and similarly, secrets override job variables of
-the same name. Each of the three sources is described below.
+the same name which override data returned from parent jobs. Each of
+the sources is described below.
Job Variables
@@ -482,6 +485,11 @@
<admin_sitewide_variables>` for information on how a site
administrator may define these variables.
+Parent Job Results
+~~~~~~~~~~~~~~~~~~
+
+A job may return data to Zuul for later use by jobs which depend on
+it. For details, see :ref:`return_values`.
SSH Keys
--------
@@ -503,9 +511,9 @@
Return Values
-------------
-The job may return some values to Zuul to affect its behavior. To
-return a value, use the *zuul_return* Ansible module in a job
-playbook. For example:
+A job may return some values to Zuul to affect its behavior and for
+use by other jobs.. To return a value, use the ``zuul_return``
+Ansible module in a job playbook. For example:
.. code-block:: yaml
@@ -514,12 +522,11 @@
data:
foo: bar
-Will return the dictionary "{'foo': 'bar'}" to Zuul.
+Will return the dictionary ``{'foo': 'bar'}`` to Zuul.
.. TODO: xref to section describing formatting
-Several uses of these values are planned, but the only currently
-implemented use is to set the log URL for a build. To do so, set the
+To set the log URL for a build, use *zuul_return* to set the
**zuul.log_url** value. For example:
.. code-block:: yaml
@@ -529,3 +536,10 @@
data:
zuul:
log_url: http://logs.example.com/path/to/build/logs
+
+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
+names are not shared by any job variables. If more than one parent
+job returns the same variable, the value from the later job in the job
+graph will take precedence.
diff --git a/tests/fixtures/config/data-return/git/common-config/playbooks/child.yaml b/tests/fixtures/config/data-return/git/common-config/playbooks/child.yaml
new file mode 100644
index 0000000..d147e13
--- /dev/null
+++ b/tests/fixtures/config/data-return/git/common-config/playbooks/child.yaml
@@ -0,0 +1,7 @@
+- hosts: localhost
+ tasks:
+ - name: Assert returned variables are valid
+ assert:
+ that:
+ - child.value1 == 'data-return-relative'
+ - child.value2 == 'data-return'
diff --git a/tests/fixtures/config/data-return/git/common-config/playbooks/data-return-relative.yaml b/tests/fixtures/config/data-return/git/common-config/playbooks/data-return-relative.yaml
new file mode 100644
index 0000000..e9193a8
--- /dev/null
+++ b/tests/fixtures/config/data-return/git/common-config/playbooks/data-return-relative.yaml
@@ -0,0 +1,8 @@
+- hosts: localhost
+ tasks:
+ - zuul_return:
+ data:
+ zuul:
+ log_url: http://example.com/test/log/url/
+ child:
+ value1: data-return-relative
diff --git a/tests/fixtures/config/data-return/git/common-config/playbooks/data-return.yaml b/tests/fixtures/config/data-return/git/common-config/playbooks/data-return.yaml
index 5e412c3..db54277 100644
--- a/tests/fixtures/config/data-return/git/common-config/playbooks/data-return.yaml
+++ b/tests/fixtures/config/data-return/git/common-config/playbooks/data-return.yaml
@@ -4,3 +4,6 @@
data:
zuul:
log_url: http://example.com/test/log/url/
+ child:
+ value1: data-return
+ value2: data-return
diff --git a/tests/fixtures/config/data-return/git/common-config/zuul.yaml b/tests/fixtures/config/data-return/git/common-config/zuul.yaml
index 906dc5b..2d5c51f 100644
--- a/tests/fixtures/config/data-return/git/common-config/zuul.yaml
+++ b/tests/fixtures/config/data-return/git/common-config/zuul.yaml
@@ -21,12 +21,18 @@
- job:
name: data-return-relative
- run: playbooks/data-return
success-url: docs/index.html
+- job:
+ name: child
+
- project:
name: org/project
check:
jobs:
- data-return
- data-return-relative
+ - child:
+ dependencies:
+ - data-return
+ - data-return-relative
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index 20f39bb..b4702f9 100755
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -1744,14 +1744,13 @@
tenant_config_file = 'config/data-return/main.yaml'
def test_data_return(self):
- # This exercises a proposed change to a role being checked out
- # and used.
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.waitUntilSettled()
self.assertHistory([
dict(name='data-return', result='SUCCESS', changes='1,1'),
dict(name='data-return-relative', result='SUCCESS', changes='1,1'),
+ dict(name='child', result='SUCCESS', changes='1,1'),
], ordered=False)
self.assertIn('- data-return http://example.com/test/log/url/',
A.messages[-1])
diff --git a/zuul/model.py b/zuul/model.py
index d2595c3..e4b6eb5 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -836,6 +836,7 @@
source_context=None,
source_line=None,
inheritance_path=(),
+ parent_data=None,
)
self.inheritable_attributes = {}
@@ -932,6 +933,21 @@
Job._deepUpdate(v, other_vars)
self.variables = v
+ def updateParentData(self, other_vars):
+ # Update variables, but give the current values priority (used
+ # for job return data which is lower precedence than defined
+ # job vars).
+ v = self.parent_data or {}
+ Job._deepUpdate(v, other_vars)
+ # To avoid running afoul of checks that jobs don't set zuul
+ # variables, remove them from parent data here.
+ if 'zuul' in v:
+ del v['zuul']
+ self.parent_data = v
+ v = copy.deepcopy(self.parent_data)
+ Job._deepUpdate(v, self.variables)
+ self.variables = v
+
def updateProjects(self, other_projects):
required_projects = self.required_projects.copy()
required_projects.update(other_projects)
@@ -1571,8 +1587,8 @@
else:
jobs_not_started.add(job)
- # Attempt to request nodes for jobs in the order jobs appear
- # in configuration.
+ # Attempt to run jobs in the order they appear in
+ # configuration.
for job in self.job_graph.getJobs():
if job not in jobs_not_started:
continue
@@ -1582,6 +1598,9 @@
if parent_job.name not in successful_job_names:
all_parent_jobs_successful = False
break
+ parent_build = self.current_build_set.getBuild(parent_job.name)
+ if parent_build.result_data:
+ job.updateParentData(parent_build.result_data)
if all_parent_jobs_successful:
nodeset = self.current_build_set.getJobNodeSet(job.name)
if nodeset is None: