summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames E. Blair <jeblair@redhat.com>2017-10-16 16:45:54 -0700
committerJames E. Blair <jeblair@redhat.com>2017-10-16 16:45:54 -0700
commit4122b0b8f0c5ba00020d2d4ae2b48825c2bf5240 (patch)
tree77c156fb1881110965756454732e97c461174450
parent15afdbadc8b9110340c94c560459ce53fae404c9 (diff)
Add support for project-templates0.2.0
Notes
Notes (review): Code-Review+2: Monty Taylor <mordred@inaugust.com> Code-Review+2: Tobias Henkel <tobias.henkel@bmw.de> Code-Review+1: Andreas Jaeger <jaegerandi@gmail.com> Code-Review+2: James E. Blair <corvus@inaugust.com> Workflow+1: James E. Blair <corvus@inaugust.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Tue, 17 Oct 2017 14:36:06 +0000 Reviewed-on: https://review.openstack.org/512449 Project: openstack-infra/zuul-sphinx Branch: refs/heads/master
-rw-r--r--doc/source/example-autodoc.rst12
-rw-r--r--doc/source/example-templates.rst20
-rw-r--r--doc/source/index.rst2
-rw-r--r--doc/source/zuul.d/test.yaml24
-rw-r--r--zuul_sphinx/zuul.py99
5 files changed, 156 insertions, 1 deletions
diff --git a/doc/source/example-autodoc.rst b/doc/source/example-autodoc.rst
new file mode 100644
index 0000000..770dbe5
--- /dev/null
+++ b/doc/source/example-autodoc.rst
@@ -0,0 +1,12 @@
1Auto Doc
2========
3
4Auto Jobs
5---------
6
7.. autojobs::
8
9Auto Project Templates
10----------------------
11
12.. autoproject_templates::
diff --git a/doc/source/example-templates.rst b/doc/source/example-templates.rst
new file mode 100644
index 0000000..62bc452
--- /dev/null
+++ b/doc/source/example-templates.rst
@@ -0,0 +1,20 @@
1Example Project Templates
2=========================
3
4Project Templates
5-----------------
6
7.. project_template:: example
8
9 This is an example project template. It contains the following jobs:
10
11 **check**
12
13 * :job:`example`
14 * :job:`example`
15
16 **gate**
17
18 * :job:`example`
19
20This is a project_template role: :project_template:`example`
diff --git a/doc/source/index.rst b/doc/source/index.rst
index a08c6d1..2c950d9 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -5,7 +5,9 @@
5 5
6 examples 6 examples
7 example-jobs 7 example-jobs
8 example-templates
8 example-roles 9 example-roles
10 example-autodoc
9 11
10Indices and tables 12Indices and tables
11================== 13==================
diff --git a/doc/source/zuul.d/test.yaml b/doc/source/zuul.d/test.yaml
new file mode 100644
index 0000000..cf476ce
--- /dev/null
+++ b/doc/source/zuul.d/test.yaml
@@ -0,0 +1,24 @@
1- job:
2 name: test-autodoc
3 description: |
4 This is a test job.
5
6- job:
7 name: test-autodoc
8 branches: stable
9 description: |
10 This is a test job variant on a stable branch.
11
12- project-template:
13 name: test-autotemplate
14 description: |
15 This is a test project template.
16 check:
17 jobs:
18 - test-autodoc
19 - example
20 - does-not-exist-in-this-repo
21 gate:
22 jobs:
23 - example
24 - does-not-exist-in-this-repo
diff --git a/zuul_sphinx/zuul.py b/zuul_sphinx/zuul.py
index f7896a5..d0c4dec 100644
--- a/zuul_sphinx/zuul.py
+++ b/zuul_sphinx/zuul.py
@@ -12,6 +12,9 @@
12# License for the specific language governing permissions and limitations 12# License for the specific language governing permissions and limitations
13# under the License. 13# under the License.
14 14
15from collections import OrderedDict
16import os
17
15from sphinx import addnodes 18from sphinx import addnodes
16from docutils.parsers.rst import Directive 19from docutils.parsers.rst import Directive
17from sphinx.domains import Domain, ObjType 20from sphinx.domains import Domain, ObjType
@@ -19,14 +22,37 @@ from sphinx.roles import XRefRole
19from sphinx.directives import ObjectDescription 22from sphinx.directives import ObjectDescription
20from sphinx.util.nodes import make_refnode 23from sphinx.util.nodes import make_refnode
21from docutils import nodes 24from docutils import nodes
22import os
23 25
24import yaml 26import yaml
25 27
26 28
29class ProjectTemplate(object):
30 def __init__(self, conf):
31 self.name = conf['name']
32 self.description = conf.get('description', '')
33 self.pipelines = OrderedDict()
34 self.parse(conf)
35
36 def parse(self, conf):
37 for k in sorted(conf.keys()):
38 v = conf[k]
39 if not isinstance(v, dict):
40 continue
41 if 'jobs' not in v:
42 continue
43 jobs = []
44 for job in v['jobs']:
45 if isinstance(job, dict):
46 job = list(dict.keys())[0]
47 jobs.append(job)
48 if jobs:
49 self.pipelines[k] = jobs
50
51
27class Layout(object): 52class Layout(object):
28 def __init__(self): 53 def __init__(self):
29 self.jobs = [] 54 self.jobs = []
55 self.project_templates = []
30 56
31 57
32class ZuulDirective(Directive): 58class ZuulDirective(Directive):
@@ -51,6 +77,9 @@ class ZuulDirective(Directive):
51 for obj in data: 77 for obj in data:
52 if 'job' in obj: 78 if 'job' in obj:
53 layout.jobs.append(obj['job']) 79 layout.jobs.append(obj['job'])
80 if 'project-template' in obj:
81 layout.project_templates.append(
82 ProjectTemplate(obj['project-template']))
54 return layout 83 return layout
55 84
56 def parse_zuul_d(self, path): 85 def parse_zuul_d(self, path):
@@ -61,6 +90,9 @@ class ZuulDirective(Directive):
61 for obj in data: 90 for obj in data:
62 if 'job' in obj: 91 if 'job' in obj:
63 layout.jobs.append(obj['job']) 92 layout.jobs.append(obj['job'])
93 if 'project-template' in obj:
94 layout.project_templates.append(
95 ProjectTemplate(obj['project-template']))
64 return layout 96 return layout
65 97
66 def _parse_zuul_layout(self): 98 def _parse_zuul_layout(self):
@@ -103,6 +135,22 @@ class ZuulDirective(Directive):
103 lines.append('') 135 lines.append('')
104 return lines 136 return lines
105 137
138 def generate_zuul_project_template_content(self, name):
139 lines = []
140 for template in self.zuul_layout.project_templates:
141 if template.name == name:
142 lines.append('.. zuul:project_template:: %s' % name)
143 lines.append('')
144 for l in template.description.split('\n'):
145 lines.append(' ' + l)
146 for pipeline, jobs in template.pipelines.items():
147 lines.append('')
148 lines.append(' **'+pipeline+'**')
149 for job in jobs:
150 lines.append(' * :zuul:xjob:`' + job + '`')
151 lines.append('')
152 return lines
153
106 def find_zuul_roles(self): 154 def find_zuul_roles(self):
107 root = os.path.dirname(self.zuul_layout_path) 155 root = os.path.dirname(self.zuul_layout_path)
108 roledir = os.path.join(root, 'roles') 156 roledir = os.path.join(root, 'roles')
@@ -210,6 +258,22 @@ class ZuulJobDirective(ZuulObjectDescription):
210 return sig 258 return sig
211 259
212 260
261class ZuulProjectTemplateDirective(ZuulObjectDescription):
262 def before_content(self):
263 path = self.env.ref_context.setdefault('zuul:attr_path', [])
264 element = self.names[-1]
265 path.append(element)
266
267 def after_content(self):
268 path = self.env.ref_context.get('zuul:attr_path')
269 if path:
270 path.pop()
271
272 def handle_signature(self, sig, signode):
273 signode += addnodes.desc_name(sig, sig)
274 return sig
275
276
213class ZuulRoleDirective(ZuulObjectDescription): 277class ZuulRoleDirective(ZuulObjectDescription):
214 def before_content(self): 278 def before_content(self):
215 path = self.env.ref_context.setdefault('zuul:attr_path', []) 279 path = self.env.ref_context.setdefault('zuul:attr_path', [])
@@ -409,6 +473,29 @@ class ZuulAutoJobsDirective(ZuulDirective):
409 self.state_machine.insert_input(lines, self.zuul_layout_path) 473 self.state_machine.insert_input(lines, self.zuul_layout_path)
410 return [] 474 return []
411 475
476class ZuulAutoProjectTemplateDirective(ZuulDirective):
477 def run(self):
478 name = self.content[0]
479 lines = self.generate_zuul_project_template_content(name)
480 self.state_machine.insert_input(lines, self.zuul_layout_path)
481 return []
482
483
484class ZuulAutoProjectTemplatesDirective(ZuulDirective):
485 has_content = False
486
487 def run(self):
488 lines = []
489 names = set()
490 for template in self.zuul_layout.project_templates:
491 name = template.name
492 if name in names:
493 continue
494 lines.extend(self.generate_zuul_project_template_content(name))
495 names.add(name)
496 self.state_machine.insert_input(lines, self.zuul_layout_path)
497 return []
498
412 499
413class ZuulAutoRoleDirective(ZuulDirective): 500class ZuulAutoRoleDirective(ZuulDirective):
414 def run(self): 501 def run(self):
@@ -447,6 +534,7 @@ class ZuulDomain(Domain):
447 directives = { 534 directives = {
448 # Object description directives 535 # Object description directives
449 'job': ZuulJobDirective, 536 'job': ZuulJobDirective,
537 'project_template': ZuulProjectTemplateDirective,
450 'role': ZuulRoleDirective, 538 'role': ZuulRoleDirective,
451 'attr': ZuulAttrDirective, 539 'attr': ZuulAttrDirective,
452 'value': ZuulValueDirective, 540 'value': ZuulValueDirective,
@@ -457,6 +545,8 @@ class ZuulDomain(Domain):
457 # Autodoc directives 545 # Autodoc directives
458 'autojob': ZuulAutoJobDirective, 546 'autojob': ZuulAutoJobDirective,
459 'autojobs': ZuulAutoJobsDirective, 547 'autojobs': ZuulAutoJobsDirective,
548 'autoproject_template': ZuulAutoProjectTemplateDirective,
549 'autoproject_templates': ZuulAutoProjectTemplatesDirective,
460 'autorole': ZuulAutoRoleDirective, 550 'autorole': ZuulAutoRoleDirective,
461 'autoroles': ZuulAutoRolesDirective, 551 'autoroles': ZuulAutoRolesDirective,
462 } 552 }
@@ -464,6 +554,11 @@ class ZuulDomain(Domain):
464 roles = { 554 roles = {
465 'job': XRefRole(innernodeclass=nodes.inline, # type: ignore 555 'job': XRefRole(innernodeclass=nodes.inline, # type: ignore
466 warn_dangling=True), 556 warn_dangling=True),
557 'xjob': XRefRole(innernodeclass=nodes.inline, # type: ignore
558 warn_dangling=False),
559 'project_template':
560 XRefRole(innernodeclass=nodes.inline, # type: ignore
561 warn_dangling=True),
467 'role': XRefRole(innernodeclass=nodes.inline, # type: ignore 562 'role': XRefRole(innernodeclass=nodes.inline, # type: ignore
468 warn_dangling=True), 563 warn_dangling=True),
469 'attr': XRefRole(innernodeclass=nodes.inline, # type: ignore 564 'attr': XRefRole(innernodeclass=nodes.inline, # type: ignore
@@ -491,6 +586,8 @@ class ZuulDomain(Domain):
491 def resolve_xref(self, env, fromdocname, builder, type, target, 586 def resolve_xref(self, env, fromdocname, builder, type, target,
492 node, contnode): 587 node, contnode):
493 objects = self.data['objects'] 588 objects = self.data['objects']
589 if type == 'xjob':
590 type = 'job'
494 name = type + '-' + target 591 name = type + '-' + target
495 obj = objects.get(name) 592 obj = objects.get(name)
496 if obj: 593 if obj: