project templating system

On setup where Zuul ends up triggering hundreds of projects, you end up
having projects using roughly the same pipeline/jobs.  Whenever one want
to add a job in all the similiar project, he has to edit each project
one by one.

To save some precious time, this patch introduces the concept of project
templates.  It lets you define a set of pipeline and attached jobs
though the job names can be passed parameters defined on a per project
basis.  Thus, updating similiar projects is all about editing a single
template.

A basic example is provided in the documentation.

The voluptuous schema has been updated. It does check whether all
parameters are properly passed to a template but does NOT check whether
the resulting job name exist.

The parameter expansion in templates is borrowed from Jenkins Job
Builder (deep_format function). It has been tweaked to also expand
dictionary keys.

Layout test plan:

  $ nosetests -m layout  --nocapture
  Test layout file validation ...
  <...>
  bad_template1.yaml
     required key not provided @
  data['projects'][0]['template']['project']
  bad_template2.yaml
     extra keys not allowed @
  data['projects'][0]['template']['extraparam']
  good_template1.yaml
  ok
  <...>
  $

A basic test hasbeen added to verify whether a project-template properly
triggers its tests:

  $ nosetests --nocapture \
  tests/test_scheduler.py:testScheduler.test_job_from_templates_launched
  Test whether a job generated via a template can be launched ... ok

  ----------------------------------------------------------------------
  Ran 1 test in 0.863s

  OK
 $

Change-Id: Ib82e4719331c204de87fbb4b20c198842b7e32f4
Reviewed-on: https://review.openstack.org/21881
Reviewed-by: Jeremy Stanley <fungi@yuggoth.org>
Reviewed-by: James E. Blair <corvus@inaugust.com>
Approved: James E. Blair <corvus@inaugust.com>
Tested-by: Jenkins
diff --git a/doc/source/zuul.rst b/doc/source/zuul.rst
index d79600f..96faf86 100644
--- a/doc/source/zuul.rst
+++ b/doc/source/zuul.rst
@@ -504,6 +504,40 @@
 
 .. seealso:: The OpenStack Zuul configuration for a comprehensive example: https://github.com/openstack-infra/config/blob/master/modules/openstack_project/files/zuul/layout.yaml
 
+Project Templates
+"""""""""""""""""
+
+Whenever you have lot of similiar projects (such as plugins for a project) you
+will most probably want to use the same pipeline configurations.  The
+project templates let you define pipelines and job name templates to trigger.
+One can then just apply the template on its project which make it easier to
+update several similiar projects. As an example::
+
+  project-templates:
+    # Name of the template
+    - name: plugin-triggering
+      # Definition of pipelines just like for a `project`
+      check:
+       - '{jobprefix}-merge':
+         - '{jobprefix}-pep8'
+         - '{jobprefix}-pyflakes'
+      gate:
+       - '{jobprefix}-merge':
+         - '{jobprefix}-unittest'
+         - '{jobprefix}-pep8'
+         - '{jobprefix}-pyflakes'
+
+In your projects definition, you will then apply the template using the template
+key::
+
+  projects:
+   - name: plugin/foobar
+     template:
+      - name: plugin-triggering
+        jobprefix: plugin-foobar
+
+You can pass several parameters to a template. A ``parameter`` value will be
+used for expansion of ``{parameter}`` in the template strings.
 
 logging.conf
 ~~~~~~~~~~~~