Browse Source

Add support for project-templates

Change-Id: I0f86acd7fb5e049e5368249de52f9d81a99936d8
James E. Blair 1 year ago
parent
commit
4122b0b8f0

+ 12
- 0
doc/source/example-autodoc.rst View File

@@ -0,0 +1,12 @@
1
+Auto Doc
2
+========
3
+
4
+Auto Jobs
5
+---------
6
+
7
+.. autojobs::
8
+
9
+Auto Project Templates
10
+----------------------
11
+
12
+.. autoproject_templates::

+ 20
- 0
doc/source/example-templates.rst View File

@@ -0,0 +1,20 @@
1
+Example Project Templates
2
+=========================
3
+
4
+Project 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
+
20
+This is a project_template role: :project_template:`example`

+ 2
- 0
doc/source/index.rst View File

@@ -5,7 +5,9 @@
5 5
 
6 6
    examples
7 7
    example-jobs
8
+   example-templates
8 9
    example-roles
10
+   example-autodoc
9 11
 
10 12
 Indices and tables
11 13
 ==================

+ 24
- 0
doc/source/zuul.d/test.yaml View File

@@ -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

+ 98
- 1
zuul_sphinx/zuul.py View File

@@ -12,6 +12,9 @@
12 12
 # License for the specific language governing permissions and limitations
13 13
 # under the License.
14 14
 
15
+from collections import OrderedDict
16
+import os
17
+
15 18
 from sphinx import addnodes
16 19
 from docutils.parsers.rst import Directive
17 20
 from sphinx.domains import Domain, ObjType
@@ -19,14 +22,37 @@ from sphinx.roles import XRefRole
19 22
 from sphinx.directives import ObjectDescription
20 23
 from sphinx.util.nodes import make_refnode
21 24
 from docutils import nodes
22
-import os
23 25
 
24 26
 import yaml
25 27
 
26 28
 
29
+class 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
+
27 52
 class Layout(object):
28 53
     def __init__(self):
29 54
         self.jobs = []
55
+        self.project_templates = []
30 56
 
31 57
 
32 58
 class ZuulDirective(Directive):
@@ -51,6 +77,9 @@ class ZuulDirective(Directive):
51 77
         for obj in data:
52 78
             if 'job' in obj:
53 79
                 layout.jobs.append(obj['job'])
80
+            if 'project-template' in obj:
81
+                layout.project_templates.append(
82
+                    ProjectTemplate(obj['project-template']))
54 83
         return layout
55 84
 
56 85
     def parse_zuul_d(self, path):
@@ -61,6 +90,9 @@ class ZuulDirective(Directive):
61 90
             for obj in data:
62 91
                 if 'job' in obj:
63 92
                     layout.jobs.append(obj['job'])
93
+                if 'project-template' in obj:
94
+                    layout.project_templates.append(
95
+                        ProjectTemplate(obj['project-template']))
64 96
         return layout
65 97
 
66 98
     def _parse_zuul_layout(self):
@@ -103,6 +135,22 @@ class ZuulDirective(Directive):
103 135
                 lines.append('')
104 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 154
     def find_zuul_roles(self):
107 155
         root = os.path.dirname(self.zuul_layout_path)
108 156
         roledir = os.path.join(root, 'roles')
@@ -210,6 +258,22 @@ class ZuulJobDirective(ZuulObjectDescription):
210 258
         return sig
211 259
 
212 260
 
261
+class 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
+
213 277
 class ZuulRoleDirective(ZuulObjectDescription):
214 278
     def before_content(self):
215 279
         path = self.env.ref_context.setdefault('zuul:attr_path', [])
@@ -409,6 +473,29 @@ class ZuulAutoJobsDirective(ZuulDirective):
409 473
         self.state_machine.insert_input(lines, self.zuul_layout_path)
410 474
         return []
411 475
 
476
+class 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
+
484
+class 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
 
413 500
 class ZuulAutoRoleDirective(ZuulDirective):
414 501
     def run(self):
@@ -447,6 +534,7 @@ class ZuulDomain(Domain):
447 534
     directives = {
448 535
         # Object description directives
449 536
         'job': ZuulJobDirective,
537
+        'project_template': ZuulProjectTemplateDirective,
450 538
         'role': ZuulRoleDirective,
451 539
         'attr': ZuulAttrDirective,
452 540
         'value': ZuulValueDirective,
@@ -457,6 +545,8 @@ class ZuulDomain(Domain):
457 545
         # Autodoc directives
458 546
         'autojob': ZuulAutoJobDirective,
459 547
         'autojobs': ZuulAutoJobsDirective,
548
+        'autoproject_template': ZuulAutoProjectTemplateDirective,
549
+        'autoproject_templates': ZuulAutoProjectTemplatesDirective,
460 550
         'autorole': ZuulAutoRoleDirective,
461 551
         'autoroles': ZuulAutoRolesDirective,
462 552
     }
@@ -464,6 +554,11 @@ class ZuulDomain(Domain):
464 554
     roles = {
465 555
         'job': XRefRole(innernodeclass=nodes.inline,  # type: ignore
466 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 562
         'role': XRefRole(innernodeclass=nodes.inline,  # type: ignore
468 563
                          warn_dangling=True),
469 564
         'attr': XRefRole(innernodeclass=nodes.inline,  # type: ignore
@@ -491,6 +586,8 @@ class ZuulDomain(Domain):
491 586
     def resolve_xref(self, env, fromdocname, builder, type, target,
492 587
                      node, contnode):
493 588
         objects = self.data['objects']
589
+        if type == 'xjob':
590
+            type = 'job'
494 591
         name = type + '-' + target
495 592
         obj = objects.get(name)
496 593
         if obj:

Loading…
Cancel
Save